Bias✓ Mathematical
◆ The PatternThe silent traps that make your backtest a fantasy
Survivorship bias: testing only on stocks that still exist today (ignoring delisted failures). Look-ahead bias: using data that wasn't available at the time of the decision. Both make backtests look better than reality.
Survivorship: Universe(t) ≠ Universe(today)
The S&P 500 today excluded hundreds of failed companies that were in it in 2005.
Look-ahead: f(t) must use only data from [0, t]
Earnings announced on day t+3 can't inform a decision on day t, even if your database has it.
// Interactive — survivorship bias impact on backtest returns
Delisted %15%
Biased return—
Real return—
# Checklist — is your backtest honest? # 1. Does your universe include delisted stocks? # 2. Are you using point-in-time data? # 3. Are fundamentals lagged by reporting delay? # 4. Is there any future information leaking? # 5. Did you optimise parameters on the test period? # 6. How many strategies did you test? (data snooping) # Point-in-time fundamental data # Use 'as_of' date columns, not 'period_end' df = df[df['report_date'] <= df['trade_date']]
Data snooping: If you tested 100 strategies, 5 will look significant at p < 0.05 by pure chance. Adjust for multiple comparisons (Bonferroni) or use a holdout period you never touch.