d5c4361a9702ae9add88f9630fa23aef8fc905bc
2 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
6b53c239dd |
feat(0083): CostNode trait + shared cost-record contract
Lift the duplicated cost-node skeleton — shared verbatim by ConstantCost and VolSlippageCost and locked by convention against CostSum — into one abstraction: - A new aura-std/src/cost.rs owns the cost-record contract (COST_WIDTH, COST_FIELD_NAMES, GEOMETRY_WIDTH), the CostNode factor trait (one hook: cost_numerator, in price units), the generic CostRunner<F> adapter that holds the shared state (cum, out) and the co-temporality skeleton (geometry gating, numerator/latched R-normalization, closed/open charge, 3-field emit), and a cost_node_builder schema assembler. - ConstantCost and VolSlippageCost become thin CostNode factors; their new() returns CostRunner<Self>, so every existing call site and unit test binds transparently and stays green verbatim. - CostSum and main.rs drop their local triple consts for the shared COST_FIELD_NAMES — the cycle-2 audit-flagged by-convention 3-field lockstep is now a structural single-source contract (the four copies of the triple collapse to one). main.rs also reads COST_WIDTH in place of the literal slot stride. Behaviour-preserving: the builders emit unchanged schemas (same port names), so the wiring, the net_r_equity seam, and summarize_r are untouched; the numerator/latched token form is preserved verbatim (IEEE-754 byte-identity). The existing suite is the regression net — all green: the per-node unit tests pass verbatim (0.5/1.5, 0.375/1.375), the composition E2E exact, the C18 no-cost golden byte-identical. Two new CLI characterization goldens pin the exact net_expectancy_r of the flat and composed cost paths (the prior tests only asserted net < gross, which a numerator drift would pass silently). New cost.rs runner/contract tests + the HalfSpreadCost author doctest cover the new surface. Deviation from the plan: CostNode::name() was dropped (the plan over-specified it) — it is dead surface, nothing consumes it (CostRunner forwards label(); cost_node_builder takes the name as an explicit arg). Removed from the trait, both impls, the doctest, and the test stubs; build + suite + clippy green. Verified: cargo build --workspace --all-targets clean; cargo test --workspace 0 failures; cargo clippy --workspace --all-targets -- -D warnings clean; doctest green. refs #148 |
||
|
|
7f3756a395 |
feat(0082): cost-graph composition — VolSlippageCost + CostSum net-R aggregate
Cycle 2 of the "Cost-model graph (in R)" milestone (#148): the milestone's real architectural claim — the cost graph composes. Two cost nodes now sum into one net-R curve while summarize_r and the net_r_equity tap stay structurally unchanged. - VolSlippageCost (aura-std): a second, STATE-DEPENDENT cost node; per-trade charge = slip_vol_mult * volatility / |entry-stop|, in R. The vol is an independent short-horizon realized range (SLIP_VOL_LENGTH=5, distinct from the stop's EWMA-3) — scaling slippage by the stop's own vol would collapse cost-in-R to a constant (indistinguishable from ConstantCost). - CostSum (aura-std): the cost-graph OUTPUT node — sums N cost nodes' 3-field cost-in-R records per-field into one aggregate. summarize_r and net_r_equity read the aggregate (one home for cost; n=1 is the identity, so the cost path is uniform). A future CostNode trait (deferred) will unify the cost-triple the two producer nodes currently restate by-convention. - Run path: --cost-per-trade and --slip-vol-mult combine, their costs summing into the net-R curve; a hoisted vol proxy (RollingMax-RollingMin) keeps the single feed. Run-path-scoped; sweep/walkforward/mc pass None. Co-temporality contract (the load-bearing design decision; corrected from the signed spec after the implement-loop correctly BLOCKED Task 3 on it). summarize_r positional-joins cost[i] <-> record[i], so the cost stream must be co-temporal 1:1 with the PM record. A cost node is therefore gated ONLY by the PM geometry (closed/open/entry/stop); a not-yet-warm state input (the vol proxy warms later than PM) contributes 0 cost that cycle rather than withholding and desyncing the stream. This makes co-temporality structural + warmup-independent, preserves the C18 golden, and generalizes to any future cost factor. The rejected alternative (a key-join in summarize_r) would have moved the golden and pushed cost-graph logic into the post-run fold. Recorded on #148. Tests: VolSlippageCost + CostSum unit sets (incl. the co-temporal-zero-during- warmup case); the CLI composition run (both flags -> net_both < net_flat, net_r_equity persisted); node-level EXACT additive composition (net_both == net_flat + net_vol - gross over the real nodes), the aggregate net_r_equity == post-run net total, and CostSum(1) identity. Full workspace suite green; clippy -D warnings clean; the no-cost C18 golden byte-identical (the regression floor). Deferred (later cycles of this milestone): the general CostNode trait + cost-graph composite-builder (now justified by two concrete nodes), the conviction-weighting R-aggregation axis, and cost on the reduce-mode sweep path. Spec + plan amended to the corrected contract; both are cycle ephemera (git rm at cycle close). refs #148 |