Quant
Look-ahead bias — the one-bar mistake
There's a particular feeling that should scare you: the backtest comes back and the equity curve is beautiful. Smooth, steep, barely a drawdown. Before you celebrate, consider the most likely explanation — not that you found an edge, but that somewhere in your code the strategy peeked. Look-ahead bias is when a backtest uses information that wasn't available at the moment it pretends to decide. It is the single most common way a great backtest turns into a losing algo.
Where it hides
The four classic leaks
- Deciding at the close, using the close. Your rule fires when today's close crosses a moving average — and you fill at today's close. But you only knew the close once the bar was over. In reality you'd fill at the next open, at a different price. This one line is the archetype.
- Full-sample normalization. You z-score your features using the mean and standard deviation of the entire series, then split into train and test. The test set's own statistics have now leaked backwards into every training row. Same for fitting a scaler before splitting, or filling missing values with a global median.
- Restated data. The Q1 earnings number in your database is the final, revised figure. It was published in May and revised in August — but your backtest reads it on April 1st. The strategy trades on a number that didn't exist for months.
- Event time vs availability time. A news item is timestamped when the event happened, not when your feed delivered it. A filing is dated the period it covers, not the day it hit the wire. Your code sees it early, every time.
Your strategy accidentally reads tomorrow's newspaper. It doesn't feel like cheating — it's usually one line where a number arrives earlier in your data than it ever did in real life — but it turns a coin flip into a genius.
The one-bar test
Here's a cheap, brutal diagnostic. Lag every signal by one bar and re-run. Push your entire decision one step later than you think you need to, so there's no possible way the strategy touches data from its own decision moment.
If the edge survives with slightly worse numbers — good, it was probably real and you've just paid a realistic delay. If the edge evaporates, you didn't have a strategy. You had a leak. A genuine edge does not depend on being one bar early; that's the whole difference between an effect and an artefact.
Building the discipline in
Fixing individual bugs is whack-a-mole. The structural fix is to make leakage hard by construction:
- Timestamp everything by availability, not by event. Every row should carry "when could I have known this?" and your engine should read strictly by that clock.
- Decide on bar
t, fill on bart+1. Make it a rule the engine enforces, not something each strategy remembers. - Fit on train only. Any statistic — mean, scaler, feature selection, even which strategy you chose — must be computed from data before the point of use.
- Be suspicious of beauty. An unusually smooth curve is evidence of a bug, not of skill. Investigate your best results hardest.
Look-ahead is the sibling of survivorship bias — one leaks the future through your data, the other through your universe — and it's the reason walk-forward validation is built the way it is: a strictly forward-moving clock leaves nowhere for the future to leak in. Get the clock right first. Everything you measure afterwards — Sharpe, drawdown, expected value — is meaningless if the strategy was reading ahead.