Bootstrap net R through the process pipeline #259

Closed
opened 2026-07-13 18:06:13 +02:00 by claude · 5 comments
Collaborator

std::monte_carlo consumes the gross realized-R series even when the campaign carries a cost model, so a costed campaign cannot produce a net pooled-OOS distribution — the natural headline for any gross-to-net question.

Evidence (external data-only research project, 2026-07-13, engine 84e1075): the same 18-point H1-breakout matrix ran twice on EURUSD 2018-2026 (seed 0, regime vol{3, k2.0}) — once with no cost block, once with cost: [{"constant":{"cost_per_trade":0.00012}},{"vol_slippage":{"slip_vol_mult":0.1}}]. The two runs' pooled_oos stage records are identical to every printed digit (mean −0.1498 / −0.2040, prob_le_zero 0.884 / 0.988 for the two strategy cells), while the same members' full-window net_expectancy_r moves by −0.61 to −0.67 R/trade against gross. The cost model is applied and stamped (cost[k].<knob> manifest params) but the walk-forward → monte-carlo evidence chain never sees it.

net_expectancy_r is already rankable/gate/generalize-able; the bootstrap stage has no analogous net path. A net-R series through std::walk_forward OOS pooling (or a net: true knob on std::monte_carlo) would close the gap.

`std::monte_carlo` consumes the gross realized-R series even when the campaign carries a cost model, so a costed campaign cannot produce a net pooled-OOS distribution — the natural headline for any gross-to-net question. Evidence (external data-only research project, 2026-07-13, engine 84e1075): the same 18-point H1-breakout matrix ran twice on EURUSD 2018-2026 (seed 0, regime vol{3, k2.0}) — once with no cost block, once with `cost: [{"constant":{"cost_per_trade":0.00012}},{"vol_slippage":{"slip_vol_mult":0.1}}]`. The two runs' `pooled_oos` stage records are identical to every printed digit (mean −0.1498 / −0.2040, prob_le_zero 0.884 / 0.988 for the two strategy cells), while the same members' full-window `net_expectancy_r` moves by −0.61 to −0.67 R/trade against gross. The cost model is applied and stamped (`cost[k].<knob>` manifest params) but the walk-forward → monte-carlo evidence chain never sees it. `net_expectancy_r` is already rankable/gate/generalize-able; the bootstrap stage has no analogous net path. A net-R series through `std::walk_forward` OOS pooling (or a `net: true` knob on `std::monte_carlo`) would close the gap.
claude added the feature label 2026-07-13 18:06:13 +02:00
Author
Collaborator

Design reconciliation (specify)

Spec: net-r-bootstrap. The issue body leaves the mechanism open ("a net-R series through std::walk_forward OOS pooling, or a net: true knob on std::monte_carlo"); this records the resolution of the three load-bearing forks. All three are derived orchestrator decisions (recorded 2026-07-13), not user picks.

  • Fork: where the per-trade net-R series lives → the existing bootstrap conduit is redefined and renamed: RMetrics.trade_rs becomes RMetrics.net_trade_rs, carrying the cost-netted realised R per trade (r − cost_in_r, trade order), still #[serde(skip)] and excluded from PartialEq.
    Basis: derived — the conduit exists solely to feed the OOS R-series bootstrap (its own doc comment, crates/aura-analysis/src/lib.rs:103), and the issue is precisely the demand that this feed be net; with an empty cost stream every trade's cost is exactly 0.0 (summarize_r's documented gross-R baseline, lib.rs:188), so r − 0.0 is bit-identical to the gross series and uncosted campaigns are byte-unchanged; the design ledger already anticipates the per-trade net-R sequence as the durable artifact (docs/design/INDEX.md:585-588: the cost model is "a feed-forward subtraction on the R stream", compounding derives from "the per-trade net-R sequence"). The rename (rather than a silent meaning change under the old name) makes every consumer compiler-enumerated.
  • Fork: how summarize_r exposes the series without disturbing its scalar contract → the net series is materialized as a new, separate expression; every existing pinned-float expression (net_sum, the SQN pair, the lockstep-coupled copies in r_metrics_from_rs) keeps its tokens verbatim.
    Basis: derived — the file's own byte-pin discipline (lib.rs:266 "kept bit-identical to the pre-0067 expression"; lib.rs:318-329 lockstep-coupling doc) forbids refactoring pinned float arithmetic; a sibling materialization adds the series without shifting any existing metric by a ULP. The wire shape is untouched (serde(skip)).
  • Fork: how std::monte_carlo selects gross vs net → no knob. Both bootstrap arms (pooled-OOS and per-survivor) read the single net conduit; net-when-costed is automatic and uncosted campaigns degenerate to today's gross bootstrap bit-exactly.
    Basis: derived — an explicit net: true knob would let a costed campaign silently produce a gross headline again, which is the exact misreading the issue documents; the uncosted bit-equality makes the automatic choice free of behaviour change; and no vocabulary/schema change means preflight, StageBlock, and StageRealization/StageBootstrap back-compat are untouched.

