Rolling Walk-Forward Backtest
Simulate periodic portfolio rebalancing over historical data to evaluate how an optimization strategy would have performed with regular weight updates, capturing realistic out-of-sample performance across multiple time periods.
Overview
A standard portfolio optimization produces a single set of weights based on the entire historical window. While useful, this approach does not reflect how portfolios are managed in practice - real investors periodically rebalance their holdings as new data arrives.
The rolling walk-forward backtest addresses this by splitting the historical period into multiple rebalance intervals. At each interval the optimizer is re-run on a training window of past data, producing fresh weights that are then held for the subsequent out-of-sample period. This cycle repeats across the entire history, generating a sequence of hold-period returns, weight snapshots, and performance metrics.
The result is a far more realistic picture of strategy performance: you see how weights evolve over time, how much turnover each rebalance incurs, and whether the strategy consistently delivers positive risk-adjusted returns or benefits from a single favorable regime.
The backtest can be enabled from the optimizer page when submitting a run, or requested through a connected AI assistant (MCP): assistants such as Claude can submit an optimization with the same rebalance schedule and window configuration, and the run renders the same full results suite described below.
Run It From an Existing Optimization
A succeeded optimization that does not already contain an inline backtest offers Run Backtest on its results page. Choose the rebalance schedule, the re-optimize frequency, estimation-window policy, and a subset of the parent's methods. The backtest becomes a persisted child run with its own queue time, worker duration, status, result artifact, and Excel workbook.
The child reuses the parent optimizer's content-addressed price snapshot and persisted benchmark path. This keeps its historical window attributable to that parent rather than extending the data to the day the backtest was submitted. Older parents without a snapshot are visibly marked as legacy live refetches.
When the parent's frozen prices are too short for the chosen schedule to hold even one period, the submission is refused before it is queued or counted, and the message names the rebalance frequencies that would work.
Open Backtests to see runs across all parent optimizations. A walk-forward result remains one realized historical path, not a probability distribution or a calibrated forecast.
Configuration Options
Rebalance Frequency
Controls how often the book trades back to its target. By default every rebalance also re-optimizes; see Re-optimize Frequency below. Available options:
| Frequency | Cadence | Use Case |
|---|---|---|
| Annual | Once per year | Long-term, low-turnover strategies |
| Semi-Annual | Twice per year (H1/H2) | Balanced rebalancing cadence |
| Quarterly | Four times per year | Active strategies, faster adaptation |
Re-optimize Frequency
Controls how often the optimizer fits a new target, separately from how often the book trades. The Re-optimize every control on the optimize form and in the backtest dialog defaults to Every rebalance, which is the behaviour every backtest had before the control existed. Through the API and MCP the field is reoptimize_frequency, and leaving it out gives the same output as before.
The value must be the rebalance frequency or a coarser one, for example a quarterly rebalance with an annual re-optimization. A finer value is refused with the reason. A rebalance between two re-optimizations calls no optimizer: it trades back to the last fitted target, and its turnover is billed from the drifted weights. When a dated constraint list changed since the last refit, that rebalance refits anyway, and the period records why it refit.
This is a neutral capability. It makes no claim that one rebalance or re-optimization policy performs better than another.
Window Type
Determines how much historical data is used for training at each rebalance point. This is the key “window” parameter.
Expanding Window
Uses all available data from the start of the dataset up to the rebalance date. Each successive period trains on a larger dataset. The window_length_years parameter is ignored in this mode.
Rolling (Fixed) Window
Uses only the most recent years of data before each rebalance date. The training window slides forward with each period, always maintaining the same size. Requires the window_length_years parameter.
Window Length (Years)
Only applies when window_type is set to rolling. Specifies how many years of historical data to include in each training window. For example, a value of 3 means each optimization uses the trailing 3 years of prices. A minimum of 60 trading days is required in each window.
Window Types Explained
Expanding Window
The training set grows with each period as more data becomes available:
More data can stabilize covariance estimates but may include stale market regimes that no longer reflect current conditions.
Rolling Window (e.g. 3 years)
The training window slides forward, always keeping the same length:
Keeps training data fresh and equally weighted across time, better reflecting recent market conditions at the cost of less data per window.
How It Works
The backtest proceeds through four stages for each rebalance period:
1. Build Rebalance Schedule
Based on the chosen frequency, the system identifies all rebalance boundary dates within the available price history. At least two boundaries are required to produce one complete train-hold cycle.
2. Train
For each rebalance date, the optimizer selects the training window (expanding or rolling) and computes the risk model - expected returns and covariance matrix - from the training prices. The selected optimization method then produces a set of portfolio weights. With a coarser re-optimize frequency, this step runs only on a refit date, and the other rebalance dates reuse the last fitted target.
3. Hold (Out-of-Sample Evaluation)
The optimized weights are applied to the next period's prices (the hold window). Portfolio returns are calculated and performance metrics (Sharpe ratio, CAGR, max drawdown, volatility) are measured on this unseen data.
4. Record & Aggregate
Each period records its weights, weight deltas (changes from the prior period), and turnover. Turnover is defined as:
where is the weight of asset at rebalance . After all periods complete, the system aggregates results into summary statistics: total return, CAGR, average Sharpe, max drawdown, total turnover, and annualized volatility.
Output & Visualizations
The results page provides several views into the backtest output:
Summary Card
Displays six key aggregate metrics across all periods: Total Return, CAGR, Average Sharpe, Max Drawdown, Total Turnover, and Annualized Volatility. Values are color-coded (green for positive, red for negative).
Weight Timeline Chart
A stacked area chart showing how portfolio allocation evolves across rebalance periods. Each colored area represents a ticker's weight, stacking to 100%. Tickers can be toggled on/off via the legend.
Weight Delta Chart
A grouped bar chart showing the weight changes at each rebalance. Green bars indicate increased allocation, red bars indicate decreased allocation. Changes below 0.05% are treated as noise and shown as neutral.
Rolling Metrics Chart
A dual-axis line chart tracking three metrics over time: Sharpe ratio (left axis), period return / CAGR (right axis, percentage), and the risk-free rate used in each period (right axis, dashed). A horizontal reference line at Sharpe = 0 is included for context.
Period Details Table
A tabular breakdown of every rebalance period showing: rebalance date, hold dates, risk-free rate, Sharpe ratio, return, volatility, top holdings (top 3 by weight), and turnover. Each row represents one complete train-hold cycle.
When the re-optimize frequency is coarser than the rebalance frequency, the page header states the pair, and a row that held its target shows the drifted turnover it actually traded. The PDF and the workbook show the refit flag, the refit reason, the fit date and the drifted turnover for each period.
Control Arms and the Policy Comparison
A benchmark index differs from the strategy in what it holds as well as in how it trades, so it cannot say whether the re-optimization was worth doing. Each backtest therefore also runs each method under two more policies, on the same book, the same prices and the same hold windows:
- Buy and hold, which trades once at the start and never again.
- Rebalance to original target, which trades back to that same book on the rebalance schedule.
The results page, the PDF and the workbook show two effects that sum to the total by construction: the rebalancing effect (rebalance to original target minus buy and hold) and the re-optimization effect (walk-forward minus rebalance to original target). An arm that cannot cover every hold date of the walk-forward arm is reported as unavailable, with the reason, rather than compounded over a shorter span.
Every figure is pre-tax. Through the API, a flat basis-point transaction cost can be applied, and the net figures then appear beside the unchanged gross figures. The comparison is one realized historical path. It is not a forecast, and it is not evidence that any policy performs better in general.
Constraints in a Backtest
When the optimization carried portfolio constraints, every refit re-optimizes under them, and the weights each period stores are checked against the limits that period applied. A sector or mktcap limit whose classification is dated after the first rebalance date is excluded from the backtest, because applying today's classification to past rebalances would use knowledge the optimizer did not have then. Per-stock limits are always applied.
The results page, the PDF and the workbook state which limits the backtest applied and which it excluded, with the date of the list and the reason. A backtest that lost every limit says that it is an unconstrained backtest.
The Same Metric Suite as the Optimizer
Each method's chained out-of-sample track carries the same headline metric suite the optimizer reports, under the optimizer's own key names: CAGR, volatility, Sharpe, Sortino, Calmar, maximum drawdown, Ulcer index, VaR and CVaR, skewness and kurtosis, benchmark beta, alpha, tracking error and information ratio, plus the full Sharpe inference payload.
The naming is reconciled structurally rather than clerically: the suite is produced by the same function the optimizer runs, so a metric renamed there is renamed here and the two cannot silently diverge into different definitions under one label.
The block states its evaluation window, which is the chained hold periods only and never the training windows the weights were fitted on, and it flags when no benchmark was supplied so a beta of zero is not read as a measured one.
Each completed period also persists the benchmark total return on the portfolio's exact hold dates, on the benchmark series the optimization chose: the price index, or the Total Return Index, which counts the dividends of the index companies. A missing benchmark point makes that paired return unavailable and is never filled from a shorter window. The results page, the PDF and the workbook all compound those same period fields into growth-of-one curves, so a benchmark comparison cannot drift between surfaces or quietly refetch newer market data.
Reports, Exports, and the API
A first-class backtest child run emits a dedicated walk-forward PDF and a dedicated Excel workbook, separate from the optimization report rather than another sheet inside it, because they answer a different question. The optimization report is about the portfolio a method produced; this is about how the method behaved when it had to keep producing them out of sample.
Both state on the cover that every number comes from the hold windows only and that a walk-forward result is a single realized historical path rather than a distribution. The Deflated Sharpe Ratio's trial-count caveat is printed on the page where the DSR appears rather than somewhere a reader will not be. See Reports and Exports.
To drive the workflow programmatically, see the Backtests API: POST /runs/{run_id}/backtest plus the parent-scoped and account-wide listings. Backtests have their own monthly meter, separate from optimizations and Monte Carlo. Before a submission occupies a worker, admission checks two limits: a conservative budget of 300 optimizer solves, and an estimated solve time priced for each method at your universe size. A submission above either is refused, and the message names the limit and the method that costs the most. A backtest with a coarser re-optimize frequency is priced on its refit grid, because a rebalance without a refit calls no optimizer. One with a dated constraint list is still priced on the rebalance grid, because a list change can force a refit at any rebalance. A constrained Critical Line Algorithm cannot enter a backtest above 100 stocks, because its solve time changes from one training window to the next and no estimate holds.
Sharpe Ratio Inference
A raw Sharpe ratio is a point estimate. Without a measure of statistical significance, it is impossible to know whether observed performance reflects genuine skill or is simply the result of a short, lucky sample. This platform computes two inference statistics - the Probabilistic Sharpe Ratio (PSR) and the Minimum Track Record Length (MinTRL) - following López de Prado, Lipton & Zoonekynd (2025/2026) “How to Use the Sharpe Ratio”.
These statistics apply to both regular optimization results (using the full historical daily return series) and rolling backtest results (using the chained out-of-sample hold-period returns). Both supply the return series needed to estimate skewness, kurtosis, and serial correlation.
Why Point Estimates Are Misleading
The standard i.i.d.-Normal assumption for SR inference can underestimate the sampling variance of the Sharpe ratio by 4× or more for realistic returns with negative skew, excess kurtosis, and positive autocorrelation. The five common pitfalls are:
- Ignoring non-normality (skewness and kurtosis)
- Ignoring serial correlation (autocorrelation)
- Using too short a track record
- Treating the annualized SR as if it were normally distributed
- Comparing SRs across different frequencies without adjusting
Generalized Sampling Variance (Eq. 2-3)
The generalized variance of the Sharpe ratio estimator, accounting for non-Normality and serial correlation, is:
where is skewness, is Pearson kurtosis (3 for Normal returns), is AR(1) autocorrelation, and is the number of observations. Setting recovers the classical i.i.d.-Normal result .
Probabilistic Sharpe Ratio - PSR (Eq. 4-5, 9)
The PSR is the probability that the true Sharpe ratio exceeds a benchmark value (typically 0), adjusted for sample properties:
where is the standard Normal CDF and is the generalized standard error evaluated at the null . PSR > 0.95 means 95% confidence that the strategy has genuine positive risk-adjusted returns.
Minimum Track Record Length - MinTRL (Eq. 10-11)
The minimum number of observations required to reject at confidence :
If < MinTRL, the observed Sharpe ratio cannot be reliably distinguished from the null even if it appears large. The platform displays whether your current track record is sufficient and how many additional observations are needed.
Paper Validation Example
López de Prado et al. (2025) report: with ,, ,, and months, the annualized SR estimate is 0.456 with , PSR(SR₀=0) = 0.966, and MinTRL(SR₀=0) ≈ 19.5 months.
Advantages & Limitations
Advantages
- +Out-of-sample evaluation avoids look-ahead bias
- +Reveals strategy robustness across different market regimes
- +Turnover tracking exposes hidden transaction costs
- +Supports both expanding and rolling window modes
- +Works with every optimization method on your plan
- +Weight evolution charts show allocation drift over time
Limitations
- −Requires sufficient history (at least 60 trading days per window)
- −Transaction cost is an optional flat basis-point charge; there is no market-impact or tax model
- −Assumes instantaneous rebalancing at period boundaries
- −Rolling window may discard useful long-term information
- −Computation time scales linearly with number of periods
References
- Bailey, D. H., Borwein, J. M., Lopez de Prado, M., & Zhu, Q. J. (2014). “Pseudo-Mathematics and Financial Charlatanism: The Effects of Backtest Overfitting on Out-of-Sample Performance.” Notices of the AMS, 61(5), 458-471.
- Harvey, C. R., & Liu, Y. (2015). “Backtesting.” Journal of Portfolio Management, 42(1), 13-28.
- Lopez de Prado, M. (2018). Advances in Financial Machine Learning. Wiley. Chapters 11-12 on backtesting and cross-validation.
Not investment advice. Past performance is not indicative of future results.