diff --git a/docs/authoring-guide.md b/docs/authoring-guide.md index 3a470cd..d6bf976 100644 --- a/docs/authoring-guide.md +++ b/docs/authoring-guide.md @@ -57,7 +57,12 @@ Every node type — std or project-local — is three things: until every input the node needs has fired at least once; this warm-up filter is what keeps a downstream consumer from ever observing a fabricated value, C8), and `label()` (a short, human-readable debug - string — not the type id used for serialization, see below). + string — not the type id used for serialization, see below). The input + window `ctx.f64_in(i)` hands those past values back **financial-style: + index 0 is the newest cycle, index `k` is `k` cycles back** — so a + `lookbacks()` of `vec![n]` makes `w[0]..=w[n-1]` the last `n` values, + newest first, and a lookback-spanning node (momentum, ATR, RSI) reads its + span as `w[0]` vs `w[length]`, never the other way round. 2. **A `PrimitiveBuilder` recipe.** A `builder()` constructor that pairs a `NodeSchema` (its input ports as `PortSpec`, its output fields as `FieldSpec`, and its bindable params as `ParamSpec`) with a **build @@ -453,6 +458,7 @@ open slot: kind (required, must be "campaign") open slot: name (required, string) open slot: data (required section: instruments + windows) open slot: risk (optional, list of stop regimes { vol: { length, k } }; absent = one default regime) +open slot: cost (optional, list of cost models { constant: { cost_per_trade } } | { vol_slippage: { slip_vol_mult } } | { carry: { carry_per_cycle } }; absent = zero cost, net = gross) open slot: strategies (required, non-empty list of { ref, axes }) open slot: process.ref (required, content id of a process document) open slot: seed (required, non-negative integer) @@ -475,6 +481,10 @@ open slot: presentation (required section: persist_taps (equity | exposure | r_e { "vol": { "length": 3, "k": 1.5 } }, { "vol": { "length": 3, "k": 3.0 } } ], + "cost": [ + { "constant": { "cost_per_trade": 0.02 } }, + { "vol_slippage": { "slip_vol_mult": 0.1 } } + ], "strategies": [ { "ref": { "content_id": "597d719b7ac607158cda3e68cd497387620397a5e93087e23da512876dafba9a" }, @@ -503,6 +513,15 @@ never by signal — the regime's stop defines the risk unit R. Absent or empty, the matrix runs one implicit default regime (the same vol regime the orchestration verbs bind when their stop flags are omitted). +The optional `cost` list is the campaign's cost model (#234): each entry +charges the trade stream in R — `constant` per closed trade, `vol_slippage` +proportional to local volatility per closed trade, `carry` per held cycle — +and the charges sum into the net curve, so every member reports net metrics +beside gross and the `net_r_equity` tap records the cost-dragged curve. +Absent or empty, the cost model is zero and net equals gross. The bound cost +knobs are stamped on each member's manifest (`cost[k].` params), so a +costed family reproduces bit-identically like any other. + ### Validate — three tiers, honest degradation ``` @@ -566,4 +585,7 @@ time registers it implicitly. `aura campaign runs` lists stored realizations; `aura campaign runs ` dumps the bare stored record(s) (not the `{"campaign_run": …}` emit wrapper above). If `presentation.persist_taps` is non-empty, the run also persists the named taps under -`runs/traces//…`, chartable with `aura chart`. +`runs/traces//…`, chartable with `aura chart`. The +`sweep`/`walkforward --trace` analog persists every member's taps as a +family charted the same way, by the handle the run prints (members keyed +`/`). diff --git a/docs/glossary.md b/docs/glossary.md index 0e1b363..c0519eb 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -307,7 +307,7 @@ An orchestration axis varying tuning params (grid or random) within a fixed stru ### tap **Avoid:** — -A named recorded stream produced by a recording `sink` — the addressable label (e.g. `equity`, `net_r_equity`) under which one sink's per-cycle output is persisted as a columnar (SoA) `ColumnarTrace` and selected for charting via `--tap`. Distinct from the `sink` node that emits it (a tap is the stream, the sink is the role) and from a whole recorded run (a bundle of taps); taps fire at their own cadences and are fused only by joining on the recorded timestamp, never by positional index. In a `campaign document`, `persist_taps` names taps from the CLOSED vocabulary `equity | exposure | r_equity | net_r_equity` (`tap_vocabulary`, 0109/#201) — a new observable is a new vocabulary entry or an authored blueprint sink, never an open node-path namespace. +A named recorded stream produced by a recording `sink` — the addressable label (e.g. `equity`, `net_r_equity`) under which one sink's per-cycle output is persisted as a columnar (SoA) `ColumnarTrace` and selected for charting via `--tap`. Distinct from the `sink` node that emits it (a tap is the stream, the sink is the role) and from a whole recorded run (a bundle of taps); taps fire at their own cadences and are fused only by joining on the recorded timestamp, never by positional index. In a `campaign document`, `persist_taps` names taps from the CLOSED vocabulary `equity | exposure | r_equity | net_r_equity` (`tap_vocabulary`, 0109/#201) — a new observable is a new vocabulary entry or an authored blueprint sink, never an open node-path namespace. Persisted taps are charted by the printed handle: a campaign run's via the record's `trace_name`, a `sweep`/`walkforward --trace` family's via the family handle the run prints (`aura chart `; its members are keyed `/` in the chart). ### topology hash **Avoid:** —