Skip to content
🤖Walk-Forward Backtest

Walk-Forward Backtest

advanced Python 22 minbacktestingwalk-forward validationlookahead bias
What you'll learn
  • backtesting
  • walk-forward validation
  • lookahead bias
  • long/short signals
  • Sharpe ratio
  • backtest overfitting

Walk-Forward Backtest - Would You Wire the Money? 💸

A fund manager slides a pitch deck across the table: "Our momentum model returned 31% a year for a decade. Sharpe ratio 2.4. Fully backtested." Allocators at pension funds and endowments hear this pitch weekly - and most versions of it die under a single question: how exactly was that backtest run?

There are two classic ways a beautiful backtest lies:

  1. Lookahead bias - the model was trained on data it could not have had at the time. Even one day of leakage can turn garbage into gold.
  2. Backtest overfitting - 500 variants were tried on the same history, and you are being shown the luckiest one.

Today you build a backtest that avoids sin #1 by construction - and you learn how to smell sin #2.

🧠 The mental model: an exam with only past textbooks

A walk-forward backtest is a student who must answer Tuesday's exam question using only books published up to Monday night. For Wednesday's question, Tuesday's book joins the shelf - the shelf grows, but it never contains tomorrow's answers. Concretely:

code
Train on:  rows [i-120 ... i-1]   <- a rolling 120-day window of the past
Predict:   row i's target         <- the NEXT day's return, strictly out of sample
Step:      i -> i+1               <- slide forward, retrain, repeat

One subtlety that catches even professionals: the P&L must be booked on the return the model predicted - the next day's - not on the current row's return, because that value was the final training label one step earlier. Book the wrong day and your "out-of-sample" backtest quietly grades the model on data it has already seen.

If you have run rolling or recursive out-of-sample forecasts in econometrics (pseudo out-of-sample evaluation), this is exactly that idea - applied to a trading rule.

Why not a single split, or k-fold?

MethodRespects time?Verdict for market data
Random k-fold CV❌ shuffles future days into traininglookahead bias - silently inflates every metric
One train/test splithonest, but a single verdict from a single regime
Walk-forwardhundreds of out-of-sample verdicts across bull, bear and sideways markets

From forecast to P&L in three lines

  1. Signal - the model predicts tomorrow's return: positive → go long (+1), negative → go short (-1).
  2. Strategy return - signal * actual_return: you profit on up-days you were long and down-days you were short, and lose when you are wrong-footed.
  3. Sharpe ratio - mean(daily returns) / std(daily returns) * sqrt(252): risk-adjusted performance, annualised. No risk-free subtraction here - this is a directional timing strategy, fully long or fully short one asset each day (never both), so it always carries ±100% net exposure. We drop the risk-free rate as a simplification (it is small at daily frequency); a fully rigorous Sharpe uses excess returns, as the long-only ROI & Sharpe Calculator does. Rule of thumb: above 1 is good, above 2 is suspicious, above 3 means check your code.

Backtest overfitting - the silent career-ender

Bailey, Borwein, López de Prado and Zhu formalised the probability of backtest overfitting (PBO): when a strategy is chosen because it had the best backtest among many trials, the winning Sharpe is mostly selection luck, and PBO estimates how likely that winner is to disappoint out of sample. Their blunt conclusion: a stellar Sharpe discovered after enough attempts carries almost no evidence of skill.

Set your expectations for today accordingly: the price series below is a seeded synthetic random walk - by construction there is nothing to predict, so a no-skill strategy should earn a long-run Sharpe of roughly 0, plus whatever the small drift donates. Whatever number your backtest prints is drift plus the luck of one particular seed - not alpha. If a random-walk backtest ever shows you a gorgeous Sharpe, suspect the backtest before you toast the strategy.

Reading the report

Your program prints five numbers. Learn to scan them like an allocator:

LineWhat it tells youRed flag
Strategy Sharperisk-adjusted return, annualisedtoo good (above 2) on unexciting data
Total Returncompounded P&L over the test spanmeaningless without the risk taken to earn it
Win Rateshare of profitable days50–55% is typical even for genuinely good strategies
Longs / Shortswhat the signal rule is actually doingShorts: 0 means the model is being ignored
Observationsnumber of out-of-sample betssmall samples make every statistic unstable

Your Task

The walk-forward engine below is complete except for one line: the signal rule. Right now signal = 1 on every single day - permanently long. That is not a strategy; it is buy-and-hold wearing a lab coat, and the report betrays it: Shorts: 0.

Fix the rule: +1 when the model predicts a positive return, -1 when it predicts a negative one - so the model's view actually drives the book.

Predict before you run: on a random walk with a small positive drift, will the long/short version beat always-long? And what would a "no-skill" Sharpe look like here? Run it and check yourself.

Related terms in the glossary

Further reading

Where to go deeper. Free means a full, legal copy is online.