← Back to blog

Walk Forward Validation: Why a 19–20% RMSE Gain Can Be Fake

October 17, 2026
Walk Forward Validation: Why a 19–20% RMSE Gain Can Be Fake

Walk forward validation trains a model on past data and tests it on the immediate future, then rolls the origin forward to produce honest out-of-sample estimates and prevent temporal leakage. Each fold only sees what was knowable at that moment. You can build it with scikit-learn's TimeSeriesSplit, but the real work is keeping features and labels from crossing the split.


TL;DR:

  • Choose an expanding window when data is limited and distant history remains useful; choose a fixed rolling window when older regimes mislead.
  • A controlled LSTM study found that building sequences before splitting and shuffled cross validation with 10 folds inflated reported RMSE by roughly 19% to 20%.
  • Keep the gap at least as long as the forecast horizon, with extra buffer for slow decaying features, and purge training labels that overlap testing.
  • Report each fold’s metric alongside its mean and standard deviation, and preserve an untouched final holdout because repeated model testing can inflate results.

Sonicaigold
Explore Automated Gold Trading
Sonic AI focuses on XAUUSD trading, using COPYX to let investors automatically copy trades managed by an experienced team.
Visit Sonic AI

Table of Contents

What walk forward validation is and which window to pick

The procedure is simple. Train on a block of past observations, predict the next block, record the error, then advance the origin and repeat. Every test period sits strictly after its training period, so the evaluation mirrors how the model will actually run. The method grew out of trading-system work: optimize on an in-sample window, test on the following out-of-sample window, slide forward, and aggregate the results, as the walk forward optimization literature describes.

Two windowing modes cover most cases.

Expanding (anchored) window. The training set always starts at the first observation and grows with each fold. Use it when data is limited and you believe the distant past still carries signal.

Rolling (sliding) window. The training set keeps a fixed length and drops the oldest data as it moves. Use it for non-stationary series where old regimes can mislead the model, such as markets that change character.

If you are unsure, run both and compare fold stability.

Expanding and rolling training windows across folds

Why it matters: temporal leakage, overlapping labels, and the leakage tax

Why it matters: temporal leakage, overlapping labels, and the leakage tax — overview diagram

Temporal leakage means information from the future reaches the model during training. Shuffled k-fold does this by design: a test row's neighbors from the following days land in the training set. Overlapping labels make it worse. If your label spans multiple future periods, a training row can share much of its label window with a later test row. The model has effectively seen the answer.

The size of the distortion can be large. A controlled LSTM study found that building sequences before splitting, then running 10-fold cross-validation, produced RMSE gains of roughly 19–20% in leaky setups compared with clean ones.

A leaky pipeline can report a 19–20% RMSE gain that does not exist. That gap came from sequence generation before the split, not from any real predictive skill.

Treat that gap as a diagnostic. Call it the leakage tax: score the same model under shuffled CV and under walk forward validation, and the difference estimates how much your pipeline flatters itself. For the broader overfitting picture, see our note on the risk of overfitting in machine learning.

Core parameters and rules for configuring the splits

Four settings control a walk forward experiment, and each trades one thing for another.

  • n_splits: more folds give more out-of-sample observations and a steadier estimate, but each test block gets smaller and the early folds train on less data.
  • test_size: by default, scikit-learn sets it to n_samples // (n_splits + 1). Set it explicitly to match your real forecasting block.
  • horizon and extra_gap: the total separation between train end and test start should be at least the forecast horizon. A multi-step-ahead label needs a gap at least as long as the forecast horizon, plus any extra buffer for slow-decaying features.
  • window_size and max_train_size: a long window gives stable fits but adapts slowly and uses more memory. A short window adapts faster but is noisier.

Aim for enough folds that you can see a trend, not a single point. A handful of tiny test sets can swing wildly on one volatile week, so a good-looking average from very few folds deserves suspicion.

How to implement it correctly: TimeSeriesSplit, post-split features, and purge/embargo

