Files
Aura/crates/aura-ingest/examples/ger40_breakout_compare.rs
T
Brummel 7e4b91ab5f feat(0074): source real-path pip from the geometry sidecar; drop the authored floor
The data-server now ships per-symbol geometry sidecars, so aura no longer
hard-codes instrument geometry. A consumption grep showed production reads
exactly one `InstrumentSpec` field — `pip_size` — at the real-data path; the
other eight (incl. `instrument_id`) were constructed but never read.

- aura-cli resolves the real-path pip from the recorded sidecar
  (`instrument_geometry` -> `InstrumentGeometry.pip_size`), refusing (exit 2)
  on absent geometry. The authored table no longer gates: any symbol with a
  sidecar + bars now runs (new test: USDJPY, never vetted, resolves its JPY
  pip 0.01 from the sidecar).
- Removed the redundant authored floor: `InstrumentSpec`, `instrument_spec`,
  `VETTED_SYMBOLS`, and the table-only tests. The `InstrumentGeometry` seam
  (the surviving pip source) and its nameability guard are kept.
- `instrument_id` (the "find out"): no production consumer. The position-event
  table's `instrument_id` is a decoupled caller parameter; the engine never
  imports an instrument spec. Dropped with the struct.
- The example `pip_size_of` is re-sourced to the sidecar; the pure-structural
  blueprint tests use a literal pip to stay archive-independent.

