Real-data source path for family runs (aura sweep|walkforward --real) #106
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?
Design record (specify, in-context entry)
This issue seeds the real-data source path for family runs. The design was
settled in an in-context discussion (the family-trace demo for #104 over
synthetic data, then "interessant wäre das ganze auch noch mit echten Daten über
einen relevanten Zeitraum"); this records it. No prior tracker issue existed, so
this is the reference issue for the
/bossrun that implements it.Gap
aura run --real <SYMBOL>streams real M1 close bars from the local data-serverarchive through the #71
M1FieldSourceseam. The family builders do not:sweep_family,momentum_sweep_family, andwalkforward_family/sweep_over/run_oosare hardcoded to a syntheticVecSource(
showcase_prices/walkforward_prices,crates/aura-cli/src/main.rs:524-525, 600-601, 730-731, 768-769, 795-796). There is no--realpath for families, sothe C21 family surface can only ever show synthetic toy streams.
Goal
Opt-in
--real <SYMBOL> [--from <ms>] [--to <ms>]onaura sweepandaura walkforward, mirroringaura run --real: each family member runs over realM1 close bars instead of the synthetic stream. Without
--real, behaviour isbyte-unchanged.
Load-bearing forks resolved (derived; bold-decide stance)
Fork A — which family kinds get
--real→ sweep + walkforward; MCexcluded. Basis (derived):
mc_family(main.rs:868-871) varies, per seed,the realization of a synthetic price walk (
SyntheticSpec.source(seed)). Realdata has exactly one realization, so every seed-member would stream identical
bars → the MC axis is undefined over real data. A real MC needs a different
stochastic axis (block-bootstrap of the real returns) — its own design cycle.
sweep (param axis) and walk-forward (time axis) are both well-defined over real
data.
Fork B — how the real source is injected → a source-provider per member
closure, mirroring
run_sample_real'sopenclosure (main.rs:342). Eachmember / window builds a fresh
M1FieldSource(Sources are single-pass;parallel members each need their own); the
DataServerisArc-shared(thread-safe cache). The family builders take a source-provider parameter
instead of the hardcoded
VecSource::new(...). Engine untouched(
M1FieldSourcealready implsSource).Fork C — pip size → from
aura_ingest::instrument_spec(symbol), refused(stderr + exit 2) before any data access for an un-vetted symbol, mirroring
run_sample_real:323. The sim-optimal broker + manifest use the real pip, notSYNTHETIC_PIP_SIZE.Fork D — walk-forward IS/OOS sizing over real time → the
WindowRolleralready works in epoch-unit timestamps (
walkforward.rs:18-21), which arenanoseconds for real M1;
M1FieldSource::open_windowtakesTimestamp, so thewindowed source binds directly to
WindowBounds. The real path uses fixedsensible calendar-time defaults for IS / OOS / step (the spec fixes the exact
values); no new CLI flags this iteration (flags are a later refinement).
Engine untouched — only the CLI-side default sizes change from bar-index
(synthetic) to calendar time.
Fork E — parser grammar →
aura sweep [--strategy <sma|momentum>] [--real <SYMBOL> [--from <ms>] [--to <ms>]] [--trace <n>]andaura walkforward [--real <SYMBOL> [--from <ms>] [--to <ms>]] [--name | --trace <n>], mirroringparse_real_args.--realis exclusive with the synthetic default; without it,byte-unchanged.
Out of scope (deferred)
Invariants
C1 (determinism — same real window streamed twice is bit-identical, already true
for
run --real), C2 (no look-ahead —WindowRollerenforcesoos.0 > is.1),C6 (record-then-replay — real bars are a pre-recorded archive), C7 (SoA), C9
(engine/project — real data is the data-server's job, engine untouched), C18/C21
(families). All upheld; this adds a source-injection seam at the CLI family
boundary and changes no engine computation.
Plan recon — two derived sub-forks (specify→planner)
Plan-recon (read-only) surfaced two mechanics the spec left to taste; both
derivable, decided here under the bold stance.
Fork F — where the walk-forward IS/OOS/step sizes live → a 5th provider
method
DataSource::wf_window_sizes(&self) -> (i64, i64, i64). Synthetic returns(24, 12, 12)(bar-index, over the 60-bar synthetic span, byte-unchanged); Realreturns
(WF_REAL_IS_NS, WF_REAL_OOS_NS, WF_REAL_STEP_NS)=(90d, 30d, 30d)inns. Basis (derived): the
WindowRolleralready takes sizes in the stream'sepoch-unit; the two sizing regimes (bar-index synthetic vs calendar-ns real)
differ only in the numbers, so one provider method keeps both at a single site,
exactly beside
full_window()which the same provider already supplies.Fork G — where build-or-refuse lives → the parser stays pure and yields a
DataChoice(unit-testable:--real SYM, window pairs, rejects). Thebuild-or-refuse (un-vetted symbol → refuse; symbol absent from archive → refuse)
mirrors
run_sample_real's inlinestderr + exit(2)pattern (main.rs:323-341)in a
DataSourceconstructor, E2E-tested via an integration test like theexisting
run_real_unspecced_symbol_refuses_with_exit_2. Basis (derived):consistency with the one real-data path that already ships; a process
exit(2)is not unit-testable without a process spawn, which the integration tests do
anyway, so the refuse path is covered E2E rather than left untested.
Authoritative call-site set for the signature changes is
cargo build -p aura-cli --all-targets(the compiler enumerates the 6#[cfg(test)]callers a prod-only grep misses), not a hand grep. Engine / ingest/ registry remain untouched. Spec 0060 committed boss-signed (grounding-check
PASS, 8/8 assumptions ratified); plan 0060 next.
Shipped (cycle 0060) — closing
aura sweep|walkforward --real <SYMBOL> [--from <ms>] [--to <ms>]now streams realM1 close bars per family member; opt-in, synthetic path byte-unchanged. Verified
end-to-end over real EURUSD:
sweep --real→ 4 members;walkforward --realover2024 → 9 rolling OOS windows; un-vetted symbol /
mc --real/ window-without-realeach exit 2.
Commits:
9637730(spec, boss-signed — grounding-check PASS 8/8) ·bd5a08d(plan) ·
cf10217(DataSource provider + DRY-extracted real-data helpers) ·2a6ca47(pip-param +&DataSourcewiring) ·8e5d14b(--realparser + gatedreal tests) ·
607e548(audit close, ledger amendment).Two corrections surfaced during implementation, both fixed forward:
wf_full_span(a design gap I missed in the plan): walk-forward is awindowed consumer whose span comes from the 60-bar
walkforward_prices, notfull_window()'s 18-bar showcase span. AddedDataSource::wf_full_span(); theimplementer correctly bounced rather than silently substitute.
RealWindowGrammar(an improvement): the--real/--from/--togrammar isshared between the two parsers (strict flag-repeat / empty-symbol rejection
mirroring
parse_real_args) instead of duplicated.Architect: cycle contract-clean (C1/C2/C6/C9/C10/C12 upheld, engine/ingest/registry
untouched). The one drift was a ledger gap, closed in
607e548(C22 real-datafamily amendment). Carry-on [low]: the real
oos{ns}key has no explicituniqueness pin beyond
starts_with("oos")— acceptable, covered in practice.Deferred to their own cycles (recorded here as the forward queue): CLI flags for
walk-forward IS/OOS/step sizing (fixed 90d/30d/30d defaults this cycle); MC over
real data (needs a bootstrap-resampling axis); the family-comparison view.