TimeSeriesSplit is expanding by default: in each split, earlier folds form the training set and the next fold is the test set, so successive training sets are supersets of earlier ones. The gap and max_train_size arguments let you add a buffer and cap the window, as the scikit-learn documentation outlines. The splitter only returns indices, though. Everything else is on you.

  1. Compute your total gap as horizon plus extra_gap and pass it to the splitter.
  2. For each split, take the raw, unprocessed series and cut the train and test index ranges.
  3. Generate features and labels inside the training fold only, using nothing beyond its last timestamp.
  4. Build test features from the last training context plus the test rows, so lags and rolling stats are available without peeking at test labels.
  5. Purge any training rows whose label window overlaps the test period, and embargo a short stretch after the test block if later folds could reuse it.
  6. Fit, predict, and store the metric for that fold.
  7. After the loop, aggregate across folds and keep the per-fold values.

Pro Tip: Always print the indices and assert that train_end + total_gap < test_start for every fold before you trust a single metric.

Common pitfalls and defensive checks

Most leakage comes from a short list of mistakes:

  • Computing features or labels on the full dataset before splitting.
  • Using centered or full-sample rolling statistics that include future values.
  • Setting a gap shorter than the label horizon.
  • Letting overlapping labels straddle the boundary.
  • Tuning hyperparameters on the same out-of-sample folds you report.

Defend against them with automated checks. Regenerate sequences after each split, assert the temporal boundary, and run a shuffled CV as a sanity comparison. If shuffled scores look far better than walk forward scores, you have measured leakage, not skill. Also report fold stability, not just the mean, using the same logic as equity curve analysis.

Pro Tip: Lock an untouched final holdout before any experimentation and write down your splitting rules, so a later reader can reproduce them exactly.

How to interpret and report out-of-sample results

Report the mean and standard deviation of your metric across folds, then show the fold-by-fold series. A flat line suggests stability. A downward drift points to decay or a regime shift that an average would hide. Forecast evaluation research describes rolling-origin evaluation as a way to obtain multiple test periods, while noting the need for gap and purge discipline to avoid leakage.

Publish the configuration beside the numbers: window type, n_splits, test_size, horizon, extra_gap, and feature rules. Add the shuffled-CV comparison so readers can see your leakage tax. And remember the limit: walk forward validation is necessary, not sufficient. Trying many variants still inflates results through multiple testing. For how this carries into live results, see our comparison of backtest vs live trading.

Walk forward is a minimum, not a finish line

We treat walk forward validation as the minimum discipline for any forecasting or trading model, because without it a result tells you very little. But passing it only earns a model the right to be checked further. A strategy still needs independent verification and a final holdout that nobody touched. In applied finance, the number that matters is the one a third party can reproduce.

— Paulo

This article is general information, not a substitute for advice from a qualified financial advisor. Consult a qualified financial professional about your own circumstances before acting on anything here.

FAQ

How do you do walk forward analysis?

Split the data in time order, train on a past window, and test on the next block. Roll the origin forward and repeat, collecting each out-of-sample result. Generate features inside each training fold and keep a gap at least as long as your forecast horizon.

What is the difference between a backtest and walk forward?

A simple backtest fits once and evaluates over a single historical stretch. Walk forward refits repeatedly and tests on many successive out-of-sample periods, which shows whether performance holds up as conditions change. It is a more honest check of robustness.

How do you validate a forecast?

Use time-ordered evaluation such as a rolling origin, never shuffled folds. Keep a gap that covers the forecast horizon and watch fold-by-fold stability. A rolling-origin approach gives several test periods instead of one.

Why does shuffled cross-validation inflate scores?

Shuffling places future observations in the training set, so the model sees information it would not have in production. A controlled LSTM forecasting study measured large score gaps between leaky and clean pipelines.

Sources

Where to run this with real money on the line

If you apply this discipline to gold, we built Sonic AI for XAUUSD, and our results are independently verified rather than backtest-only. You can copy trades automatically through COPYX without trading manually. Review our live results and setup guides on the Sonic AI live page, then decide whether the track record meets your own standard.