Speculative deploy-grade fields and the #124 override/floor tiers are deferred
to the Stage-2 broker that will consume them, read from the sidecar geometry
then. Ledger (C8/C15/#22/#106) updated; #124 collapses to "recorded sidecar
geometry -> refuse" in the meantime.

Verified: cargo test --workspace (all green), clippy -D warnings clean, cargo
doc clean, with the local archive present so the sidecar paths run.

refs #124
2026-06-25 19:06:12 +02:00

171 lines
6.6 KiB
Rust

//! Runnable World-family demo: **`compare`** the session-breakout `Composite`
//! blueprint across two structural axes (C11/C20 experiment matrix),
//! on REAL data, with NO re-authoring:
//!
//! 1. **Instrument** — GER40 vs FRA40 (both `pip_size = 1.0`, index points), the
//! SAME blueprint bootstrapped at the same `{entry=3, exit=5}` point over each
//! symbol. The pip honesty is by construction (both quote in index points; the
//! pip is sourced per cell from the recorded geometry sidecar — #22
//! shipped).
//! 2. **Bar period** — a 15m blueprint vs a 30m blueprint. The bar period is a
//! STRUCTURAL axis (C34): `ger40_breakout_blueprint` is instantiated TWICE,
//! at 15 and at 30, each a *different strategy* (the period is bound at
//! construction, locking Resample and Session equal — it is NOT a sweep param).
//!
//! A "comparison" here is a plain Rust loop over the matrix (C20): one blueprint
//! per matrix cell, each bootstrapped + run + summarized, the reports tabulated.
//!
//! Run:
//! ```text
//! cargo run -p aura-ingest --example ger40_breakout_compare
//! ```
//! Prints both comparison tables. Skips a row cleanly where a symbol is absent.
use std::sync::Arc;
use aura_core::{Cell, Scalar, Timestamp};
use aura_engine::{summarize, RunMetrics};
use chrono_tz::Europe::Berlin;
use aura_ingest::{default_data_server, open_ohlc, DataServer, DEFAULT_DATA_PATH};
#[path = "shared/breakout_real.rs"]
mod breakout_real;
use breakout_real::*;
// The baseline tuning point both axes hold fixed (so only the structural axis
// varies): entry bar 3, exit bar 5 — the shipped baseline.
const ENTRY_BAR: i64 = 3;
const EXIT_BAR: i64 = 5;
// GER40 and FRA40 both quote in index points, so pip_size = 1.0 for both — the
// only reason a cross-instrument pip comparison is honest here. The pip is sourced
// per cell from the recorded geometry sidecar (#22 shipped), not a
// literal carried here. (symbol, human note)
const INSTRUMENTS: &[(&str, &str)] = &[("GER40", "index point"), ("FRA40", "index point")];
/// Bootstrap the blueprint (at `bar_period`) at `{entry=3, exit=5}`, run it over
/// `[from, to]` (epoch-ns) of real `symbol` OHLC, and summarize — or `None` if the
/// symbol has no file overlapping the window. The `pip_size` is sourced per cell
/// from the recorded geometry sidecar (always 1.0 here; both
/// indices) and rides on the blueprint's baked SimBroker. Returns the report plus
/// the entry count (0→1 transitions of held).
fn run_cell(
server: &Arc<DataServer>,
symbol: &str,
bar_period: i64,
from: Timestamp,
to: Timestamp,
) -> Option<(RunMetrics, u32)> {
let pip_size = pip_size_of(symbol);
let (bp, taps) =
ger40_breakout_blueprint(pip_size, bar_period, SESSION_HOUR, SESSION_MINUTE, Berlin);
let point: Vec<Cell> = bp
.param_space()
.iter()
.map(|ps| match ps.name.as_str() {
"entry_bar.target" => Scalar::i64(ENTRY_BAR).cell(),
"exit_bar.target" => Scalar::i64(EXIT_BAR).cell(),
other => panic!("unexpected param slot {other}"),
})
.collect();
let mut h = bp.bootstrap_with_cells(&point).expect("point kind-checked");
let srcs = open_ohlc(server, symbol, from, to)?;
h.run(srcs);
drop(h);
let equity: Vec<(Timestamp, f64)> = taps
.equity
.try_iter()
.map(|(t, r)| (t, as_f64(&r[0])))
.collect();
let held: Vec<(Timestamp, f64)> = taps
.held
.try_iter()
.map(|(t, r)| (t, as_f64(&r[0])))
.collect();
// Count entries (0 -> 1 transitions of held).
let mut entries = 0u32;
let mut prev = 0.0_f64;
for (_, v) in &held {
if *v == 1.0 && prev == 0.0 {
entries += 1;
}
prev = *v;
}
Some((summarize(&equity, &held), entries))
}
fn main() {
let server = default_data_server();
if !server.has_symbol(SYMBOL) {
println!("skip: no local data at {DEFAULT_DATA_PATH} (symbol {SYMBOL} absent).");
return;
}
// Full year 2024 (the same UTC span, via the shared Timestamp helper).
let (from, _) = utc_month_window(2024, 1);
let (_, to) = utc_month_window(2024, 12);
println!("=== GER40 session-breakout — World `compare` (structural matrix) ===");
println!("window=2024 (UTC, full year), fixed tuning point entry={ENTRY_BAR}, exit={EXIT_BAR}\n");
// --- Axis 1: instrument (GER40 vs FRA40), 15m blueprint. -----------------
println!("--- axis 1: instrument (same 15m blueprint, GER40 vs FRA40) ---");
println!(
"{:<8} {:<14} {:>9} {:>11} {:>10} {:>7}",
"symbol", "pip-meaning", "sessions", "total_pips", "max_dd", "flips"
);
println!("{}", "-".repeat(62));
for &(symbol, note) in INSTRUMENTS {
if !server.has_symbol(symbol) {
println!("{symbol:<8} (no local data — skip)");
continue;
}
match run_cell(&server, symbol, BAR_MINUTES, from, to) {
Some((m, entries)) => println!(
"{symbol:<8} {note:<14} {entries:>9} {:>11.1} {:>10.1} {:>7}",
m.total_pips, m.max_drawdown, m.bias_sign_flips
),
None => println!("{symbol:<8} (no overlapping OHLC files — skip)"),
}
}
println!();
// --- Axis 2: bar period (15m vs 30m blueprint), GER40. -------------------
// The STRUCTURAL axis: ger40_breakout_blueprint instantiated at 15 AND at 30
// — two *different strategies* (the period binds Resample AND Session equal at
// construction; it is not a sweep param). C34 / C11.
println!("--- axis 2: bar period (GER40, 15m blueprint vs 30m blueprint) ---");
println!(
"{:<10} {:>9} {:>11} {:>10} {:>7}",
"bar-period", "sessions", "total_pips", "max_dd", "flips"
);
println!("{}", "-".repeat(52));
for &period in &[15_i64, 30] {
match run_cell(&server, SYMBOL, period, from, to) {
Some((m, entries)) => println!(
"{:<10} {entries:>9} {:>11.1} {:>10.1} {:>7}",
format!("{period}m"),
m.total_pips,
m.max_drawdown,
m.bias_sign_flips,
),
None => println!("{period}m (no data — skip)"),
}
}
println!("\nOK: one blueprint, two structural axes (instrument + bar period) compared");
println!(" with no re-authoring — the bar period is a construction arg (15m and 30m");
println!(" are different strategies, C34), the instrument a plain matrix loop (C20).");
}
fn as_f64(s: &Scalar) -> f64 {
match s {
Scalar::F64(v) => *v,
other => panic!("expected f64, got {other:?}"),
}
}