SEC Financial Statements Data: EDGAR Bulk Downloads, XBRL, Insider Trades and 13F Holdings
Published 2026-08-04 · DataForge team
Everything a US public company tells the SEC is free on EDGAR: every 10-K, every insider trade, every hedge-fund 13F. The SEC even publishes structured bulk datasets so you don’t have to parse filings yourself. And yet most people who start with “I’ll just download it from EDGAR” lose two weekends before their first clean quarterly time series. This guide covers the official bulk sources — Financial Statement Data Sets, Form 3/4/5 insider files, 13F holdings — what breaks when you use them raw, and code that works.
The official bulk sources
Financial Statement Data Sets. Quarterly zips of every number in every XBRL financial statement: four files per quarter (sub.txt submissions, num.txt numeric facts, tag.txt taxonomy, pre.txt presentation). This is the source behind “SEC EDGAR financial statements datasets” searches, and it’s genuinely comprehensive — tens of millions of facts per quarter.
Insider transactions (Forms 3/4/5). Since 2004 every officer/director/10% owner trade is filed in structured XML; the SEC packages these quarterly too. Transaction date, shares, price, ownership after — the raw material of every “insider buying” signal.
Form 13F holdings. Quarterly portfolio snapshots of every institutional manager above $100M. Structured data sets exist from 2013Q2 onward.
Company facts API. https://data.sec.gov/api/xbrl/companyfacts/CIK##########.json returns every reported XBRL fact for one company — perfect for single-company lookups, hopeless for cross-sectional work (you’d make 8,000 requests, rate-limited to 10/s).
What breaks when you use the raw files
Tag chaos. Companies report the “same” concept under different XBRL tags: Revenues, RevenueFromContractWithCustomerExcludingAssessedTax, SalesRevenueNet… Building a comparable revenue series across companies means maintaining tag-mapping logic that changes with each taxonomy release. This is the single biggest time sink.
Restatements and amendments. The same period appears in multiple filings (original 10-K, amended 10-K/A, next year’s comparative figures). Naive loading double-counts; you must deduplicate by (company, concept, period) with a precedence rule.
Identifier joins. Financial data keys on CIK; market data keys on ticker; tickers change and get recycled. The SEC’s company_tickers.json mapping is current-state only, so historical joins need a point-in-time crosswalk.
Scale. All quarters of num.txt together are hundreds of millions of rows. Loading “just the numbers” into pandas is not a plan; you need a database and a schema.
Working code: from zip to queryable
One quarter of financial facts into DuckDB:
import duckdb, urllib.request
url = "https://www.sec.gov/files/dera/data/financial-statement-data-sets/2025q2.zip"
urllib.request.urlretrieve(url, "2025q2.zip")
con = duckdb.connect("edgar.db")
for t in ("sub", "num"):
con.execute(f"""
CREATE OR REPLACE TABLE {t} AS
SELECT * FROM read_csv('zip://2025q2.zip/{t}.txt',
delim='\t', header=true, quote='')
""")
# Quarterly revenue for filers reporting under the common tags
print(
con.execute("""
SELECT s.name, n.ddate, n.value/1e6 AS revenue_musd
FROM num n JOIN sub s USING (adsh)
WHERE n.tag IN ('Revenues',
'RevenueFromContractWithCustomerExcludingAssessedTax')
AND n.qtrs = 1 AND s.form = '10-Q'
ORDER BY n.value DESC LIMIT 10
""").df()
)
Insider-trade aggregation, once you have a normalized transactions table:
-- Net insider buying by company, trailing 90 days
SELECT issuer_cik,
issuer_name,
SUM(CASE WHEN transaction_code = 'P' THEN shares * price ELSE 0 END)
- SUM(CASE WHEN transaction_code = 'S' THEN shares * price ELSE 0 END)
AS net_insider_usd
FROM insider_transactions
WHERE transaction_date >= CURRENT_DATE - INTERVAL '90 days'
AND transaction_code IN ('P', 'S') -- open-market buys/sells only
GROUP BY issuer_cik, issuer_name
ORDER BY net_insider_usd DESC
LIMIT 20;
The transaction_code IN ('P','S') filter matters: most Form 4 rows are grants, exercises and tax withholding (codes A, M, F), not conviction trades. Skipping this filter is the most common beginner error in insider-signal research.
13F holdings: reconstructing institutional portfolios
The 13F corpus deserves its own workflow notes because it trips people differently. Each quarter, every institutional manager above $100M files a table of long positions: issuer, CUSIP, share count, market value. The structured data sets are clean — the semantics are not. Managers file amendments (restatements vs additions — the amendmentType field matters), some file combined reports for sub-advisors while others file separately (double-counting risk when you aggregate “institutional ownership” of a stock), and values were reported in thousands of dollars before 2023 and in dollars after — a silent 1000× landmine in any time series crossing that boundary.
The classic outputs, once normalized: quarter-over-quarter position changes per manager (the actual signal — levels are stale by up to 45 days), crowding metrics (how many funds hold the same name, concentration of the top holders), and clone portfolios (replicating a manager’s disclosed book). Each needs the CUSIP→ticker mapping, which is not free from the SEC — another quiet reason assembled datasets exist; ours ships issuer-linked holdings so the join is already done.
import pandas as pd
h = pd.read_parquet("holdings.parquet") # normalized 13F table
# Biggest new positions opened last quarter across all managers
last, prev = "2026-03-31", "2025-12-31"
cur = h[h.period == last].set_index(["manager_cik", "cusip"])["value_usd"]
old = h[h.period == prev].set_index(["manager_cik", "cusip"])["value_usd"]
new_positions = cur[~cur.index.isin(old.index)].sort_values(ascending=False)
print(new_positions.head(15))
What people build with EDGAR data
- Fundamental screens and backtests. Point-in-time fundamentals without a Bloomberg terminal.
- Insider-signal strategies. Cluster buying by officers is one of the most-studied public anomalies.
- 13F tracking. Reconstruct hedge-fund portfolios and crowding metrics quarterly.
- Credit and counterparty monitoring. Leverage and liquidity trends for any filer, including bond-only issuers.
- LLM training and RAG. Structured facts ground financial-QA systems; filings text plus facts make strong eval sets.
Free EDGAR vs. a cleaned dataset
| Raw SEC bulk files | DataForge dataset | |
|---|---|---|
| Cost | Free | From $199 |
| Facts | All, but tag-mapped by you | 27M+ facts, deduplicated, in analysis-ready tables |
| Insider trades | Quarterly XML/TSV zips | 8.8M Form 3/4/5 non-derivative transactions, one table |
| 13F | Separate quarterly sets | 20.7M holdings rows (L tier), manager-linked |
| Identifiers | CIK only; DIY crosswalk | CIK + ticker on every table |
| Restatements | Handle yourself | Deduplication convention applied and documented |
| Total size | 100GB+ raw | 68.2M rows across 8 tables (L tier) |
Honest guidance: for one company, use the free company-facts API — it’s excellent. For cross-sectional research, budget 2–4 weeks to build your own pipeline from the bulk files, or buy the cleaned tables and start querying today. The free 500-row sample shows the exact schema.
FAQ
Is EDGAR data legal to redistribute or use commercially? Yes — SEC filings are US government-published public records. No license fee, no attribution requirement (though citing filings is good practice).
Why do reported numbers differ from Yahoo Finance? Aggregators adjust and standardize; EDGAR facts are as-reported under GAAP taxonomy. Both are “right” — as-reported is what you want for research reproducibility.
How fast does data appear after filing? Filings hit EDGAR within seconds; the bulk Financial Statement Data Sets refresh quarterly. Our snapshot editions follow the bulk cadence.
Which forms matter beyond 10-K/10-Q, Form 4 and 13F? A practical shortlist. 8-K: material events within four business days — M&A, executive departures, restatement warnings (Item 4.02 is the scariest three-digit number in finance). S-1: IPO registrations, the only public financials many companies ever show before listing. 13D/13G: activist and passive 5%+ ownership stakes — 13D filings move prices the day they land. DEF 14A (proxy): executive compensation detail far richer than anything in the 10-K. All are in EDGAR full-text search and the daily index files; the structured bulk datasets covered in this guide are the financial-statement, insider and 13F corpora because those are the ones with clean tabular publications.
How do I map XBRL tags to a standard income statement? The honest answer: with a mapping table you maintain. Start from the FASB taxonomy’s presentation networks (the pre.txt file shows how each filer organizes its own statements), pick your canonical concepts (revenue, operating income, net income, total assets…), and map the top ~50 tags by frequency — that covers the vast majority of filers; the long tail is judgment calls. Expect industry exceptions (banks and insurers use entirely different statement structures) and check your aggregate against a known-good source for a sample of companies before trusting it. Our tables ship with the mapping convention documented per field, which is most of what you’re paying for.
Can I use this for point-in-time backtests? Yes, with care — this is actually EDGAR’s superpower versus vendor fundamentals. Each fact carries its filing (accepted) date, so you can reconstruct exactly what was knowable on any historical date, avoiding the look-ahead bias baked into restated vendor data. The discipline required: always join on filing date, not period date, and keep amended filings as separate observations rather than overwriting.
Do 13Fs show short positions or bonds? No — long US equity-ish positions only (Section 13(f) securities), reported up to 45 days late. Treat 13F-based “smart money” signals accordingly.