Look-ahead bias in backtesting

by , founder of Stochastly

How can a Pine Script backtest use a daily close before that close exists?

A request.security call to the daily timeframe with lookahead set to barmerge.lookahead_on returns the final daily value on the intraday bars of that day. Requesting close[1] instead returns the previous completed day, which a live chart also had.

Look-ahead bias appears when a backtest uses information that was not available at the moment the trading decision was made.

Where look-ahead bias comes from

Filling an order at the close of the bar whose close generated the signal. Using an indicator computed on the full series, such as a normalization over the full history. Reading economic data at its reference date when it was published weeks later, or after a revision.

Each of these leaks makes the backtest trade on the future, and the result cannot be reproduced live.

Publication calendar of a macro series in Stochastly: the delay between each observation date and the date the value was published.Open full size
Publication calendar of a macro series in Stochastly: the delay between each observation date and the date the value was published.

The Pine Script case

In TradingView, calling request.security on a higher timeframe with lookahead set to barmerge.lookahead_on returns the final value of the higher-timeframe bar while it is still forming. Historical bars then show values that a live chart did not have.

The usual fix is to request the previous completed value, for example the series shifted by one bar, when lookahead is on.

request.security(syminfo.tickerid, "D", close[1], lookahead = barmerge.lookahead_on)

“The most reliable approach to achieve non-repainting results is to use an expression argument that only references past bars (e.g., close[1]) while using barmerge.lookahead_on as the lookahead value.”

How to detect it

A causal strategy gives the same output for past bars when future bars are removed. Truncating the series at a cut, replaying the strategy and comparing the overlap bar by bar reveals any output that depended on data after the cut.

Stochastly runs this truncation test before a search and stops the run when past output changes.

“Traders can often confirm whether a strategy has lookahead bias by forward testing it on realtime data, where no known data exists beyond the latest bar.”

Frequently asked questions

What is an example of look-ahead bias?

Buying at the open of a day using that day's closing price, or using a quarterly figure at its period end when it was published later.

Is repainting the same as look-ahead bias?

Repainting indicators change their past values as new data arrives. When a backtest reads those revised values, the result carries look-ahead bias.

How is look-ahead bias different from survivorship bias?

Look-ahead bias uses future information in time. Survivorship bias uses a universe filtered by the future, such as testing on the assets that still exist today.

Sources

TradingView (n.d.). Other timeframes and data. Pine Script v6 User Manual, Concepts.

TradingView (n.d.). Strategies. Pine Script v6 User Manual, Concepts.

Arnott, Harvey and Markowitz (2019). A Backtesting Protocol in the Era of Machine Learning. Journal of Financial Data Science 1(1), 64-74.

Brown, Goetzmann, Ibbotson and Ross (1992). Survivorship Bias in Performance Studies. Review of Financial Studies 5(4), 553-580.

Primary source for Look-ahead bias in backtesting

Related