Lookahead bias: how a backtest cheats without telling you
The four most common ways future information leaks into a backtest, why the results still look believable, and how to rule the leak out by construction.
3 min read
A backtest makes one claim: if you had followed these rules back then, this is what would have happened. Lookahead bias is when the test knows something the trader could not have known at the moment of the decision.
It rarely looks like cheating. It looks like a clean equity curve.
Four ways the future gets in
Deciding on the close and filling on the same close. A signal computed from a bar’s close can only be acted on after that bar has closed. The earliest honest fill is the open of the next bar. On daily data that gap is the overnight session, which is exactly where the gaps live. A test that fills at the close it just read is trading a price nobody could get.
Using the higher timeframe after it has finished. You trade five-minute bars and filter on “above the day’s open and below the day’s high”. At ten in the morning the day’s high isn’t known yet. If the test reads it from a finished daily candle, it knows how the day ends.
Indicators computed over the whole series. Normalizing a feature with the mean and standard deviation of the full sample, scaling to the all-time range, or smoothing with a centered window. Every one of these reaches past the current bar. The code looks innocent because the leak is inside a library call.
Choosing the period after seeing the chart. This one lives in the person, not the code. You test on a stretch you remember, because you remember it went somewhere. The rules might be clean; the sample isn’t. We wrote more about this in why we hide the dates.
Why the results still look believable
Lookahead seldom produces absurd returns. It produces a curve that is slightly too smooth, a win rate a few points too high, drawdowns that end a bar too early. Each leak is small, which is why it survives review, and small edges compound into a strategy that fails the week it goes live.
Ruling it out by construction
Reading your own code for leaks is necessary, but you can’t prove a negative by reading. The sturdier fix is a test in which the future is simply not there to leak.
That’s how the replay engine behind Backstride works. It advances one one-minute bar at a time. Every timeframe you can look at, from one minute to one day, is built from those bars and cut at the cursor, so the hourly candle you see at 10:20 has twenty minutes in it, exactly as it would live. An order placed on a bar fills on a later one, never on the bar that prompted it. Nothing ahead of the cursor reaches the chart, the panels or a single statistic.
A short checklist
- Delete every bar after the cursor. Does any number on screen change? Then it was reading the future.
- A signal on bar N should fill on bar N + 1 at the earliest.
- Higher-timeframe values should come from the candle that is still forming, not the finished one.
- Write down the date range before you look at the chart, or better, let something else choose it.