advanced
10 minPoint-in-Time Universe Construction
Build a survivorship-bias-free historical S&P 500 universe for any rebalance date.
PITuniversebacktestingDuckDB
## The Survivorship Bias Problem
If you use today's S&P 500 list to backtest 2018 strategies, you're including companies that weren't in the index in 2018 — and excluding companies that were delisted since then. This is survivorship bias and it inflates backtest returns.
`index_membership` keys on `cik` and uses `effective_date` / `removal_date` as the half-open `[)` membership window. `client.pit_universe(date)` applies that window for you and returns each member's ticker on that date.
python
from datetime import date from valuein_sdk import ValueinClient, ValueinError try: with ValueinClient() as client: # pit_universe() reads index_membership: members on that date, # including companies that have since left the index or delisted. universe_2020 = client.pit_universe("2020-01-02") print(f"S&P 500 size on 2020-01-02: {len(universe_2020)} companies") universe_now = client.pit_universe(date.today().isoformat()) print(f"S&P 500 size today: {len(universe_now)} companies") # Members today that were not members in 2020 (matched on CIK, not ticker) added = universe_now[~universe_now["cik"].isin(universe_2020["cik"])] print(f"Added since 2020: {len(added)} companies") print(sorted(added["ticker_at_date"].dropna())[:10]) except ValueinError as e: print(f"Error: {e}")Try it yourself
Every snippet runs on the free sample with no token. Add one to run this notebook against all 120.5M+ SEC EDGAR facts.