SimBroker pip value is a global constructor literal, not per-asset #22
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?
Surfaced while running the walking-skeleton pipeline (SMA-cross -> Exposure -> SimBroker) over the full history of all 28 data-server assets as a sequential consumer loop.
Observation
SimBroker::new(pip_size)takes a single globalpip_size(0.0001in the sample/CLI harness). That value is correct only for 5-decimal FX. Over non-FX assets the synthetic pip equity becomes nonsensical:Engine mechanics are fine (deterministic, finite, 92.8M bars in ~75s); only the unit is wrong off-FX. A cross-asset signal-quality comparison is meaningless until the pip/point value is per-instrument.
Direction (not prescriptive)
The pip/point value (and tick size) is per-instrument metadata and belongs beside the hot path (C4 non-scalars-as-metadata), keyed by instrument, not a single
f64baked into the broker node at construction. Most relevant to the realistic-broker layer (C10), but the sim-optimal broker already needs it to make multi-asset pip equity comparable.Found via a throwaway multi-asset probe (since discarded); no code change in tree.
Now reproducible in-tree (no throwaway probe needed)
Since
aura run --real <SYMBOL> [--from <ms>] [--to <ms>]landed (0ce843b, pushed) the off-FX pip-unit symptom is reproducible straight from the shipped CLI — the sample harness still bakesSimBroker::new(0.0001), so any non-FX instrument streamed through it shows the wrong unit.Fresh numbers, same SMA-cross sample, calendar year 2021 (release build, ~12 backtests in <2s):
Repro:
Edit surface a fix touches: the constructor literal
SimBroker::new(pip_size)(crates/aura-std/src/sim_broker.rs:47), and the0.0001baked at the two CLI call sites (sample_harness()and thesim_optimal_manifestbroker label incrates/aura-cli/src/main.rs). The body's direction still holds: pip/point is per-instrument metadata keyed by instrument, not a constructorf64— most naturally sourced from the per-instrumentAura.tomlmetadata layer.Deferred — parked here for when the per-asset pip / instrument-metadata work is picked up.
Confirmed by the GER40 research deep-dive fieldtest (docs/specs/fieldtest-research-breakout-deepdive.md): the gap bites at the first real cross-asset comparison. GER40 (+203.4) vs FRA40 (+83.7) over 2024 is honest ONLY because the researcher hand-supplied matching pip_size=1.0 for both index instruments — there is no registry, and nothing flags or prevents comparing GER40 index-pips against EURUSD fx-pips (0.0001). The sim-optimal broker's cross-asset yardstick is currently honest by researcher discipline, not by construction.
Design reconciliation (specify, in-context entry)
Spec:
0054-per-instrument-pip. The forks below are still listed open on thisissue (the body frames the direction as "not prescriptive"); they were resolved
in the in-context design discussion, not by the orchestrator.
Fork: where per-instrument pip lives → a typed
InstrumentSpec { pip_size }in
aura-std, looked up bysymbolviaaura_ingest::instrument_spec(symbol)at the ingestion/source edge (where the symbol still exists). The engine stays
domain-free: no
instrument_idonCtx, pip never streamed (C4/C7/C15 — pip isnon-scalar reference metadata beside the hot path). NOT via
Aura.toml(aRust-authored table, which the later
Aura.tomlschema can subsume). Explicitlyportfolio-agnostic: only keys pip per-instrument; introduces no
instrument_idflow, no basket/aggregation node, no position-event table (that is the carved-out
realistic-execution milestone).
SimBrokeris and stays by-constructionsingle-instrument (slot0 exposure + slot1 price → one equity).
Provenance: resolved by the user in the interactive session on 2026-06-18 — chose
"B-core-with-A-home" (typed spec + source-edge home) over the bare-f64 option,
and confirmed the portfolio-agnostic scope boundary verbatim ("ja, bleibt stabil")
after a multi-instrument clarification ("two instruments ⇒ two brokers + a
not-yet-built aggregator, out of scope here").
Fork: manifest/label scope → minimal: the sim-optimal broker label
(
RunManifest.broker) carries the real per-instrument pip on the real-datapath, so the C18 manifest stays a faithful reproduction recipe; NO separate
instrument_idmanifest axis (deferred to later registry-instrument-axis work).Provenance: user accepted the recommended "minimal in scope" for Fork 2 in the
same session, with no objection.
Design reconciliation — correction (specify, in-context entry)
Correcting the crate-home stated in my earlier reconciliation comment. The typed
InstrumentSpeclives inaura-ingest(the ingestion / source edge), NOTaura-std. The earlier comment's "in aura-std" was a transcription slip; theagreed decision was the source-edge home ("A-home"), which is the aura-ingest
crate.
SimBroker(aura-std) does not reference the type; the consumers areaura-cli and the aura-ingest examples, and the dependency direction
(
aura-cli → aura-ingest → aura-std, and aura-std does NOT depend on aura-ingest)makes aura-ingest the only home consistent with "source edge".
InstrumentSpec→aura-ingest.Provenance: confirmed by the user in the interactive session on 2026-06-18
("ja" to "Bestätigst du
aura-ingestals Home?", after the spec-skepticscope-fork lens flagged the comment-vs-spec mismatch).
The substantive resolution (typed spec, source edge, keyed by
symbol, enginedomain-free, not
Aura.toml, portfolio-agnostic) is unchanged from the priorcomment.
Design decision — #22 metadata channel & scope (user-directed, 2026-06-18)
Root cause (user): the data-server symbol stream carries only price bars — NO
instrument metadata (pip size). That absence is the bug. The fix is a channel to
specify per-instrument pip metadata, since the data does not carry it.
Decisions (user-directed this session — "Das Problem ist doch, dass die Symboldaten
keine Metadaten (wie Pipsize) mitbringen. DAS ist der Bug. Also sieh zu, dass man die
IRGENDWIE angeben kann und werd mal fertig!"):
InstrumentSpec { pip_size }+ anaura_ingest::instrument_spec(symbol)lookup — a Rust-authored vetted table(NOT
Aura.toml). Home:aura-ingest(source edge; user-confirmed earlier).aura run --realpath (whichbakes
0.0001for every symbol) + the lookup + the refusal. The runnable-examplepip centralization (GER40/FRA40 already bake the correct
1.0— not buggy) isDEFERRED to a follow-up
ideaissue.REFUSES (exit 2) rather than guessing a pip — honest by construction, consistent
with "you must be able to specify it".
1.0(index points); 5-decimal FX majors =0.0001(note: JPY pairs are 0.01, not 0.0001 — seed only vetted values). Extend as vetted.
These resolve the spec-skeptic round-2 scope-fork (refusal provenance) and criterion
(the CLI example —
--real GER40=1.0 vs--real EURUSD=0.0001 vs--real BTCUSD→refuse — is the cross-asset evidence) blocks. The deferred example refactor removes
the ambiguity/plan-readiness blocks from this cycle's scope.
Landed in
26bec6d(feat: per-instrument pip metadata channel) + cycle-close77358d2(C10/C15 realization note). InstrumentSpec + instrument_spec lookup in aura-ingest; CLI aura run --real threads the looked-up pip and refuses un-specced symbols (exit 2). SimBroker unchanged. Audit clean, full suite green. Runnable-example centralization deferred to #98.Brummel referenced this issue2026-06-22 16:30:50 +02:00