Walk-forward orchestrator: rolling in-sample/out-of-sample windows to a WalkForwardResult (C12 axis 3) #69
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
C12 axis 3: walk-forward — the most structurally novel of the family axes, because it varies the data window, not a param or a seed. A window roller produces rolling (in-sample, out-of-sample) splits over the data window (C12); each split bootstraps a harness on its in-sample slice (optionally optimizing params there, reusing axis 2), then evaluates out-of-sample; the OOS pip-equity segments stitch into a continuous out-of-sample curve, plus a param-stability summary across windows.
Build
WalkForwardResult: stitched OOS equity + per-window chosen params + a stability metric.aura walkforward).Depends on
Acceptance
A known multi-window split produces deterministic per-window results and a correctly-stitched OOS curve, with no look-ahead across the IS/OOS boundary (C2).
Contracts
C12 axis 3, C21, C2 (the IS/OOS split is the structural anti-look-ahead boundary).
Design constraint (World-II eager-agnostic firewall — PRIMARY — refs #71)
Walk-forward is the only milestone axis that varies the data window, at the worst scale (a 20y history is the ~190 GB eager object). Its public surface must carry TIME-BOUNDS, not data slices:
WindowBounds { is: (Timestamp, Timestamp), oos: (Timestamp, Timestamp) }— it never holds or indexes tick data, so its type cannot encode a materialized history. NOWindowRoller::new(history: Vec<...>)+&history[lo..hi]slicing.make_source: Fn(Timestamp, Timestamp) -> impl Source— which maps 1:1 ontoDataServer::stream_*_windowed(symbol, from, to). A first impl MAY(from..to).collect()internally.oos.0 > is.1), checkable with zero ticks materialized.requires_lazy_at_scale = true. Depends on #71.
Design reconciliation (specify, in-context entry)
Spec:
0044-walk-forward-family. The fork below is named only loosely in thisissue ("a param-stability summary across windows" / "a stability metric"); the
shape of that summary was resolved in the in-context design discussion.
statistic. → On-demand reduction, not a stored field.
WalkForwardResultstores only the raw per-window outcomes (each carrying its
chosen_params) plusthe stitched OOS curve.
param_stability(&WalkForwardResult) -> Vec<MetricStats>is a public on-demand reduction over the retained per-window chosen params,
reusing the Monte-Carlo family's
MetricStats(mean + type-7 quantiles) perslot.
Rationale (substantive, not effort): a stored summary is a pure reduction over
the raw windows — recomputable, hence redundant — and caching one statistic
forces it canonical when "stability" admits several (a quantile distribution, a
moment std/CV, IQR, a distinct-value count). This mirrors
SweepFamily, whichstores raw points and computes
optimize/rank_byon demand (never cached),rather than
McFamily, whose stored aggregate is the axis's headline. The rawchosen_paramsstay the substrate for any measure the caller wants.Provenance: user decision "R2" on 2026-06-15 in the
/bossspecify session. Theuser drove the reduction explicitly — first "Kann B [std/CV] nicht aus A
[MetricStats] abgeleitet werden?", then "Genügt A, oder ist es sogar selbst
redundant?", then chose R2 = raw-only result + on-demand
param_stabilityhelper.