Consequence recorded for the same reason: the pooled walk-forward OOS reduction (pooled_trade_rsr_metrics_from_rs) thereby reduces the net series, so a costed campaign's pooled-OOS stage record (mean, prob_le_zero, deflation inputs) becomes net-based — the issue's requested headline — while every per-member gross metric (expectancy_r etc.) stays gross.

## Design reconciliation (specify) Spec: net-r-bootstrap. The issue body leaves the mechanism open ("a net-R series through std::walk_forward OOS pooling, or a net: true knob on std::monte_carlo"); this records the resolution of the three load-bearing forks. All three are derived orchestrator decisions (recorded 2026-07-13), not user picks. - **Fork: where the per-trade net-R series lives** → the existing bootstrap conduit is redefined and renamed: `RMetrics.trade_rs` becomes `RMetrics.net_trade_rs`, carrying the cost-netted realised R per trade (`r − cost_in_r`, trade order), still `#[serde(skip)]` and excluded from `PartialEq`. Basis: derived — the conduit exists solely to feed the OOS R-series bootstrap (its own doc comment, `crates/aura-analysis/src/lib.rs:103`), and the issue is precisely the demand that this feed be net; with an empty cost stream every trade's cost is exactly `0.0` (`summarize_r`'s documented gross-R baseline, `lib.rs:188`), so `r − 0.0` is bit-identical to the gross series and uncosted campaigns are byte-unchanged; the design ledger already anticipates the per-trade net-R sequence as the durable artifact (`docs/design/INDEX.md:585-588`: the cost model is "a feed-forward subtraction on the R stream", compounding derives from "the per-trade net-R sequence"). The rename (rather than a silent meaning change under the old name) makes every consumer compiler-enumerated. - **Fork: how `summarize_r` exposes the series without disturbing its scalar contract** → the net series is materialized as a new, separate expression; every existing pinned-float expression (`net_sum`, the SQN pair, the lockstep-coupled copies in `r_metrics_from_rs`) keeps its tokens verbatim. Basis: derived — the file's own byte-pin discipline (`lib.rs:266` "kept bit-identical to the pre-0067 expression"; `lib.rs:318-329` lockstep-coupling doc) forbids refactoring pinned float arithmetic; a sibling materialization adds the series without shifting any existing metric by a ULP. The wire shape is untouched (`serde(skip)`). - **Fork: how `std::monte_carlo` selects gross vs net** → no knob. Both bootstrap arms (pooled-OOS and per-survivor) read the single net conduit; net-when-costed is automatic and uncosted campaigns degenerate to today's gross bootstrap bit-exactly. Basis: derived — an explicit `net: true` knob would let a costed campaign silently produce a gross headline again, which is the exact misreading the issue documents; the uncosted bit-equality makes the automatic choice free of behaviour change; and no vocabulary/schema change means preflight, `StageBlock`, and `StageRealization`/`StageBootstrap` back-compat are untouched. Consequence recorded for the same reason: the pooled walk-forward OOS reduction (`pooled_trade_rs` → `r_metrics_from_rs`) thereby reduces the net series, so a costed campaign's pooled-OOS stage record (mean, prob_le_zero, deflation inputs) becomes net-based — the issue's requested headline — while every per-member gross metric (`expectancy_r` etc.) stays gross.
Author
Collaborator

Design reconciliation, addendum (specify)

