How to backtest a trading strategy

by , founder of Stochastly

What should be written down before running the first backtest of a new trading idea?

The entry and exit rules, position sizing, market universe, data period, cost assumptions and the acceptance threshold, plus a log of each variant tested afterwards. That variant count is the input the deflated Sharpe ratio needs later.

The checklist summarizes the protocol of Arnott, Harvey and Markowitz in Stochastly's words; the paper's own list is longer.

A backtest replays a set of trading rules on historical data to estimate how they would have performed. Its value depends on the checks around it.

1. Write the rules before looking at results

Define entries, exits, position size and the market universe in advance, and record each variant you test. The number of variants is needed later to correct the results.

Trades of a recorded backtest drawn on the price axis in Stochastly, with each entry and exit placed at its bar.Open full size
Trades of a recorded backtest drawn on the price axis in Stochastly, with each entry and exit placed at its bar.

2. Use point-in-time data

Prices adjusted for splits and dividends, delisted assets kept in the universe, and fundamental or macro data taken at their publication date. Missing any of these introduces survivorship or look-ahead bias.

3. Charge realistic costs

Spread, commission, slippage and financing costs. High-frequency strategies are the most exposed: a small cost per trade multiplied by many trades can remove the whole edge.

“Even with modest transactions costs, the statistical significance of many published anomalies essentially vanishes.”

4. Keep data the strategy has not seen

Split the history into in-sample and out-of-sample periods, or run a walk-forward analysis. Judge the strategy on the out-of-sample results.

5. Correct for the search

When selecting among several configurations, report the deflated Sharpe ratio and, where measurable, the probability of backtest overfitting. Check that performance holds when parameters move slightly.

“Data snooping occurs when a given set of data is used more than once for purposes of inference or model selection.”

6. Set the acceptance threshold in advance

Set the acceptance criteria before the final test. Stochastly reports the measurements it can make and explains the run status, including NO TRADES or NOT CONCLUSIVE. Previews are labelled separately.

Frequently asked questions

How many trades are enough for a backtest?

Enough for the statistics to be stable: a few dozen trades give a very wide confidence interval on the win rate. Several hundred trades are preferable, and more when the strategy has many parameters.

Can I backtest without coding?

Yes. Visual strategy builders such as Stochastly let you assemble rules as a graph of nodes and export them to Python, Pine Script or MQL5.

Why does my backtest not match live results?

The usual causes are costs and slippage, look-ahead bias, survivorship bias and overfitting to the tested period.

Sources

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

White (2000). A Reality Check for Data Snooping. Econometrica 68(5), 1097-1126.

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

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

Bailey and López de Prado (2014). The Deflated Sharpe Ratio: Correcting for Selection Bias, Backtest Overfitting, and Non-Normality. Journal of Portfolio Management 40(5), 94-107.

Primary source for How to backtest a trading strategy

In the library

The Discount Between Backtest and Live, Measured at the Vendors

A Backtesting Protocol for the Machine Learning Era

Ernest Chan (backtest hygiene for the practitioner)

A backtest is reported with the number of trials, or it is not reported

The Efficient-Market Null, Stated by Its Defenders

Rolls and Continuous Futures Contracts: a Constructed, Untraded Series

Custom Node Code: the Allow-List, the Contract, and Vectorised versus Event-Driven

Related