Walk-forward
Validate a run over out-of-sample windows — `vike-cli backtest run` over a profile carrying a [walkforward] table, which replaced the retired top-level `walkforward` verb.
This verb moved — it is `vike-cli backtest run` now
Walking forward is how a run is validated, not a different kind of run, so it stopped being a
verb of its own. Put a [walkforward] table in the profile and run vike-cli backtest run with
the same file: n_splits is the window count and mode/rank_by shape it.
was: vike-cli walkforward --profile wf.toml
now: vike-cli backtest run --profile wf.tomlThe old spelling is refused by name with that pairing printed — vike-cli carries it in
crates/vike-cli/src/lib.rs's RETIRED_COMMANDS, so a pasted old command tells you what to type
rather than reading as a typo.
⚠ There is no --local. The standalone engine has no walk-forward driver to spawn, so unlike a
plain backtest run this one has only the remote route.
The anchored out-of-sample sibling of backtest. Ship a profile's
TOML verbatim to a remote vike-datahub server, run
the walk-forward there — the existing vike_backtest::harness::run_walkforward, next to the data —
and print the stitched out-of-sample result, with no DataFusion in this side's build graph
(crates/vike-cli/src/cmd/walkforward.rs).
usage: vike-cli walkforward --profile <run.toml> [--addr 127.0.0.1:7878] [--json]| flag | meaning |
|---|---|
--profile <path> | required. A backtest profile .toml, shipped verbatim. Its [walkforward] table supplies n_splits, the number of anchored out-of-sample windows |
--addr <host:port> | the data service address; default 127.0.0.1:7878 |
--json | print the server's WalkForwardReport JSON |
-h, --help | print the usage to stdout and exit 0 |
[walkforward] is a first-class profile section like [sweep], so one file describes the whole
run — see run profiles. A profile with no [walkforward]
table comes back as a clean server-side error. Reach a remote server over
ssh -L 7878:localhost:7878 <host>.
Bar mode, one series
A tick or multi-symbol profile is a clean error, never a silent fallback
Server-side this is bar mode over one series: the splitter divides a single bar series by index. A tick profile or a multi-symbol profile is refused outright rather than quietly running on the first symbol it finds — which would produce a plausible report about a different experiment than the one the profile describes.
Why the profile crosses the wire whole
Like the sweep sibling, this replaced a client-side profile→DTO
mapping whose WireSlice/WireEngineParams pair could not carry [engine].fee and the rest of the
[engine] surface. The server now parses the profile with the one BacktestProfile::from_toml_str
parser, so the walk-forward honours the whole [engine] — the cost model
and market impact a run was configured with are the ones it
actually ran under. The Studio's DTO-shaped RunWalkforward wire verb is untouched and still serves
the GUI (remote runs).
The output
One row per out-of-sample window, then the summary line. Every number is the server's own — nothing is recomputed on this side.
walk-forward: 2 out-of-sample window(s)
window test_range oos_return
1 [0, 60) +5.00%
2 [60, 120) -2.00%
oos_return = +2.90% oos_sharpe = 0.810 wf_consistency = 50.0%test_range is the window's half-open bar index range as the server reported it. The three summary
scalars are the stitched out-of-sample return, its Sharpe, and the walk-forward consistency — the
fraction of windows that came back positive. What each one is for, and the trap of reading a single
number off a small number of windows, is on walk-forward and
validation.
A degenerate report renders rather than breaking: a numeric field that is absent or null — which
is serde_json's encoding of a non-finite f64 — reads as 0.0, so a run with no windows still
prints a table instead of failing at the printer.
Under --json the bytes are the server's own WalkForwardReport, including the oos_equity_curve
the human table does not draw.
Related
The usual order is a sweep to pick a parameter point, then this verb over the winner; overfitting is why the second step is not optional. Running a backtest covers running the same profile as a single in-sample run first.