Point-in-Time Universe
get_pit_universeUse this tool to answer questions about historical index membership — e.g. "Was Company X in the S&P 500 on date Y?" (S&P 500 members on a date, including former members, from 1996) or "Which companies were in the Russell 2000 on 2010-01-01?" Use this INSTEAD OF search_companies when the question involves a specific historical date or whether a company was an index member in the past — search_companies only returns current membership and cannot answer historical questions.
Returns a survivorship-free universe valid on a given as_of_date (only companies that existed and were members on that exact date — no hindsight; [) interval semantics). To check one company, pass ticker (a ticker or, better, a CIK) + index + the target date: present = was a member, absent = was not.
⚠️ HISTORICAL DEPTH AND PROVENANCE DIFFER BY INDEX — read this before using a result for a backtest.
• SP500 — membership history from 1996, reconstructed and incomplete before about 2007. Those years hold fewer members than the index had, and many changes are dated to a window, not a day. Long-delisted registrants are included. Check _meta.pit_safe and each row's confidence before relying on a date.
• RUSSELL1000 / RUSSELL2000 / RUSSELL3000 — back to 2000-09-30, medium confidence. Reconstructed from the N-PORT and N-CSR portfolio filings of funds that track each index, plus publicly available constituent lists and public reports of index changes. Three consequences you must carry into any conclusion: OBSERVATION SPACING VARIES — roughly one to four observations a year from 2000 through 2006, monthly from 2007 on — so a join or leave date is only as precise as the interval between observations and is never exact to the day in the early years; a tracking fund only PROXIES its index, so a few holdings sit outside the index and a sampled fund can miss some members; and there is NO data before 2000-09-30 — an earlier as_of_date returns zero rows because we do not carry it, which is not a statement that the index was empty.
• Known gap: 2016-12-30 → 2017-07-31. No holdings observation exists anywhere in that 213-day window, so Russell membership cannot be observed inside it. Departures collapse onto 2016-12-31 and arrivals onto 2017-07-31, which means the June 2017 reconstitution appears to happen on 31 July. Treat Russell results dated inside that window as interpolated.
Returns per company: CIK, ticker, name, sector, industry, SIC code, enriched, and per-row confidence (high/medium/low). The CIK is always present and is the identifier to carry forward; every other identity field is nullable. enriched: false means index_membership names this member but the company has no row in references (it delisted before SEC's current-only ticker map was written) — its identity is UNKNOWN, not absent, and it is still a member. ticker is separately null when the company was not listed under any ticker on the as_of_date.
⚠️ A RESPONSE IS USUALLY A PAGE, NOT THE UNIVERSE. universe_size always reports the FULL matched membership count; returned_rows reports what THIS response carries; complete is true only when they are equal, and survivorship_free is true only when complete is — a slice of a universe is not a survivorship-free universe. A response carries one page of at most limit rows (default 100, never more than 250 inlined), starting at offset; whenever rows remain after it the response carries a truncation envelope, so call again with offset = its next_offset (same other arguments) until the pages sum to universe_size. To get the whole universe in one read, use get_compute_ready_stream, the Python SDK, or the Bulk Data API. Index rows are ordered by CIK — deliberately uncorrelated with whether a company survived to today, so a truncated page is an arbitrary sample rather than a list of survivors. _meta.pit_safe is true only when EVERY matched row is high-confidence — so it is false for any Russell query by construction. That flag is the one to branch on: when it is false, treat the universe as approximate, whatever the index. sector is SIC-derived (GICS-aligned, not licensed GICS) — a screening bucket, not an authoritative label.
Use as the first step of a quantitative backtest before get_compute_ready_stream. Returns an empty array (with error detail) if the date is out of range or has no coverage. Available on every plan — sample returns the subset covered by the sample bucket.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| index | No | Index filter. 'sp500' (~500 large caps; reconstructed history from 1996, incomplete before ~2007, check pit_safe), 'russell1000' (~1000 large/mid), 'russell2000' (~2000 small caps), 'russell3000' (~3000 broad market) — the three Russell indices carry fund-derived history back to 2000-09-30 at medium confidence, with observation spacing that widens before 2007. Omit for no index filter (sector-only or full universe queries). | |
| limit | No | Rows per page (1–3500; at most 250 are inlined per call). Defaults to 100. `universe_size` always states the full matched count; when more rows remain after this page the response carries a `truncation` envelope — call again with `offset` = its `next_offset`. Universe is deduped to one row per CIK (SP500 ~505, Russell 3000 ~3050). | |
| offset | No | Zero-based row offset where this page starts. Pass the previous response's `truncation.next_offset` to fetch the next page. Defaults to 0. | |
| sector | No | Sector filter (case-insensitive substring) over the SIC-derived, GICS-aligned label (not licensed GICS — see tool description). E.g. 'Technology', 'Energy'. | |
| ticker | No | Check ONE company: a ticker or a CIK (SEC identifier), e.g. 'AAPL' or '0000320193'. Returns that company's row if it was a member on as_of_date, none if it was not. A ticker matches the symbol listed ON that date, and a since-delisted member can carry no ticker at all (enriched=false), so prefer the CIK for historical checks. Omit to list the universe. | |
| is_active | No | Filter to active (currently trading) companies only. Omit to include all. WARNING: setting this to true on a HISTORICAL query reintroduces survivorship bias — companies that were active on as_of_date but later went bankrupt or got acquired will be filtered out. Leave unset for true PIT backtests. | |
| as_of_date | No | Historical date (YYYY-MM-DD) for survivorship-free construction. Index queries use index_membership join/leave dates (entrants after the date excluded, later-removed members kept); sector queries use security valid_from/valid_to. Omit for the current universe. | |
| include_share_classes | No | false (default) collapses to one row per CIK (index-provider convention — BRK counts once, not BRK-A + BRK-B). true returns every share-class row (GOOG and GOOGL separately) — for security-level analysis only. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| note | Yes | ||
| _meta | Yes | Provenance envelope — data lineage for every MCP response | |
| index | Yes | ||
| sector | Yes | ||
| complete | Yes | ||
| coverage | Yes | ||
| companies | Yes | ||
| as_of_date | Yes | ||
| truncation | No | Present only when the inline-row cap withheld rows. Page with `next_offset` (keep the same `limit`) or pull the full set via get_compute_ready_stream. | |
| coverage_gap | Yes | ||
| returned_rows | Yes | ||
| universe_size | Yes | ||
| limit_truncated | Yes | ||
| survivorship_free | Yes | ||
| confidence_summary | Yes |