fix(cli): thread the resolved pip into wrap_r so real-data runs hit the graph broker
wrap_r hardwired SimBroker::builder(SYNTHETIC_PIP_SIZE); the resolved geometry-sidecar pip reached only the manifest broker label, so every real-data run computed total_pips/max_drawdown at 0.0001 regardless of instrument (GER40 pip=1: inflated 10^4) while the label claimed the real pip. wrap_r now takes pip_size. Real-pip call sites pass the resolved pip: run_signal_r (resolve_run_data reordered before the wrap), run_blueprint_member, and the campaign trace re-run in persist_campaign_traces (instrument_geometry lookup mirroring the run_member refusal — required so the C1 drift alarm compares re-run and nominee at the same pip). Probe-only call sites (param-space and axis probes; metrics discarded) keep SYNTHETIC_PIP_SIZE explicitly. The two golden stitched_total_pips pins in cli_run.rs rescaled by exactly the 10^4 bug factor while n_trades/expectancy_r stayed byte-identical — confirming R metrics were never pip-contaminated. Alternative rejected: dropping pip-denominated metrics from real-data reports — the manifest already stamps the resolved pip, so running the graph at it restores label truthfulness without shrinking the report. Verified: full workspace suite green (0 failed incl. the real-data e2e suite), clippy -D warnings clean. closes #232
This commit is contained in:
@@ -735,6 +735,17 @@ fn persist_campaign_traces(
|
||||
let space = crate::blueprint_axis_probe(blueprint_json, env).param_space();
|
||||
let point = crate::point_from_params(&space, &nominee_report.manifest.params);
|
||||
let (from, to) = nominee_report.manifest.window;
|
||||
// Same resolved pip the nominee ran at (`CliMemberRunner::run_member`'s
|
||||
// `geo.pip_size`), else the C1 drift-alarm equality below would trip
|
||||
// spuriously on a re-run computed at a different (default) pip.
|
||||
let geo = instrument_geometry(server, &cell_rec.instrument).ok_or_else(|| {
|
||||
format!(
|
||||
"no recorded geometry for symbol '{}' at {} — refusing to re-run a \
|
||||
real instrument with a guessed pip",
|
||||
cell_rec.instrument,
|
||||
env.data_path()
|
||||
)
|
||||
})?;
|
||||
let no_data = || {
|
||||
format!(
|
||||
"no data for instrument {} in the nominee window [{}, {}] (epoch-ns)",
|
||||
@@ -764,7 +775,7 @@ fn persist_campaign_traces(
|
||||
let (tx_ex, rx_ex) = mpsc::channel();
|
||||
let (tx_r, rx_r) = mpsc::channel();
|
||||
let (tx_req, rx_req) = mpsc::channel();
|
||||
let mut h = crate::wrap_r(signal, tx_eq, tx_ex, tx_r, tx_req, stop, false)
|
||||
let mut h = crate::wrap_r(signal, tx_eq, tx_ex, tx_r, tx_req, stop, false, geo.pip_size)
|
||||
.bootstrap_with_cells(&point)
|
||||
.expect("the nominee's point re-bootstraps (it already ran this realization)");
|
||||
let sources: Vec<Box<dyn aura_engine::Source>> = vec![Box::new(source)];
|
||||
|
||||
@@ -1093,7 +1093,7 @@ fn reproduce_family_in(
|
||||
let (tx_r, _) = mpsc::channel();
|
||||
let (tx_req, _) = mpsc::channel();
|
||||
let space =
|
||||
wrap_r(reload(), tx_eq, tx_ex, tx_r, tx_req, StopRule::Vol { length: R_SMA_STOP_LENGTH, k: R_SMA_STOP_K }, true).param_space();
|
||||
wrap_r(reload(), tx_eq, tx_ex, tx_r, tx_req, StopRule::Vol { length: R_SMA_STOP_LENGTH, k: R_SMA_STOP_K }, true, SYNTHETIC_PIP_SIZE).param_space();
|
||||
let point = point_from_params(&space, &stored.manifest.params);
|
||||
// A MonteCarlo member carries no tuning params (the params-join is empty), so its
|
||||
// reproduce line would print a BLANK member label; the seed IS its realization
|
||||
@@ -1261,12 +1261,13 @@ fn wrap_r(
|
||||
tx_req: mpsc::Sender<(Timestamp, Vec<Scalar>)>,
|
||||
stop: StopRule,
|
||||
reduce: bool,
|
||||
pip_size: f64,
|
||||
) -> Composite {
|
||||
let mut g = GraphBuilder::new("r_sma");
|
||||
// SMA-cross signal → Bias, nested as a serializable `price`→`bias` leg.
|
||||
let sig = g.add(BlueprintNode::Composite(signal));
|
||||
// pip branch (verbatim from the retired `sample_blueprint_with_sinks`, #159).
|
||||
let broker = g.add(SimBroker::builder(SYNTHETIC_PIP_SIZE));
|
||||
let broker = g.add(SimBroker::builder(pip_size));
|
||||
// R branch: bias + price → RiskExecutor(vol_stop) → dense R-record. The stop is a
|
||||
// fixed `StopRule` — the pinned default constants, or an arbitrary per-regime rule
|
||||
// the caller resolved.
|
||||
@@ -1370,12 +1371,12 @@ fn run_signal_r(
|
||||
// The req tap (r_equity recorder) is wired but not persisted on this path; keep the
|
||||
// receiver alive so the sink's sends do not fail, but do not drain it.
|
||||
let (tx_req, _rx_req) = mpsc::channel();
|
||||
let wrapped = wrap_r(signal, tx_eq, tx_ex, tx_r, tx_req, StopRule::Vol { length: R_SMA_STOP_LENGTH, k: R_SMA_STOP_K }, false);
|
||||
let (sources, window, pip_size) = resolve_run_data(&data, env);
|
||||
let wrapped = wrap_r(signal, tx_eq, tx_ex, tx_r, tx_req, StopRule::Vol { length: R_SMA_STOP_LENGTH, k: R_SMA_STOP_K }, false, pip_size);
|
||||
let flat = wrapped
|
||||
.compile_with_params(params)
|
||||
.expect("signal binds + wraps to a valid harness");
|
||||
let mut h = Harness::bootstrap(flat).expect("valid r-sma harness");
|
||||
let (sources, window, pip_size) = resolve_run_data(&data, env);
|
||||
h.run(sources);
|
||||
let eq_rows: Vec<(Timestamp, Vec<Scalar>)> = rx_eq.try_iter().collect();
|
||||
let ex_rows: Vec<(Timestamp, Vec<Scalar>)> = rx_ex.try_iter().collect();
|
||||
@@ -1414,7 +1415,7 @@ fn run_blueprint_member(
|
||||
let (tx_ex, rx_ex) = mpsc::channel();
|
||||
let (tx_r, rx_r) = mpsc::channel();
|
||||
let (tx_req, _rx_req) = mpsc::channel();
|
||||
let mut h = wrap_r(signal, tx_eq, tx_ex, tx_r, tx_req, stop, true)
|
||||
let mut h = wrap_r(signal, tx_eq, tx_ex, tx_r, tx_req, stop, true, pip)
|
||||
.bootstrap_with_cells(point)
|
||||
.expect("member bootstraps (point kind-checked against param_space)");
|
||||
h.run(sources);
|
||||
@@ -1461,7 +1462,7 @@ fn blueprint_axis_probe(doc: &str, env: &project::Env) -> Composite {
|
||||
let (tx_ex, _) = mpsc::channel();
|
||||
let (tx_r, _) = mpsc::channel();
|
||||
let (tx_req, _) = mpsc::channel();
|
||||
wrap_r(signal, tx_eq, tx_ex, tx_r, tx_req, StopRule::Vol { length: R_SMA_STOP_LENGTH, k: R_SMA_STOP_K }, true)
|
||||
wrap_r(signal, tx_eq, tx_ex, tx_r, tx_req, StopRule::Vol { length: R_SMA_STOP_LENGTH, k: R_SMA_STOP_K }, true, SYNTHETIC_PIP_SIZE)
|
||||
}
|
||||
|
||||
/// `aura sweep <blueprint.json> --list-axes`: one `<name>:<kind>` line per open
|
||||
@@ -3386,6 +3387,7 @@ mod tests {
|
||||
tx_req,
|
||||
StopRule::Vol { length: 3, k: 2.0 },
|
||||
false,
|
||||
SYNTHETIC_PIP_SIZE,
|
||||
)
|
||||
.compile_with_params(&[])
|
||||
.expect("r-meanrev signal wraps to a valid harness");
|
||||
|
||||
@@ -1952,7 +1952,7 @@ fn walkforward_real_e2e_pins_the_exact_current_grade() {
|
||||
assert_eq!(wf["windows"].as_u64(), Some(9), "window count: {grade_line}");
|
||||
// EXACT floats -- the byte-identity anchor the dissolution must preserve.
|
||||
// stitched_total_pips is retained only if the campaign runner keeps the OOS curve.
|
||||
assert_eq!(wf["stitched_total_pips"].as_f64(), Some(-10398606.666650848), "stitched OOS pips: {grade_line}");
|
||||
assert_eq!(wf["stitched_total_pips"].as_f64(), Some(-1039.8606666650755), "stitched OOS pips: {grade_line}");
|
||||
let r = &wf["oos_r"];
|
||||
assert_eq!(r["n_trades"].as_u64(), Some(20681), "pooled OOS trade count: {grade_line}");
|
||||
assert_eq!(r["expectancy_r"].as_f64(), Some(-0.002397100685333715), "pooled OOS expectancy R: {grade_line}");
|
||||
@@ -2119,7 +2119,7 @@ fn walkforward_real_e2e_pins_the_exact_current_plateau_grade() {
|
||||
let wf = &v["walkforward"];
|
||||
assert_eq!(wf["windows"].as_u64(), Some(9), "window count: {grade_line}");
|
||||
// EXACT floats -- the byte-identity anchor a plateau-vs-argmax regression must preserve.
|
||||
assert_eq!(wf["stitched_total_pips"].as_f64(), Some(-9683776.66663749), "stitched OOS pips: {grade_line}");
|
||||
assert_eq!(wf["stitched_total_pips"].as_f64(), Some(-968.3776666637464), "stitched OOS pips: {grade_line}");
|
||||
let r = &wf["oos_r"];
|
||||
assert_eq!(r["n_trades"].as_u64(), Some(20667), "pooled OOS trade count: {grade_line}");
|
||||
assert_eq!(r["expectancy_r"].as_f64(), Some(0.007635120926372627), "pooled OOS expectancy R: {grade_line}");
|
||||
|
||||
Reference in New Issue
Block a user