Spec: net-r-bootstrap. The grounding gate rejected the first draft for an incomplete consumer enumeration: the bootstrap conduit has two further production consumer families beyond the two monte-carlo arms recorded in issues/259#issuecomment-3526. Both are now scoped in; the fork decisions (derived, recorded 2026-07-13):

  • Fork: deflation null basis → the deflation null-max (member_trade_rs → the centred null_best_of_k behind overfit_probability) follows the conduit and becomes net-based for costed campaigns.
    Basis: derived — today a costed campaign that selects on net_expectancy_r compares a net observed statistic against a gross-resampled null, because the null's metric recomputation maps NetExpectancyR onto the plain mean of whatever series it is fed (aura-registry/src/lib.rs:513-524); a single net conduit puts observed and null on one basis, removing that inconsistency, and uncosted campaigns stay bit-identical (cost 0.0). Keeping the null gross would require a second, gross conduit whose only purpose is preserving an apples-to-oranges comparison.
  • Fork: walk-forward oos_r record basis → the standalone walk-forward summary's pooled OOS reduction (pooled_oos_trade_rs, aura-cli/src/main.rs:878-891, plus the reports-pooling sibling at main.rs:955-957) follows the conduit and becomes net-based for costed runs.
    Basis: derived — this is the issue's literal ask ("a net-R series through std::walk_forward OOS pooling"), and the helper's own doc declares it "the single home of the pooling-in-roll-order semantics — both the walk-forward oos_r summary and the mc R-bootstrap reduce this": summary and bootstrap must stay on one basis or the single-home invariant is broken.

Boundary restated precisely: per-member RMetrics scalar fields stay gross (net_expectancy_r keeps its meaning); every conduit-derived artifact — pooled-OOS bootstrap, per-survivor bootstrap, walk-forward oos_r, deflation null — is net-when-costed. No consumer reads the conduit and stays gross.

## Design reconciliation, addendum (specify) Spec: net-r-bootstrap. The grounding gate rejected the first draft for an incomplete consumer enumeration: the bootstrap conduit has two further production consumer families beyond the two monte-carlo arms recorded in `issues/259#issuecomment-3526`. Both are now scoped in; the fork decisions (derived, recorded 2026-07-13): - **Fork: deflation null basis** → the deflation null-max (`member_trade_rs` → the centred `null_best_of_k` behind `overfit_probability`) follows the conduit and becomes net-based for costed campaigns. Basis: derived — today a costed campaign that selects on `net_expectancy_r` compares a **net** observed statistic against a **gross**-resampled null, because the null's metric recomputation maps `NetExpectancyR` onto the plain mean of whatever series it is fed (`aura-registry/src/lib.rs:513-524`); a single net conduit puts observed and null on one basis, removing that inconsistency, and uncosted campaigns stay bit-identical (cost 0.0). Keeping the null gross would require a second, gross conduit whose only purpose is preserving an apples-to-oranges comparison. - **Fork: walk-forward `oos_r` record basis** → the standalone walk-forward summary's pooled OOS reduction (`pooled_oos_trade_rs`, `aura-cli/src/main.rs:878-891`, plus the reports-pooling sibling at `main.rs:955-957`) follows the conduit and becomes net-based for costed runs. Basis: derived — this is the issue's literal ask ("a net-R series through std::walk_forward OOS pooling"), and the helper's own doc declares it "the single home of the pooling-in-roll-order semantics — both the walk-forward `oos_r` summary and the `mc` R-bootstrap reduce this": summary and bootstrap must stay on one basis or the single-home invariant is broken. Boundary restated precisely: per-member `RMetrics` scalar fields stay gross (`net_expectancy_r` keeps its meaning); every conduit-derived artifact — pooled-OOS bootstrap, per-survivor bootstrap, walk-forward `oos_r`, deflation null — is net-when-costed. No consumer reads the conduit and stays gross.
Author
Collaborator

Spec auto-signed (specify Step 6, autonomous run)

Spec: net-r-bootstrap (net-of-cost R through the walk-forward → monte-carlo evidence chain: one net conduit feeding the pooled-OOS / per-survivor bootstraps, the walk-forward oos_r record, and the deflation null; uncosted runs bit-identical).

The signature is the Step-5 grounding-check PASS — an independent fresh-context agent's verdict; eight load-bearing assumption clusters each ratified against currently-green tests (report in the session transcript). No human signed; the fork decisions live at issues/259#issuecomment-3526 and issues/259#issuecomment-3528. Status: design settled, spec signed — proceeding to implementation planning.

