//! Gated integration test: the GER40 session-breakout `Composite` blueprint is //! driven by the World *orchestration families* — `sweep` and //! `walk_forward` — on REAL GER40 M1 bars, with NO re-authoring of the strategy. //! This is the milestone-completing executable proof that the #94 friction is //! gone: the same `ger40_breakout_blueprint` the single backtest bootstraps is //! consumed verbatim by the World machinery. //! //! Mirrors `tests/ger40_breakout_real.rs` / `real_bars.rs`: skips with a note //! where the local Pepperstone archive is absent, so `cargo test --workspace` //! stays green anywhere; exercises the real path where the files exist. //! //! Two properties, both over the shipped blueprint: //! - `sweep` returns a ranked grid over the two named params //! (`entry_bar.target` × `exit_bar.target`), each point's `total_pips` finite — //! the `param_space()` is driven directly. //! - `walk_forward` returns a NON-EMPTY roll, every window carrying a NON-EMPTY //! `chosen_params` (the executable #97 non-degenerate proof: a real, non-empty //! space is optimized per window — contrast the fieldtest's empty-space //! degenerate roll over the raw FlatGraph). use std::sync::Arc; use aura_core::{Cell, Scalar, Timestamp}; use aura_engine::{ sweep, summarize, walk_forward, GridSpace, RollMode, RunManifest, RunReport, WindowBounds, WindowRoller, WindowRun, }; use chrono::TimeZone; use chrono_tz::Europe::Berlin; use data_server::{DataServer, DEFAULT_DATA_PATH}; #[path = "../examples/shared/breakout_real.rs"] mod breakout_real; use breakout_real::*; /// ns → ms: the shipped `open_ohlc_sources` opens by Unix-ms, but the World /// `WindowBounds` are epoch-ns. `aura-ingest` exports only the forward direction /// (`unix_ms_to_epoch_ns`), so the inverse is a local hand-divide (#80, filed). fn ns_to_ms(ts: Timestamp) -> i64 { ts.0 / 1_000_000 } /// Bootstrap the shipped blueprint at one `{entry_bar, exit_bar}` point, run it /// over `[from_ms, to_ms]` of real GER40 OHLC, and fold the recorded equity/held /// taps into a `RunReport` (`summarize` over the drained channels — exactly as /// the SMA-cross sweep fixture and the fieldtest's `run_point` do). A fresh /// blueprint per call (fresh nodes + channels) keeps the disjoint sweep points /// independent (C1). fn run_point(server: &Arc, point: &[Cell], from_ms: i64, to_ms: i64) -> RunReport { let (bp, taps) = ger40_breakout_blueprint(BAR_MINUTES, SESSION_HOUR, SESSION_MINUTE, Berlin); let mut h = bp .bootstrap_with_cells(point) .expect("sweep point kind-checked against param_space"); let sources = open_ohlc_sources(server, from_ms, to_ms).expect("window overlaps GER40 data"); h.run(sources); drop(h); let equity: Vec<(Timestamp, f64)> = taps.equity.try_iter().collect::>() .iter() .map(|(t, r)| (*t, scalar_f64(&r[0]))) .collect(); let exposure: Vec<(Timestamp, f64)> = taps.held.try_iter().collect::>() .iter() .map(|(t, r)| (*t, scalar_f64(&r[0]))) .collect(); RunReport { manifest: RunManifest { commit: "ger40-breakout-world".to_string(), params: vec![], window: ( aura_ingest::unix_ms_to_epoch_ns(from_ms), aura_ingest::unix_ms_to_epoch_ns(to_ms), ), seed: 0, broker: "sim-optimal(pip_size=1)".to_string(), }, metrics: summarize(&equity, &exposure), } } fn scalar_f64(s: &Scalar) -> f64 { match s { Scalar::F64(v) => *v, other => panic!("expected f64, got {other:?}"), } } /// Property: the World `sweep` family CONSUMES the shipped breakout blueprint /// over its two named params on real GER40 — it returns a full ranked grid (no /// re-authoring), and every grid point's `total_pips` is finite (a backtest /// actually ran at each point). The grid is built from the blueprint's /// `param_space()` directly, so the two `EqConst` targets are the swept axes. #[test] fn sweep_consumes_blueprint_over_named_params() { let server = Arc::new(DataServer::new(DEFAULT_DATA_PATH)); if !server.has_symbol(SYMBOL) { eprintln!("skip: no local data at {DEFAULT_DATA_PATH} (symbol {SYMBOL} absent)"); return; } let (from_ms, to_ms) = utc_month_window_ms(2024, 9); let space = ger40_breakout_blueprint(BAR_MINUTES, SESSION_HOUR, SESSION_MINUTE, Berlin) .0 .param_space(); // The grid is exactly over `param_space()`: entry ∈ {2,3,4}, exit ∈ {4,5,6}. let grid = GridSpace::new( &space, space .iter() .map(|ps| match ps.name.as_str() { "entry_bar.target" => vec![Scalar::i64(2), Scalar::i64(3), Scalar::i64(4)], "exit_bar.target" => vec![Scalar::i64(4), Scalar::i64(5), Scalar::i64(6)], other => panic!("unexpected param slot {other}"), }) .collect(), ) .expect("grid well-formed for the breakout param_space"); let server_for_closure = Arc::clone(&server); let family = sweep(&grid, |pt: &[Cell]| { run_point(&server_for_closure, pt, from_ms, to_ms) }); // A full 3×3 grid was enumerated over the two named params (no re-authoring). assert_eq!(family.points.len(), 9, "the 3×3 entry×exit grid must enumerate 9 points"); assert_eq!( family.space.iter().map(|p| p.name.as_str()).collect::>(), vec!["entry_bar.target", "exit_bar.target"], "the swept space is exactly the two genuine tuning knobs", ); // Every point's metrics are finite — a real backtest ran at each grid point. for (i, p) in family.points.iter().enumerate() { assert!( p.report.metrics.total_pips.is_finite(), "point {i} {:?} produced a non-finite total_pips", family.named_params(i), ); } // The best point (max total_pips) is finite — the ranked grid has a real head. let best = family .points .iter() .map(|p| p.report.metrics.total_pips) .fold(f64::NEG_INFINITY, f64::max); assert!(best.is_finite(), "the best grid point's total_pips must be finite"); } /// Property: the World `walk_forward` family CONSUMES the shipped breakout /// blueprint NON-DEGENERATELY (the executable #97 resolution). The roll over /// multi-year GER40 yields a NON-EMPTY set of windows, and EACH window carries a /// NON-EMPTY `chosen_params` — a real `{entry_bar, exit_bar}` point was selected /// by an in-sample sweep per window (contrast the fieldtest's empty-space roll /// over the raw FlatGraph, where `chosen_params == vec![]` everywhere). #[test] fn walk_forward_consumes_blueprint_non_degenerate() { let server = Arc::new(DataServer::new(DEFAULT_DATA_PATH)); if !server.has_symbol(SYMBOL) { eprintln!("skip: no local data at {DEFAULT_DATA_PATH} (symbol {SYMBOL} absent)"); return; } // A short 2-window roll over 2023..2024 keeps the gated test cheap while still // exercising the per-window in-sample optimize. is=6mo, oos=3mo, step=3mo. let day_ns: i64 = 86_400_000 * 1_000_000; let month_ns: i64 = 30 * day_ns; let origin = aura_ingest::unix_ms_to_epoch_ns( chrono::Utc.with_ymd_and_hms(2023, 1, 1, 0, 0, 0).unwrap().timestamp_millis(), ); let end = aura_ingest::unix_ms_to_epoch_ns( chrono::Utc.with_ymd_and_hms(2024, 6, 30, 23, 59, 59).unwrap().timestamp_millis(), ); let roller = WindowRoller::new( (origin, end), 6 * month_ns, 3 * month_ns, 3 * month_ns, RollMode::Rolling, ) .expect("span fits >= 1 window"); // The non-empty space the in-sample sweep optimizes over per window: the two // genuine tuning knobs. This is the #97 resolution — a real space, so the // chosen params are populated, never an empty degenerate vec. let space = ger40_breakout_blueprint(BAR_MINUTES, SESSION_HOUR, SESSION_MINUTE, Berlin) .0 .param_space(); let server_for_closure = Arc::clone(&server); let result = walk_forward(roller, space.clone(), move |w: WindowBounds| -> WindowRun { // In-sample optimize: a tiny entry×exit grid over the IS window, choose the // point with the best in-sample total_pips. The blueprint is consumed // directly via its param_space() — no re-authoring. let is_grid = GridSpace::new( &space, space .iter() .map(|ps| match ps.name.as_str() { "entry_bar.target" => vec![Scalar::i64(2), Scalar::i64(3)], "exit_bar.target" => vec![Scalar::i64(5), Scalar::i64(6)], other => panic!("unexpected param slot {other}"), }) .collect(), ) .expect("IS grid well-formed"); let (is_from, is_to) = (ns_to_ms(w.is.0), ns_to_ms(w.is.1)); let is_family = sweep(&is_grid, |pt: &[Cell]| { run_point(&server_for_closure, pt, is_from, is_to) }); let best = is_family .points .iter() .max_by(|a, b| { a.report .metrics .total_pips .partial_cmp(&b.report.metrics.total_pips) .unwrap_or(std::cmp::Ordering::Equal) }) .expect("the IS grid is non-empty"); let chosen = best.params.clone(); // Apply the chosen params on the OOS window. let (oos_from, oos_to) = (ns_to_ms(w.oos.0), ns_to_ms(w.oos.1)); let oos_report = run_point(&server_for_closure, &chosen, oos_from, oos_to); // Re-run once on OOS to capture the recorded equity segment for stitching. let (bp, taps) = ger40_breakout_blueprint(BAR_MINUTES, SESSION_HOUR, SESSION_MINUTE, Berlin); let mut h = bp.bootstrap_with_cells(&chosen).expect("chosen point kind-checked"); let sources = open_ohlc_sources(&server_for_closure, oos_from, oos_to) .expect("OOS window overlaps data"); h.run(sources); drop(h); let oos_equity: Vec<(Timestamp, f64)> = taps .equity .try_iter() .collect::>() .iter() .map(|(t, r)| (*t, scalar_f64(&r[0]))) .collect(); WindowRun { chosen_params: chosen, oos_equity, oos_report } }); // Non-degenerate: a non-empty roll, EACH window carrying a non-empty chosen // point (the #97 proof — a real space was optimized per window). assert!(!result.windows.is_empty(), "walk_forward must yield >= 1 window"); for (k, w) in result.windows.iter().enumerate() { assert!( !w.run.chosen_params.is_empty(), "window {k}: chosen_params must be NON-empty (the #97 non-degenerate proof)", ); assert_eq!( w.run.chosen_params.len(), 2, "window {k}: chosen_params spans the two-param space", ); assert!( w.run.oos_report.metrics.total_pips.is_finite(), "window {k}: OOS total_pips must be finite", ); } }