Basic Prerequisites: 01 · From Zero.
1. Intuition & Practical Objective
SEC EDGAR is the only source in this folder that is simultaneously free, authoritative, and point-in-time by construction - because it stores filings, and a filing is immutable once submitted. Every commercial provider is, at bottom, a repackaging of EDGAR (plus non-US filings, estimates, and prices). Learning to read EDGAR directly is the difference between renting your fundamental data and owning it.
Three things EDGAR gives you, and the job each does:
- Filing documents (10-K, 10-Q, 8-K, DEF 14A, Form 4, 13-F) - the primary text; everything else is derived from these. Full-text search finds disclosures, risk factors, and the raw tables.
- XBRL facts (the
companyfacts/companyconcept/framesJSON APIs) - the statements already machine-read, as tagged by the filer. This is the layer a pipeline actually ingests. - Submission metadata (
submissionsAPI) - the filing index with accession numbers and filing dates, which is exactly the that makes a panel point-in-time.
The hard part is not fetching. The hard part is that XBRL is not a schema, it is a vocabulary - the filer chooses which tag expresses “revenue,” and the same economic concept can carry a dozen different us-gaap: element names. Mapping tags to canonical fields, deterministically and in priority order, is the craft of this page.
2. Mathematical Ground Truth & Derivations
The three data endpoints (all free, no login, JSON):
| Endpoint | Pattern | Gives you | Use it for |
|---|---|---|---|
| companyfacts | data.sec.gov/api/xbrl/companyfacts/CIK{10-digit}.json | all XBRL facts ever filed by one company, by taxonomy | full history of one firm |
| companyconcept | data.sec.gov/api/xbrl/companyconcept/CIK{…}/us-gaap/{Tag}.json | one tag’s values across all periods | a single line item, all vintages |
| frames | data.sec.gov/api/xbrl/frames/us-gaap/{Tag}/USD/CY{year}.json | one tag for all filers in one period | cross-sectional screens / universe pulls |
| submissions | data.sec.gov/submissions/CIK{…}.json | the filing index + filing dates | resolving |
The rate-limit rule. The SEC requires an identifying User-Agent and throttles politely; treat ≤ 10 requests/second as the budget and prefer frames bulk pulls over per-company loops wherever the screen allows it (the cost comparison is quantified in 05).
Tag resolution as a deterministic function. Because the filer picks the tag, extraction is a priority search, not a lookup:
with the priority list fixed before you ever touch the data. Making the list ad hoc - “whatever tag I found that year” - is how tag drift silently changes the meaning of a time series. The canonical revenue priority used below is:
Duration vs. instant. Revenue, net income, and cash flow are duration facts (they carry start and end); assets and equity are instant facts (they carry only end). The frames convention makes this explicit in the period key: revenue frames are keyed CY2019 (a year), balance-sheet frames are keyed CY2019Q4I (an instant).
3. Computational Implementation - the companyfacts parser and tag mapper
Offline and fully runnable (stdlib only). It embeds a companyfacts-shaped document and applies the priority mapper to produce the canonical FY2022 row, printing the resolved tag for each field so the mapping is auditable.
Note the output: revenue resolved to the ASC-606 tag, not to Revenues - precisely the priority-list decision that makes the series stable. Had Revenues been tried first, a pre-606 firm and a post-606 firm would be mixed in one column.
The live fetch stub (requires network; shown for completeness, not executed here) - the only EDGAR-specific requirement is the identifying User-Agent:
4. Failure Modes & First-Principles Breakdowns
- Tag drift (first principle: XBRL is a vocabulary, not a schema). The same firm can switch revenue tags between years; an unversioned extraction then joins two different concepts into one time series. Rule: fix the priority list and record which tag resolved each point.
- Taxonomy-version drift. A
us-gaapelement deprecated in one taxonomy release may be the only tag a 2014 filing used. Pin the taxonomy version you claim to interpret against (03 covers vendor standardization of exactly this). - Ignoring
form/fp/fy. The same period value appears repeatedly across filings (10-K, then 10-K/A, then next year’s comparatives); picking the first match can grab a quarter figure or a comparative rather than the annual as-filed value. Rule: filter onform="10-K",fp="FY",fy=year, and take the latest accession, not the first. - Duration/instant mixing. Summing
Assetsacross four quarters (“to annualize”) is meaningless - assets are an instant, not a flow. Only duration facts add over time. - Rate-limit abuse → silent IP block. Looping a 5,000-name universe one request at a time both takes ≥8 minutes at the theoretical floor and invites throttling; use
framesor the quarterly bulk archives instead (quantified in 05). - Treating EDGAR as restatement-free. EDGAR keeps every filing, which is a feature - but it means “the latest 10-K’s comparative column” is a restated vintage. Point-in-time extraction requires reading the original filing, not the newest one that mentions the period.
5. References
- SEC, EDGAR APIs
- XBRL US (xbrl.us)
- Arelle (arelle.org)
- Loughran & McDonald (JF, 2011)
- WRDS Compustat User’s Guide
6. Connected Graph Bridges
- Back: 01 · From Zero · Index Hub
- Forward: 03 · Commercial Providers · 04 · Insider & Ownership
- Application: Accounting Quality & Red Flags (filings are where red flags are found) · 06 · Advanced Extensions (EDGAR as the pipeline’s ingestion layer)