## Spec auto-signed (specify Step 6, autonomous run) Spec: net-r-bootstrap (net-of-cost R through the walk-forward → monte-carlo evidence chain: one net conduit feeding the pooled-OOS / per-survivor bootstraps, the walk-forward `oos_r` record, and the deflation null; uncosted runs bit-identical). The signature is the Step-5 grounding-check `PASS` — an independent fresh-context agent's verdict; eight load-bearing assumption clusters each ratified against currently-green tests (report in the session transcript). No human signed; the fork decisions live at `issues/259#issuecomment-3526` and `issues/259#issuecomment-3528`. Status: design settled, spec signed — proceeding to implementation planning.
Author
Collaborator

Design reconciliation, planning-stage addendum (specify/planner)

Spec: net-r-bootstrap. Two decisions derived while decomposing the plan (recorded 2026-07-13); both are testing-channel calls, not semantic changes to the forks in issues/259#issuecomment-3526 / issues/259#issuecomment-3528.

  • Fork: e2e host dependency → the new #259 e2e runs hostless over the synthetic per-test archive (a synthetic-instrument campaign document beside the GER40-hardcoded fixture helper), not over real GER40 behind a data-present skip-guard.
    Basis: derived — an evidence-chain guard that skips on data-less hosts protects nothing exactly where the suite runs most; the synthetic archive's ~8 contiguous months support the existing 14d/7d/7d walk-forward roller arithmetic (verified during recon), and hostless synthetic fixtures are the direction the suite-wallclock work already ratified.
  • Fork: costed walk-forward oos_r observation channel → none exists today, deliberately: the dissolved walkforward/mc sugar binds an empty cost list unconditionally, so no cost-bearing walk-forward summary can be invoked. The oos_r/deflation sites' net basis is therefore covered by the compile-forced single-conduit construction plus their uncosted exact-float pins staying green (bit-exact degeneracy), and the spec's testing section states this instead of prescribing an unimplementable assertion. Making the sugar cost-bearing is recorded as a non-goal (verbs stay cost-less sugar; costed research goes through campaign documents).
## Design reconciliation, planning-stage addendum (specify/planner) Spec: net-r-bootstrap. Two decisions derived while decomposing the plan (recorded 2026-07-13); both are testing-channel calls, not semantic changes to the forks in `issues/259#issuecomment-3526` / `issues/259#issuecomment-3528`. - **Fork: e2e host dependency** → the new #259 e2e runs hostless over the synthetic per-test archive (a synthetic-instrument campaign document beside the GER40-hardcoded fixture helper), not over real GER40 behind a data-present skip-guard. Basis: derived — an evidence-chain guard that skips on data-less hosts protects nothing exactly where the suite runs most; the synthetic archive's ~8 contiguous months support the existing 14d/7d/7d walk-forward roller arithmetic (verified during recon), and hostless synthetic fixtures are the direction the suite-wallclock work already ratified. - **Fork: costed walk-forward `oos_r` observation channel** → none exists today, deliberately: the dissolved walkforward/mc sugar binds an empty cost list unconditionally, so no cost-bearing walk-forward summary can be invoked. The `oos_r`/deflation sites' net basis is therefore covered by the compile-forced single-conduit construction plus their uncosted exact-float pins staying green (bit-exact degeneracy), and the spec's testing section states this instead of prescribing an unimplementable assertion. Making the sugar cost-bearing is recorded as a non-goal (verbs stay cost-less sugar; costed research goes through campaign documents).
Author
Collaborator

Re-attestation: the testing-channel amendments recorded in issues/259#issuecomment-3530 were re-run through the grounding gate on the final spec bytes — PASS (9 ratified assumption clusters, incl. the three new ones: sugar binds an empty cost list; the synthetic archive supports the 14d/7d/7d roller hostlessly; the uncosted exact-float oos_r pins exist and are green). The signature of issues/259#issuecomment-3529 stands on the amended spec.

Re-attestation: the testing-channel amendments recorded in `issues/259#issuecomment-3530` were re-run through the grounding gate on the final spec bytes — PASS (9 ratified assumption clusters, incl. the three new ones: sugar binds an empty cost list; the synthetic archive supports the 14d/7d/7d roller hostlessly; the uncosted exact-float oos_r pins exist and are green). The signature of `issues/259#issuecomment-3529` stands on the amended spec.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Brummel/Aura#259