Weeknight listicle: SEC companyfacts bulk ZIP (nightly ~3am ET), SEC Financial Statement Data Sets 2026 Q2 ZIP, EdgarTools, pitedgar, optional Kaggle CSV. Download → Polars/pandas → a ratio screen. Not a yfinance vs Polygon bake-off. Not investment advice.
Five free, documented ways to get US company fundamentals onto a laptop without a market-data contract. This is not a yfinance vs Polygon comparison, not a ranking contest, and not investment advice. The only course CTA is Introduction to Python Programming.
Related Hub: Polars 1.44 if you load Parquet/CSV after the download.
SEC access must follow SEC.gov developer / fair-access rules: identify yourself (User-Agent with a real email), no CORS from a browser app, no hammering data.sec.gov. The Commission does not provide tech support for scrapers.
From the EDGAR APIs page: JSON APIs need no key. A bulk ZIP of all companyfacts JSON is recompiled nightly at approximately 3:00 a.m. ET.
https://www.sec.gov/Archives/edgar/daily-index/xbrl/companyfacts.ziphttps://data.sec.gov/api/xbrl/companyfacts/CIK##########.json (10-digit CIK, leading zeros)companyfacts.zip is the efficient way to fetch large amounts of XBRL company-facts / frames data. Submissions bulk ZIP is separate (submissions.zip). APIs update through the day; the ZIP is the overnight snapshot.
Financial Statement Data Sets (January 2009 – June 2026). Numeric face financials from XBRL, flattened, updated quarterly. 2026 Q2 is listed as a ZIP (57.62 MB on the table as of the page last reviewed 30 June 2026). Data filed after the last business day of a quarter lands in the next quarterly posting. December 2024 reprocess: NUM file gained a segments field; see the Commission PDF for table layouts.
Disclaimer on that page: derived from registrant filings; not a substitute for the filings; review full filings before any investment decision.
edgartools)dgunning/edgartools — MIT, pip install edgartools. Typed objects for 10-K/10-Q, 8-K, 13F, Form 4, XBRL. SEC requires an identity email:
from edgar import Company, set_identity
set_identity("your.name@example.com") # required; no API key
# Company("AAPL").get_financials().income_statement() # see current docs
Use it when you want one ticker’s statements, not the whole bulk ZIP.
arielNacamulli/pitedgar, PyPI pitedgar (0.4.0 as of 30 Apr 2026, Python ≥ 3.11). Downloads the same companyfacts.zip, writes local Parquet, queries with the filed date (when the number was public), not period-end — the point of a PIT pipeline. Depends on edgartools>=5.0. Identity email still required. The ZIP is ~1.5 GB; do not fetch every run.
from pathlib import Path
from pitedgar import PitEdgarConfig, build_cik_map, download_bulk, parse_all, PitQuery
config = PitEdgarConfig(
edgar_identity="Your Name you@example.com",
data_dir=Path("./data"),
)
# cik_map = build_cik_map(["AAPL", "MSFT"], config)
# download_bulk(config) # periodic
# parse_all(config, cik_map)
# q = PitQuery(config.data_dir / "pit_financials.parquet")
If you already have a Kaggle account and a small, clearly licensed fundamentals or ratios CSV you use for teaching, load it as a fallback when SEC bulk is too large for tonight. Prefer datasets that cite SEC as the origin. Skip mystery “100k stocks” dumps with no licence. This slot is optional — items 1–4 are enough.
Pick one source. Respect rate limits. Synthetic-scale sketch if the ZIP is still downloading:
import io
from pathlib import Path
# After you unzip a Financial Statement Data Set quarterly ZIP, you typically
# get tab-separated NUM / SUB / TAG / PRE files (see the SEC PDF). Names:
# num.txt, sub.txt, tag.txt, pre.txt
# Example: load NUM, join SUB on adsh, filter a us-gaap tag, compute a ratio.
try:
import polars as pl
# df = pl.read_csv("num.txt", separator="\t", infer_schema_length=10000)
# print(df.columns)
except ImportError:
import pandas as pd
# df = pd.read_csv("num.txt", sep="\t", low_memory=False)
# Tiny local ratio sketch (replace with joined Assets / Liabilities from NUM):
import pandas as pd
demo = pd.DataFrame({
"cik": [320193, 789019],
"assets": [350e9, 500e9],
"liab": [250e9, 300e9],
})
demo["equity_proxy"] = demo["assets"] - demo["liab"]
demo["leverage"] = demo["liab"] / demo["assets"]
print(demo.sort_values("leverage"))
A “ratio screen” here means sort and look — not a trading rule. Tag names differ across US-GAAP versions; always keep the accession (adsh) and filed / period columns.
If Python I/O is the hard part, Introduction to Python Programming, then download one SEC ZIP (or pip install edgartools) with a proper User-Agent.