XBRL API Reference
The XBRL module provides comprehensive parsing and processing of XBRL (eXtensible Business Reporting Language) data from SEC filings. It includes support for statement standardization, multi-period analysis, and advanced querying capabilities.
Module Overview
The XBRL module is organized into several key components:
- Core Classes:
XBRL,XBRLSfor parsing and managing XBRL documents - Statement Processing:
Statements,Statementfor working with financial statements - Facts Querying:
FactsView,FactQueryfor querying XBRL facts - Multi-Period Analysis:
StitchedStatements,StitchedStatementfor comparative analysis - Standardization:
StandardConceptfor normalizing company-specific concepts - Rendering:
RenderedStatementfor formatted output
Core Classes
XBRL
The main class for parsing and working with XBRL documents from SEC filings.
from edgar.xbrl import XBRL
class XBRL:
"""Main XBRL parser integrating all components of the XBRL parsing system."""
Factory Methods
from_filing()
@classmethod
def from_filing(cls, filing: Filing) -> XBRL
Create an XBRL instance from a Filing object.
Parameters:
- filing: SEC filing object containing XBRL data
Returns: XBRL instance
Example:
from edgar import Company
from edgar.xbrl import XBRL
company = Company("AAPL")
filing = company.latest("10-K")
xbrl = XBRL.from_filing(filing)
from_directory()
@classmethod
def from_directory(cls, directory: str) -> XBRL
Create an XBRL instance from a directory containing XBRL files.
Parameters:
- directory: Path to directory containing XBRL files
Returns: XBRL instance
from_files()
@classmethod
def from_files(cls, files: List[str]) -> XBRL
Create an XBRL instance from a list of XBRL files.
Parameters:
- files: List of file paths to XBRL documents
Returns: XBRL instance
Core Properties
statements
@property
def statements(self) -> Statements
Access to all financial statements in the XBRL document.
Returns: Statements object for accessing individual statements
Example:
# Access different statement types
balance_sheet = xbrl.statements.balance_sheet()
income_statement = xbrl.statements.income_statement()
cash_flow = xbrl.statements.cash_flow_statement()
facts
@property
def facts(self) -> FactsView
Access to all XBRL facts with querying capabilities.
Returns: FactsView object for querying facts
Example:
# Query facts by concept
revenue_facts = xbrl.facts.by_concept("Revenue")
# Convert to DataFrame for analysis
facts_df = xbrl.facts.to_dataframe()
Statement Methods
get_statement()
def get_statement(self, statement_type: str) -> Optional[Statement]
Get a specific financial statement by type.
Parameters:
- statement_type: Statement type ("BalanceSheet", "IncomeStatement", "CashFlowStatement", etc.)
Returns: Statement object or None if not found
render_statement()
def render_statement(self, statement_type: str, **kwargs) -> RenderedStatement
Render a financial statement with rich formatting.
Parameters:
- statement_type: Statement type to render
- **kwargs: Additional rendering options
Returns: RenderedStatement object
Example:
# Render balance sheet
rendered = xbrl.render_statement("BalanceSheet")
print(rendered)
# Render with custom options
rendered = xbrl.render_statement("IncomeStatement",
show_percentages=True,
max_rows=50)
Data Conversion
to_pandas()
def to_pandas(self) -> pd.DataFrame
Convert XBRL facts to a pandas DataFrame.
Returns: DataFrame with all facts and their attributes
Example:
# Convert to DataFrame for analysis
df = xbrl.to_pandas()
print(df.columns) # ['concept', 'value', 'period', 'label', ...]
# Filter for specific concepts
revenue_df = df[df['concept'].str.contains('Revenue', case=False)]
XBRLS
Container class for managing multiple XBRL documents for multi-period analysis.
from edgar.xbrl import XBRLS
class XBRLS:
"""Container for multiple XBRL objects enabling multi-period analysis."""
Factory Methods
from_filings()
@classmethod
def from_filings(cls, filings: List[Filing]) -> XBRLS
Create an XBRLS instance from multiple filings.
Parameters:
- filings: List of Filing objects
Returns: XBRLS instance
Example:
from edgar import Company
from edgar.xbrl import XBRLS
company = Company("AAPL")
filings = company.get_filings(form="10-K").head(3) # Get 3 years
xbrls = XBRLS.from_filings(filings)
Properties
statements
@property
def statements(self) -> StitchedStatements
Access to stitched statements showing multi-period data.
Returns: StitchedStatements object
Example:
# Get multi-period statements
income_stmt = xbrls.statements.income_statement()
balance_sheet = xbrls.statements.balance_sheet()
# Render multi-period view
print(income_stmt.render())
Statement Classes
Statements
High-level interface for accessing financial statements from a single XBRL document.
class Statements:
"""High-level interface to all statements in an XBRL document."""
Statement Access Methods
balance_sheet()
def balance_sheet(self) -> Optional[Statement]
Get the balance sheet statement.
Returns: Statement object or None
income_statement()
def income_statement(self) -> Optional[Statement]
Get the income statement.
Returns: Statement object or None
cash_flow_statement()
def cash_flow_statement(self) -> Optional[Statement]
Get the cash flow statement.
Returns: Statement object or None
statement_of_equity()
def statement_of_equity(self) -> Optional[Statement]
Get the statement of equity.
Returns: Statement object or None
comprehensive_income()
def comprehensive_income(self) -> Optional[Statement]
Get the comprehensive income statement.
Returns: Statement object or None
Example:
statements = xbrl.statements
# Access different statement types
if statements.balance_sheet():
bs = statements.balance_sheet()
print(f"Total Assets: {bs.get_concept_value('Assets')}")
if statements.income_statement():
is_stmt = statements.income_statement()
print(f"Revenue: {is_stmt.get_concept_value('Revenue')}")
Statement
Individual financial statement with analysis and rendering capabilities.
class Statement:
"""A single financial statement extracted from XBRL data."""
Core Methods
render()
def render(self, **kwargs) -> RenderedStatement
Render the statement with rich formatting.
Parameters:
- **kwargs: Rendering options (show_percentages, max_rows, etc.)
Returns: RenderedStatement object
to_dataframe()
def to_dataframe(
self,
include_dimensions: bool = True,
include_unit: bool = False,
include_point_in_time: bool = False,
presentation: bool = False
) -> pd.DataFrame
Convert statement to pandas DataFrame with optional transformations.
Parameters:
- include_dimensions: Include dimensional breakdowns (default: True)
- include_unit: Include unit column (USD, shares, etc.) (default: False)
- include_point_in_time: Include point-in-time column for instant facts (default: False)
- presentation: Apply HTML-matching transformations using preferred_sign (default: False)
- False (default): Raw instance values from XML
- True: Transform values to match SEC filing HTML display
Returns: DataFrame with the following columns:
- Core columns: concept, label, period columns (dates)
- Metadata columns (always included): balance, weight, preferred_sign
- Optional columns: dimension, unit, point_in_time
Value Modes:
- Raw mode (default): Preserves values exactly as reported in instance document
- Presentation mode (presentation=True): Applies transformations to match SEC HTML rendering
- Cash Flow: outflows with preferred_sign=-1 shown as negative
- Income Statement: applies preferred_sign transformations
Example:
statement = xbrl.statements.income_statement()
# Raw values (default)
df_raw = statement.to_dataframe()
# Returns actual XML values + metadata columns
# Presentation mode (matches SEC HTML)
df_presentation = statement.to_dataframe(presentation=True)
# Returns transformed values matching 10-K HTML display
# Check metadata
print(df_raw[['concept', 'balance', 'weight', 'preferred_sign']].head())
See Also: Issue #463 - XBRL value transformations and metadata columns
Returns: DataFrame with statement data
get_concept_value()
def get_concept_value(self, concept: str) -> Optional[Any]
Get the value for a specific concept.
Parameters:
- concept: Concept name to look up
Returns: Concept value or None
Example:
statement = xbrl.statements.income_statement()
# Render the statement
rendered = statement.render()
print(rendered)
# Convert to DataFrame
df = statement.to_dataframe()
# Get specific values
revenue = statement.get_concept_value("Revenue")
net_income = statement.get_concept_value("NetIncomeLoss")
Facts Querying
FactsView
Provides a view over all XBRL facts with analysis and querying methods.
class FactsView:
"""View over all facts with analysis methods."""
Query Methods
by_concept()
def by_concept(self, pattern: str, exact: bool = False) -> FactQuery
Filter facts by concept name.
Parameters:
- pattern: Pattern to match against concept names
- exact: If True, require exact match; otherwise, use regex
Returns: FactQuery object for further filtering
by_label()
def by_label(self, pattern: str, exact: bool = False) -> FactQuery
Filter facts by element label.
Parameters:
- pattern: Pattern to match against labels
- exact: If True, require exact match; otherwise, use regex
Returns: FactQuery object for further filtering
by_value()
def by_value(self, min_value: float = None, max_value: float = None) -> FactQuery
Filter facts by value range.
Parameters:
- min_value: Minimum value threshold
- max_value: Maximum value threshold
Returns: FactQuery object for further filtering
by_period()
def by_period(self, start_date: str = None, end_date: str = None) -> FactQuery
Filter facts by period range.
Parameters:
- start_date: Start date (YYYY-MM-DD format)
- end_date: End date (YYYY-MM-DD format)
Returns: FactQuery object for further filtering
Analysis Methods
pivot_by_period()
def pivot_by_period(self, concepts: List[str] = None) -> pd.DataFrame
Create a pivot table showing concepts by period.
Parameters:
- concepts: List of concepts to include (default: all)
Returns: DataFrame with concepts as rows and periods as columns
time_series()
def time_series(self, concept: str) -> pd.Series
Get time series data for a specific concept.
Parameters:
- concept: Concept name
Returns: pandas Series with time series data
Data Conversion
to_dataframe()
def to_dataframe(self) -> pd.DataFrame
Convert facts to pandas DataFrame.
Returns: DataFrame with all facts and metadata
Example:
facts = xbrl.facts
# Query by concept
revenue_query = facts.by_concept("Revenue")
revenue_facts = revenue_query.execute()
# Query by label and value
large_expenses = facts.by_label("expense").by_value(min_value=1000000)
expense_facts = large_expenses.to_dataframe()
# Time series analysis
revenue_ts = facts.time_series("Revenue")
print(revenue_ts.head())
# Pivot analysis
pivot_df = facts.pivot_by_period(["Revenue", "NetIncomeLoss"])
FactQuery
Fluent query builder for filtering and manipulating XBRL facts.
class FactQuery:
"""A query builder for XBRL facts with fluent interface."""
Filtering Methods
All filtering methods return self for method chaining.
by_concept()
def by_concept(self, pattern: str, exact: bool = False) -> FactQuery
by_label()
def by_label(self, pattern: str, exact: bool = False) -> FactQuery
by_value()
def by_value(self, min_value: float = None, max_value: float = None) -> FactQuery
by_period()
def by_period(self, start_date: str = None, end_date: str = None) -> FactQuery
by_statement()
def by_statement(self, statement_type: str) -> FactQuery
Filter facts by statement type.
Parameters:
- statement_type: Statement type to filter by
Returns: FactQuery object for method chaining
Execution Methods
execute()
def execute(self) -> List[Dict]
Execute the query and return matching facts.
Returns: List of fact dictionaries
to_dataframe()
def to_dataframe(self) -> pd.DataFrame
Execute the query and return results as DataFrame.
Returns: DataFrame with query results
first()
def first(self) -> Optional[Dict]
Get the first matching fact.
Returns: First fact dictionary or None
count()
def count(self) -> int
Count matching facts without retrieving them.
Returns: Number of matching facts
Example:
# Chain multiple filters
query = (xbrl.facts
.by_concept("Revenue")
.by_period(start_date="2023-01-01")
.by_value(min_value=1000000))
# Execute in different ways
facts_list = query.execute()
facts_df = query.to_dataframe()
first_fact = query.first()
count = query.count()
Multi-Period Analysis
StitchedStatements
Interface for accessing multi-period statements that combine data across multiple XBRL documents.
class StitchedStatements:
"""Interface for multi-period statements."""
Statement Access Methods
Similar to Statements but returns StitchedStatement objects:
balance_sheet()
def balance_sheet(self) -> Optional[StitchedStatement]
income_statement()
def income_statement(self) -> Optional[StitchedStatement]
cash_flow_statement()
def cash_flow_statement(self) -> Optional[StitchedStatement]
Example:
# Multi-period analysis
stitched_statements = xbrls.statements
income_stmt = stitched_statements.income_statement()
# Shows multiple years of data
print(income_stmt.render())
StitchedStatement
Individual statement showing multi-period data with comparative analysis.
class StitchedStatement:
"""Individual stitched statement showing multi-period data."""
Analysis Methods
render()
def render(self, **kwargs) -> RenderedStatement
Render multi-period statement with rich formatting.
to_dataframe()
def to_dataframe(self) -> pd.DataFrame
Convert to DataFrame with periods as columns.
Standardization
StandardConcept
Represents a standardized concept that normalizes company-specific terminology.
class StandardConcept:
"""Standardized concept representation."""
Properties
name
@property
def name(self) -> str
Standardized concept name.
label
@property
def label(self) -> str
Standardized human-readable label.
Example:
# Standardization is applied automatically in statements
statement = xbrl.statements.income_statement()
df = statement.to_dataframe()
# Check for standardized vs original labels
print(df[['label', 'original_label']].head())
Rendering
RenderedStatement
Formatted statement output with rich console display capabilities.
class RenderedStatement:
"""Rich formatted statement output."""
Display Methods
str()
def __str__(self) -> str
Plain text representation of the statement.
rich()
def __rich__(self) -> RichRenderable
Rich console representation with formatting.
Example:
# Rich rendering in console
rendered = xbrl.render_statement("BalanceSheet")
print(rendered) # Displays with rich formatting
# Plain text for export
text_output = str(rendered)
Utility Functions
stitch_statements()
def stitch_statements(statements: List[Statement]) -> StitchedStatement
Combine multiple statements into a stitched statement.
Parameters:
- statements: List of Statement objects to combine
Returns: StitchedStatement object
render_stitched_statement()
def render_stitched_statement(stitched_statement: StitchedStatement, **kwargs) -> RenderedStatement
Render a stitched statement with formatting.
Parameters:
- stitched_statement: StitchedStatement to render
- **kwargs: Rendering options
Returns: RenderedStatement object
to_pandas()
def to_pandas(obj: Union[XBRL, Statement, FactsView]) -> pd.DataFrame
Convert various XBRL objects to pandas DataFrame.
Parameters:
- obj: Object to convert (XBRL, Statement, or FactsView)
Returns: DataFrame representation
Advanced Usage Examples
Multi-Period Financial Analysis
from edgar import Company
from edgar.xbrl import XBRLS
# Get multiple years of data
company = Company("AAPL")
filings = company.get_filings(form="10-K").head(3)
xbrls = XBRLS.from_filings(filings)
# Analyze income statement trends
income_stmt = xbrls.statements.income_statement()
revenue_trend = income_stmt.get_trend("Revenue")
revenue_growth = income_stmt.calculate_growth("Revenue")
print(f"Revenue Growth: {revenue_growth.iloc[-1]:.2%}")
Complex Fact Querying
from edgar import Company
from edgar.xbrl import XBRL
company = Company("MSFT")
filing = company.latest("10-K")
xbrl = XBRL.from_filing(filing)
# Complex query with multiple filters
high_value_revenue = (xbrl.facts
.by_concept("Revenue")
.by_value(min_value=50000000000) # $50B+
.by_period(start_date="2023-01-01")
.to_dataframe())
# Pivot analysis
pivot_df = xbrl.facts.pivot_by_period([
"Revenue",
"NetIncomeLoss",
"OperatingIncomeLoss"
])
Statement Comparison
# Compare statements across different companies
companies = ["AAPL", "MSFT", "GOOGL"]
statements = []
for ticker in companies:
company = Company(ticker)
filing = company.latest("10-K")
xbrl = XBRL.from_filing(filing)
if xbrl.statements.income_statement():
statements.append(xbrl.statements.income_statement())
# Create comparison DataFrame
comparison_data = []
for stmt in statements:
df = stmt.to_dataframe()
comparison_data.append(df)
# Analyze key metrics across companies
key_metrics = ["Revenue", "NetIncomeLoss", "OperatingIncomeLoss"]
for metric in key_metrics:
print(f"\n{metric} Comparison:")
for i, stmt in enumerate(statements):
value = stmt.get_concept_value(metric)
if value:
print(f" {companies[i]}: ${value/1e9:.1f}B")
Import Reference
# Core classes
from edgar.xbrl import XBRL, XBRLS
# Statement classes
from edgar.xbrl import Statements, Statement
from edgar.xbrl import StitchedStatements, StitchedStatement
# Facts querying
from edgar.xbrl import FactsView, FactQuery
from edgar.xbrl import StitchedFactsView, StitchedFactQuery
# Standardization and rendering
from edgar.xbrl import StandardConcept, RenderedStatement
# Utility functions
from edgar.xbrl import stitch_statements, render_stitched_statement, to_pandas
Error Handling
from edgar.xbrl import XBRL, XBRLFilingWithNoXbrlData
try:
xbrl = XBRL.from_filing(filing)
except XBRLFilingWithNoXbrlData:
print("Filing does not contain XBRL data")
except Exception as e:
print(f"Error parsing XBRL: {e}")
# Check for statement availability
if xbrl.statements.income_statement():
income_stmt = xbrl.statements.income_statement()
df = income_stmt.to_dataframe()
else:
print("Income statement not found")
XBRL Value Transformations (Issue #463)
EdgarTools provides a two-layer system for XBRL value handling:
Value Layers
- Raw Values (default): Values exactly as reported in the XBRL instance document
- Matches SEC CompanyFacts API
- Preserves original data for analysis
-
No transformations applied
-
Presentation Values (
presentation=True): Values transformed to match SEC filing HTML display - Applies
preferred_signtransformations from presentation linkbase - Cash Flow outflows shown as negative when appropriate
- Matches how values appear in the official 10-K/10-Q HTML
Metadata Columns
All statement DataFrames include XBRL metadata columns:
balance: Debit or credit classification from schema (accounting semantics)weight: Calculation weight from calculation linkbase (+1.0 or -1.0)preferred_sign: Presentation hint from presentation linkbase (+1 or -1)
These columns provide transparency about XBRL semantics and enable custom transformations.
Usage Examples
# Get raw values (default)
xbrl = filing.xbrl()
statement = xbrl.statements.cash_flow_statement()
df_raw = statement.to_dataframe()
# PaymentsOfDividends appears as positive (raw XML value)
dividends = df_raw[df_raw['concept'].str.contains('PaymentsOfDividends')]
print(dividends[['concept', 'balance', 'preferred_sign', '2024-09-30']])
# Output: concept=PaymentsOfDividends, balance=credit, preferred_sign=-1, value=12345000000 (positive)
# Get presentation values (matches SEC HTML)
df_presentation = statement.to_dataframe(presentation=True)
dividends_pres = df_presentation[df_presentation['concept'].str.contains('PaymentsOfDividends')]
print(dividends_pres[['concept', '2024-09-30']])
# Output: value=-12345000000 (negative, matches HTML display with parentheses)
When to Use Each Mode
Use Raw Values (default): - Cross-company financial analysis - Data science and machine learning - Comparison with SEC CompanyFacts API - When you need unmodified reported values
Use Presentation Values (presentation=True):
- Matching SEC filing HTML display
- Creating investor-facing reports
- Replicating official financial statement appearance
- When users expect "traditional" financial statement signs
Technical Notes
- Raw values are consistent across companies: Testing confirmed SEC instance data uses consistent signs
- Metadata always included: All transformations can be recreated using metadata columns
- No data loss: Raw values always preserved, transformations are reversible
Performance Tips
- Use specific queries - Filter facts early to reduce processing time
- Cache XBRL objects - Parsing is expensive, reuse when possible
- Limit statement rendering - Use
max_rowsparameter for large statements - Batch processing - Use
XBRLSfor efficient multi-period analysis
See Also
- Company API Reference - Working with company data
- Filing API Reference - Working with individual filings
- Extract Financial Statements Guide - Practical examples
- Working with Filing Guide - Filing workflows