Skip to main content

secfin

Fetch company financial records from SEC EDGAR.

Installation

pip install secfin

Or install from source:

pip install -e .

Quick Start

from secfin import SECClient, Company

# Initialize client (SEC requires User-Agent with contact info)
client = SECClient(user_agent="MyApp contact@email.com")

# Get company financials
company = Company("AAPL", client)

# Income Statement
income = company.get_income_statement()
print(f"Revenue: {income.revenue.latest()}")
print(f"Net Income: {income.net_income.latest()}")

# Balance Sheet
balance = company.get_balance_sheet()
print(f"Total Assets: {balance.total_assets.latest()}")
print(f"Cash: {balance.cash.latest()}")

# Cash Flow Statement
cashflow = company.get_cash_flow()
print(f"Operating Cash Flow: {cashflow.operating_cash_flow.latest()}")
print(f"Free Cash Flow: {cashflow.free_cash_flow.latest()}")

Features

  • Income Statement: Revenue, Cost of Revenue, Gross Profit, R&D, SG&A, Operating Income, Net Income, EPS, Shares Outstanding
  • Balance Sheet: Assets, Liabilities, Equity, Cash, Inventory, Debt
  • Cash Flow: Operating, Investing, Financing cash flows, CapEx, Dividends, Free Cash Flow
  • Analytics: TTM calculations, YoY growth, CAGR, margins, ratios
  • Caching: Automatic disk caching to reduce API calls
  • Async Support: Async batch fetching for improved performance

Data Export

Convert to pandas DataFrame:

# Get historical data as DataFrame
df = company.get_income_statement().to_dataframe()
print(df)

Get a summary of all financials:

summary = company.summary()
print(summary)

Quarterly vs Annual Data

# Annual data (10-K filings)
annual_income = company.get_income_statement(period="annual")

# Quarterly data (10-Q filings)
quarterly_income = company.get_income_statement(period="quarterly")

Financial Analytics

income = company.get_income_statement()

# Trailing Twelve Months (TTM)
ttm_revenue = income.revenue.ttm()

# Year-over-Year Growth
yoy_growth = income.revenue.growth()  # Returns decimal (0.1 = 10%)

# Compound Annual Growth Rate
cagr_5yr = income.revenue.cagr(years=5)

# Margins
gross_margin = income.gross_margin()
operating_margin = income.operating_margin()
net_margin = income.net_margin()

# Balance Sheet Ratios
balance = company.get_balance_sheet()
current_ratio = balance.current_ratio()
debt_to_equity = balance.debt_to_equity()

Caching

Responses are cached locally to reduce API calls (default: 24 hours).

# Disable caching
client = SECClient("MyApp contact@email.com", cache_enabled=False)

# Custom cache TTL (1 hour)
client = SECClient("MyApp contact@email.com", cache_ttl=3600)

# Clear cache
client.clear_cache()

# View cache stats
print(client.cache_stats())
# {'files': 10, 'size_bytes': 5000000, 'size_mb': 4.77}

Async Batch Fetching

For faster fetching of large ticker lists:

import asyncio
from secfin import SECClient, AsyncBatchFetcher

client = SECClient("MyApp contact@email.com")
fetcher = AsyncBatchFetcher(client, max_concurrent=5)

# Async fetch
results = asyncio.run(fetcher.fetch_tickers(["AAPL", "MSFT", "GOOGL"]))

# Or use the sync wrapper
from secfin import run_async_fetch
results = run_async_fetch(client, ["AAPL", "MSFT", "GOOGL"])

Earnings Dates

Get historical and estimated future earnings dates:

company = Company("AAPL", client)

# Last earnings date
last = company.last_earnings()
print(f"Last Filing: {last['date']} ({last['form_type']})")

# Next earnings (estimated)
next_e = company.next_earnings()
print(f"Next Expected: {next_e['date']} ({next_e['fiscal_quarter']})")

# Historical earnings dates
history = company.earnings_history(limit=10)
for h in history:
    print(f"{h['date']} | {h['form_type']} | {h['fiscal_quarter']}")

# Full earnings calendar
calendar = company.get_earnings_calendar()
print(f"Fiscal Year End: {calendar.fiscal_year_end}")
df = calendar.get_historical_df()

Example Output

Last Earnings:
  Filing Date: 2026-01-30
  Period End: 2025-12-27
  Form Type: 10-Q
  Quarter: Q1

Next Earnings (Estimated):
  Expected Date: 2026-04-30
  Form Type: 10-Q
  Quarter: Q2

Rate Limiting

The client automatically respects SEC's rate limit (10 requests/second).

Batch Fetching - Index Constituents

Fetch financials for entire indices:

from secfin import SECClient, BatchFetcher

client = SECClient("MyApp contact@email.com")
fetcher = BatchFetcher(client)

# Fetch all S&P 500 companies (~500 companies)
sp500_data = fetcher.fetch_sp500()

# Fetch all NASDAQ 100 companies (~100 companies)
nasdaq_data = fetcher.fetch_nasdaq100()

# Fetch custom list of tickers
tickers = ["AAPL", "MSFT", "GOOGL", "AMZN", "META"]
custom_data = fetcher.fetch_tickers(tickers)

Progress Tracking

def my_progress(current, total, ticker, status):
    print(f"Progress: {current}/{total} - {ticker}: {status}")

fetcher = BatchFetcher(client, on_progress=my_progress)
results = fetcher.fetch_nasdaq100()

Export to DataFrame

# Get summary DataFrame with key metrics
summary_df = fetcher.summary_dataframe(results)
print(summary_df)

# Get specific metric across all companies
revenue_df = fetcher.to_dataframe(results, "income_statement", "revenue")
print(revenue_df)

Available Indices

Index Method Companies
S&P 500 fetch_sp500() ~500
NASDAQ 100 fetch_nasdaq100() ~100
Russell 2000 fetch_russell2000(tickers) ~2000 (requires ticker list)

Russell 2000

Russell 2000 constituent list is not freely available. You need to provide your own list:

# Load your Russell 2000 tickers
russell_tickers = [...]  # Your list of ~2000 tickers

results = fetcher.fetch_russell2000(tickers=russell_tickers)

Requirements

  • Python 3.9+
  • requests
  • pandas

License

MIT

Metadata

Release files for secfin 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for secfin 1.0.0
File Size Uploaded Provenance
secfin-1.0.0.tar.gz 51.7 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for secfin 1.0.0
File Interpreter ABI Platform
secfin-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 102.9 kB

Release files / secfin-1.0.0.tar.gz

Download URL secfin-1.0.0.tar.gz
Size 51.7 kB
Tags Source
SHA-256 checksum
How to use checksums
e914ee0aa961f19adeb382ec542c4b72735e5f209299bad23cb7d4490adaa1f7
BLAKE2b-256 checksum
How to use checksums
bfaa77eff3d62b79a4a3a53db302ba1eee9686d0bb552a59678ce88c3e14f3e0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.1

Release files / secfin-1.0.0-py3-none-any.whl

Download URL secfin-1.0.0-py3-none-any.whl
Size 51.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d2ee9af152f6897f209f0b2ad3cb2f4efd5b1df58c8d735b5a537eb37d8a5014
BLAKE2b-256 checksum
How to use checksums
064577941a3dfd3779b7f25f4b1015482b827c37e3d6538f1615163689c5419a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.1

Security for secfin 1.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page