design(c10): reframe to a bias stream + R-unit signal quality

Adopt the R-reframe ratified in #117: the strategy's native unit is risk
(R), not pips/dollars, and its primary output is a directional bias.

- exposure -> bias: the primary output is an UNSIZED direction + conviction
  `f64 in [-1,+1]`; sizing and the protective stop leave the strategy.
- Signal quality is measured in R (Stage 1): an R-evaluator integrates the
  per-trade R-outcomes of a flat-1R RiskExecutor into R-expectancy. R is
  defined by the stop, account-/instrument-agnostic; pips retired as the unit.
  Flat-1R needs no equity, so Stage 1 is feed-forward (no cycle).
- Risk-based execution is a decoupled layer: a RiskExecutor composite
  (stop-rule -> Sizer -> Veto -> position-management) per symbol, nested in a
  Broker/Account composite; account mode (netting/hedging) = composition
  constraint. "Sizer" is not "risk-manager" (that names the Veto layer).
- Currency P&L is Stage 2 (fixed-fractional, compounding). The only feedback
  (equity -> Sizer) is cut by a z^-1 register on the fill edge (mark-to-market
  stays a same-cycle price read), encapsulated in the executor; flat-1R vs
  compounding is a structural axis (the explicit register is mandatory because
  C23 reorders the flat graph).
- Position-event table stays the decoupled Stage-2 audit layer = first
  difference of the book (deal = target - book - in_flight); the flawed 0064
  exposure-integral derive is abandoned.

Touches: ledger C10 + CLAUDE.md domain invariant #7 + glossary (adds bias, R,
R-evaluator, RiskExecutor, Sizer, veto, Stage 1/2; revises broker, exposure
stream, position table, sim-optimal broker, strategy, ...). Also fixes
cross-file drift surfaced by adversarial review (C20 guarantee + front-matter
provenance still claimed "exposure stream"; cross-refs corrected to
C9/C19/C20/C23). Industry-grounded against LEAN / nautilus_trader / backtrader
/ QSTrader / vectorbt / zipline.

refs #117
This commit is contained in:
2026-06-23 13:14:31 +02:00
parent 2e0500dedd
commit f040b66f30
3 changed files with 175 additions and 87 deletions
+25 -15
View File
@@ -84,21 +84,31 @@ design decision, not a refactor, and belongs in the ledger.
makes a live external call mid-replay. (See `~/.claude/CLAUDE.md` for the
IONOS consent rule: external LLM calls happen at the recording/live-source
edge, with explicit per-session consent, never inside a backtest.)
7. **Strategy output is an intent/exposure stream; position management is a
decoupled derived layer.** The DAG expresses one state at t (C8: ≤1 record per
`eval`), so a strategy's primary, backtestable output is a signed, bounded
**exposure** `f64 ∈ [-1,+1]` per cycle, not an equity curve. **Signal quality**
is measured by the **sim-optimal broker** — a downstream consumer node that
integrates `exposure·return` into a deterministic, frictionless synthetic
equity stream in **pips**. The broker-independent **position-event table**
(`event_ts, action[buy/sell/close], position_id, instrument_id, volume`) is a
**decoupled, derivable** layer — the first difference of the exposure state, a
computed table (not a per-`eval` output, since one decision instant may yield
>1 event) — that feeds **realistic broker nodes** (currency equity, real
frictions) for viability and deploy. The two broker classes attach at two
points: sim-optimal on the exposure stream, realistic on the derived
position-event table; brokers are ordinary downstream nodes, never part of the
strategy.
7. **Strategy output is a directional bias stream; risk-based execution and
realistic brokers are decoupled downstream layers; signal quality is measured
in R.** The DAG expresses one state at t (C8: ≤1 record per `eval`), so a
strategy's primary, backtestable output is a signed, bounded **bias** `f64 ∈
[-1,+1]` per cycle — direction (sign) + conviction (magnitude, optional),
**unsized** (not an equity curve, not a position, not a size). Sizing leaves the
strategy: a decoupled **risk-based execution** layer `bias → stop-rule → Sizer →
Veto → position-management` (the **RiskExecutor** composite, per symbol, nested
in a Broker/Account composite) turns bias + a protective **stop** into a sized
intent. The **stop defines the risk unit R** (1R = the loss if stopped).
**Signal quality is measured in R** (R-multiples / expectancy), the account- and
instrument-agnostic yardstick — **Stage 1**: flat-1R sizing, feed-forward, no
equity feedback, the primary research loop. **Currency P&L is Stage 2** (deploy
viability): fixed-fractional sizing reads equity (compounding) → realistic
brokers apply real frictions → currency equity, entered only after `E[R] > 0`.
The single feedback (equity → Sizer) is cut by a `z⁻¹` register on the **fill
edge** (mark-to-market stays a same-cycle price read), encapsulated in the
executor composite; flat-1R vs compounding is a **structural axis** (C11). The
broker-independent **position-event table** (`event_ts, action[buy/sell/close],
position_id, instrument_id, volume`) remains the **decoupled, derived** Stage-2
audit layer — the first difference of the *book* (`deal = target book
in_flight`), a computed table (not a per-`eval` output, since one decision
instant may yield >1 event) — feeding realistic brokers. Brokers/executors are
ordinary downstream nodes, never part of the strategy; account mode
(netting/hedging) is a composition constraint.
8. **Deploy artifacts are frozen.** Hot-reload (cdylib) is an authoring-loop
tool only. The live bot is a statically-linked, versioned, frozen artifact —
never hot-swapped (audit trail: this bot = this commit).
+113 -63
View File
@@ -8,8 +8,9 @@ its new rationale), never a silent refactor.
Provenance: contracts C1C18 were settled in the initial rough-sketch design
interview (2026-06-03), walking the design tree root-to-leaf (C16C18 and the
C10 refinement to a broker-independent position table came in follow-up turns;
C10 was later reframed in cycle 0007 — the intent/exposure stream is the primary
output, the position table a derived layer — see C10). C19C22 were added as the
C10 was reframed in cycle 0007 to an exposure stream, then again 2026-06-23
(#117) to a **bias** stream with signal quality in **R**, the position table a
derived layer — see C10). C19C22 were added as the
construction / World / playground layer; C23 and the C9/C19 compilation
refinements were settled 2026-06-05 for the **Construction-layer** milestone (the
blueprint→flat-graph reading of composites and graph optimisation).
@@ -20,8 +21,9 @@ rationale.
Vocabulary: a *contract* is one ledger entry. A *cycle* is one pipeline round; a
*milestone* is a tracker container spanning many cycles (the first milestone is
the **walking skeleton**: ingest → one signal → exposure/intent → sim-optimal
broker → synthetic pip-equity signal-quality metric).
the **walking skeleton**: ingest → one signal → exposure → sim-optimal broker →
synthetic pip-equity signal-quality metric — the *pre-reframe* substrate, now
reframed to bias → R-evaluator → R-expectancy, see C10).
---
@@ -401,7 +403,7 @@ cycle 0005). This is the **same arity** C8 already grants a leaf (OHLCV = one po
5 columns): a multi-line indicator (MACD = macd/signal/histogram) is **one** record
of K fields, **one** port, **one** row per `eval` — C8/C7/C4 untouched, a boundary
completion, not a contract change. A strategy composite is simply the K=1 case
(one exposure field, C10). The re-export **names** are **non-load-bearing** (C23):
(one bias field, C10). The re-export **names** are **non-load-bearing** (C23):
they live at the blueprint boundary and in render (cycle 0022/#46 folds each onto
its producing node as a `name := …` binding; originally `[out:<name>]` markers, #13)
but are dropped at lowering — `ItemLowering::Composite.output` is `Vec<(usize,
@@ -447,74 +449,122 @@ distinguishability check, if ever wanted (e.g. for the WASM graph view's #21
thread), is decoupled from param-space injectivity. Construction-phase only; the
flat graph stays name-free (C23).
### C10 — Strategy output is an intent/exposure stream; position management is a decoupled derived layer; brokers are downstream nodes
### C10 — Strategy output is a bias stream; signal quality is measured in R; risk-based execution and realistic brokers are decoupled downstream layers
**Guarantee.** A strategy's primary, backtestable output is **not** an equity
curve, **nor a position-event table**, but an **intent / exposure stream**: the
DAG expresses exactly one *state* at time t (C8 — a node emits at most one record
per `eval`), so a strategy emits one **signed, bounded exposure** `f64 ∈
[-1, +1]` per cycle (per instrument; the portfolio is multi-instrument). Exposure
is the desired fractional position; **position sizing and risk live in the
decision/sizing node** that shapes a raw signal score into exposure. The chain is
`signals (scores) → decision/sizing node → exposure stream`.
curve, **nor a position-event table**, **nor a position size**, but a **bias
stream**: the DAG expresses exactly one *state* at time t (C8 — a node emits at
most one record per `eval`), so a strategy emits one **signed, bounded bias**
`f64 ∈ [-1, +1]` per cycle (per instrument) — the **sign is direction, the
magnitude is conviction**, and conviction is optional (a bare ±1 / 0 is the modal
case). Bias is **unsized**: position sizing and the protective stop do **not**
live in the strategy. The chain is `signals (scores) → decision node → bias
stream`.
**Signal quality** is evaluated by the **(a) sim-optimal broker** — a downstream
consumer node (C8/C9) that consumes the **exposure stream** plus the relevant
price stream and integrates `exposure(t-1) · (price(t) price(t-1))` into a
**synthetic equity stream in pips**: deterministic, frictionless, perfect-fill
(no currency, no real-broker constraints). The exposure held *into* a cycle
(decided at t-1) earns that cycle's return, so the integration is causal (C2 — no
look-ahead). Pip PnL uses per-instrument pip metadata (reference data beside the
hot path, C7/C15). This pip-equity curve measures the **signal's quality**, not
an execution-modelled P&L; it is the primary research loop — backtest one signal,
combine it with another, backtest the combination.
**Risk-based execution is a decoupled downstream layer.** Turning a bias into a
position is the job of a **risk-based execution** chain — `bias → stop-rule →
Sizer → Veto → position-management` — never the strategy's. The **stop-rule** sets
a protective stop, which **defines the risk unit R** (1R = the loss taken if
stopped). The **Sizer** sizes the trade in R; the **Veto** is a distinct
pre-trade gate (position / exposure caps), kept separate from sizing. These wire
into a **RiskExecutor** composite (per symbol); RiskExecutors nest inside a
**Broker / Account** composite that aggregates per-symbol P&L into account equity.
The account **mode is a composition constraint**: a *netting* account allows ≤1
RiskExecutor per (strategy, symbol); a *hedging* account (the European CFD
default) allows many per symbol, even oppositely directed.
**Position management** — turning the exposure stream into a broker-independent,
**Signal quality is measured in R — Stage 1.** A downstream **R-evaluator**
consumes a RiskExecutor run under **flat-1R** sizing (every trade risks exactly
1R) and integrates the per-trade R-outcomes into an **R-expectancy** / R-curve:
the account- and instrument-agnostic yardstick for *"how much R out per 1R
risked?"*. Flat-1R needs no equity, so this stage is **feed-forward** (no
feedback, no cycle) — the primary research loop, maximally parallel and
deterministic (C1). R, not pips, is the unit: pips are not risk-normalized.
**Currency P&L is Stage 2 — deploy viability.** Entered only once `E[R] > 0` is
established. Here sizing is **fixed-fractional** (size = risk-fraction · equity /
stop-distance), so it **reads account equity** and **compounds**; **realistic
broker** nodes apply real spread / commission / slippage / lot / margin and emit a
**currency** equity stream. This introduces the *only* feedback in the whole
design — equity → Sizer — cut by a **`z⁻¹` register on the fill edge** (the
realized/fill component is delayed one cycle; mark-to-market off the current price
stays a legal same-cycle read, C2), **encapsulated inside the executor
composite**. Whether that register is live is the **flat-1R vs compounding
structural axis** (instantiating a feedback edge is topology, fixed at bootstrap
(C19), hence a structural axis (C20), never a numeric sweep param): flat-1R DCEs
it away (Stage 1), compounding keeps it (Stage 2). The explicit register is
**mandatory** — C9's "only feedback is an explicit delay node" made concrete —
because the bootstrap's optimiser reorders the flat graph (C23 CSE/DCE): the
implicit read-before-fill ordering by which conventional sequential backtesters
cut this loop would not survive that reordering.
**The position-event table** — turning the executed book into a broker-independent,
time-ordered **table of position events** (pure scalar columns, C7: `event_ts:
timestamp`, `action: i64` buy / sell / close, `position_id: i64`,
`instrument_id: i64`, `volume: f64` unsigned — direction is the `action`; a
position's open time is its opening event's `event_ts`, no separate `open_ts`; a
`close` references a `position_id` and may be partial via its own `volume`) — is a
**decoupled, derivable, downstream** layer. The events are the **first difference
of the exposure state**, materialized as a *computed table* (where multiple
events may share one `event_ts` — e.g. a reversal's close + open), **never as a
per-`eval` node output** (which C8 caps at one record per cycle). This layer feeds
**(b) realistic broker nodes** (Pepperstone, …): downstream consumer nodes that
consume the position-event table plus prices, apply real spread / commission /
slippage / lot / margin, may reject or modify positions, and produce a
**currency** equity stream for viability and deployment. The position-event table
stays broker-independent — one table feeds many realistic brokers, giving
**decoupled, derived, downstream** Stage-2 layer. The events are the **first
difference of the book** under book-tracking (`deal = target book in_flight`;
a close sizes the actual book, never an exposure delta), materialized as a
*computed table* (multiple events may share one `event_ts` — e.g. a reversal's
close + open), **never as a per-`eval` node output** (C8 caps one record per
cycle). This table feeds the realistic broker nodes; one table feeds many, giving
directly comparable currency curves. Live: a realistic broker node consumes the
events in real time and routes orders as a side effect; reconciliation with the
real account is an external adapter.
So **the two broker classes attach at two different points**: the sim-optimal
broker on the **exposure stream** (signal quality, pips, now), realistic brokers
on the **derived position-event table** (execution viability, currency, later).
Both are ordinary downstream nodes (C8/C9); several can attach at once for
directly comparable curves.
**Forbids.** Treating an equity curve as the strategy's output; making the
**position-event table the strategy's direct DAG output** (it is derived, not
emitted per `eval` — a decision instant may need >1 event, which C8 forbids) or
the measure of signal quality; baking a broker into the strategy; a special
external broker subsystem (a broker is an ordinary node); storing `open_ts`
(derive it from the opening event); a signed-volume direction trick in the event
table (use `action`); broker-specific assumptions leaking into the strategy logic.
**Why.** The DAG is a synchronous reactive graph: at time t it holds exactly one
state, and a node emits at most one record per `eval` (C8). A *sequence of
position events* — where one decision instant (a stop-and-reverse) needs a close
**and** an open at the same `event_ts` — cannot be the DAG's per-cycle output
without violating C8. The state the DAG *can* express faithfully is the **desired
exposure** (one value per cycle); the position events are its first difference, a
derived consequence. Decoupling them resolves the C8↔C10 impedance and matches
how signal research actually proceeds: you first measure a signal's *quality*
(does this exposure, held over time, make pips?) independently of any execution
model; only later do you model position management and real-broker frictions for
deployment. The sim-optimal pip curve is a level, currency-free playing field for
comparing and combining signals; the derived position-event table + realistic
broker nodes then test real-world viability. Modelling brokers as nodes (not a
bespoke subsystem) keeps them within the one Node/graph abstraction (C9). This
supersedes the earlier "the strategy's output is the position-event table"
framing (cycle 0007 reframe).
So the layers attach at distinct points: the **R-evaluator** on a flat-1R
RiskExecutor (signal quality, R, Stage 1); **realistic brokers** on the derived
position-event table (execution viability, currency, Stage 2). All are ordinary
downstream nodes (C8/C9); several can attach at once for directly comparable
curves.
**Forbids.** Putting **sizing or the stop in the strategy** (bias is unsized; the
Sizer and stop-rule own them); treating an equity curve as the strategy's output;
making the **position-event table the strategy's direct DAG output** (it is
derived, not emitted per `eval` — a decision instant may need >1 event, which C8
forbids) or the measure of signal quality; **measuring signal quality in currency
before R is established** (Stage 2 before Stage 1); a **combinational equity → size
cycle** (the fill-edge register is mandatory — an implicit execution ordering does
not survive C23 reordering); **fusing the Sizer and the Veto** into one node (the
size / veto / fill roles stay distinct); baking a broker into the strategy; a
special external broker subsystem (a broker is an ordinary node); storing
`open_ts` (derive it from the opening event); a signed-volume direction trick in
the event table (use `action`); broker-specific assumptions leaking into the
strategy logic.
**Why.** A strategy's edge is a *procedure*, not a currency outcome ("focus on the
procedure, not the money"): the right primary question is *"how much R out per 1R
risked?"*, and R — defined by the stop — is the only account- and
instrument-agnostic, risk-normalized unit (pips are not). Separating **direction
(bias) from sizing (Sizer) from fill (broker)** is the decomposition every mature
system converges on (LEAN's Alpha → Portfolio-Construction → Execution is a near
isomorphism; backtrader, QSTrader, zipline all emit an unsized directional signal
sized downstream). The **Stage-1 / Stage-2 cleave** quarantines the *only*
feedback (equity → sizing) into Stage 2, leaving the signal-quality layer
feed-forward, parallel and deterministic (C1); its closest external precedent is
vectorbt's split of vectorized signal generation from sequential money-management
— it is aura's own synthesis, not an industry standard. The DAG holds exactly one
state at t and a node emits ≤1 record per `eval` (C8), so the faithful per-cycle
output is the **bias** (one value); position *events* are its book's first
difference, a derived consequence — decoupling them resolves the C8↔C10 impedance.
Modelling brokers and executors as nodes (not a bespoke subsystem) keeps them
within the one Node/graph abstraction (C9). This supersedes the **exposure**
framing (the strategy's output was a signed fractional *position*) of the
cycle-0007 reframe and its realization notes below; that in turn superseded the
still-earlier "the strategy's output is the position-event table" framing.
**Reframe (2026-06-23, #117 — exposure → bias, R as the signal-quality unit).**
The contract above is the R-reframe; the realization notes below describe the
**pre-reframe code** (`Exposure`, `SimBroker`, pip-equity) and are retained as
history and as the **Stage-1 ancestor**: `Exposure { scale }` is the ancestor of
the unsized `bias` node, and `SimBroker`'s pip integral is the ancestor of the
R-evaluator (which additionally requires a stop, since R is stop-defined, so it
consumes a flat-1R RiskExecutor rather than raw bias). The `exposure → bias`
rename, the RiskExecutor / Sizer / Veto nodes, and the R-evaluator are **pending
Stage-1 implementation**; the position-event schema (0063, #114) survives
unchanged as the Stage-2 audit layer, though its derivation is now the **book**
first-difference (`deal = target book in_flight`), not the flawed 0064
exposure-integral derive (abandoned). Industry grounding for this reframe: LEAN /
nautilus_trader / backtrader / QSTrader / vectorbt / zipline (see #117 decision
log).
**Realization (cycle 0007).** The signal-quality half of this contract is now
realized at the substrate, as two `aura-std` nodes composed on the unchanged
engine (the engine stays domain-free — it routes only `f64` records, never
@@ -923,7 +973,7 @@ per-knob overlay, no registry (C9/C10 intact).
### C20 — Strategy ↔ harness; the harness is the root sim graph
**Guarantee.** A **strategy** is a reusable composite-node blueprint (C9):
broker-, data-, and viz-independent, with inputs declared as named **roles**
(symbol-agnostic where possible) and the intent/exposure stream (C10) as output.
(symbol-agnostic where possible) and the **bias** stream (C10) as output.
A **harness** (the experimental setup) is the **root sim graph** — sources bound
to the strategy's input roles + the strategy + attached broker node(s) + sinks —
and is itself produced by the bootstrap (C19). A harness *instance* is C1's
@@ -1131,7 +1181,7 @@ recorded data stays on disk (view-only), and the walk-forward null-fill page col
for free. Deterministic (C1): pure bucketing over the sorted-deduped spine, no-op under
budget. **Refinement (#111, 2957561):** the per-bucket reduction is **tap-aware** — an
*envelope* series (equity) keeps min/max, but a *bounded level* series (the C10
exposure, ∈[-1,+1]) reduces by per-bucket **mean** (a `ReduceKind` on each `Series`,
bias level — pre-reframe: exposure ∈[-1,+1]) reduces by per-bucket **mean** (a `ReduceKind` on each `Series`,
set by `reduce_for_tap`). Without it min/max made every multi-year exposure a solid
-1..+1 band (each bucket straddles many sign flips), reading as per-point oscillation;
the mean shows the net/duty-cycle level. Deferred refinements: rendering the min/max
+37 -9
View File
@@ -23,6 +23,10 @@ The per-project declarative config holding only static context (data paths, inst
**Avoid:** —
A single deterministic, synchronous run of one harness over historical input — the historical-replay framing of an execution. The commodity substrate the World builds families of; distinct from `sim` (the executable unit) and `run` (its registry record).
### bias
**Avoid:** exposure, exposure stream, intent stream
A strategy's primary, backtestable DAG output: one signed, bounded `f64 ∈ [-1,+1]` per cycle whose **sign is direction and magnitude is conviction** (conviction optional). Bias is **unsized** — sizing and the protective stop live downstream in the risk-based execution layer (`Sizer`/`RiskExecutor`), never in the strategy; it reframes the pre-reframe `exposure stream` (a signed fractional *position*).
### blueprint
**Avoid:** —
The param-generic, input-role-generic graph-as-data produced by running a Rust builder; it carries free numeric params and free input roles before bootstrap. Bootstrapped into a frozen instance by binding params + data + seed.
@@ -37,7 +41,7 @@ A frozen artifact that is a deployed strategy + broker: the live trading program
### broker
**Avoid:** —
A downstream consumer node that emits an equity stream, attaching at one of two points: the **sim-optimal broker** consumes the **exposure stream** (integrating `exposure·return` → synthetic pip equity = signal quality); **realistic brokers** consume the derived **position-event table** (real frictions → currency equity). Several can attach at once for directly comparable curves. Not part of the strategy. Two classes: the sim-optimal broker and realistic brokers.
A downstream consumer node that emits an equity stream, never part of the strategy. The signal-quality side is the **R-evaluator** (Stage 1: per-trade R-outcomes from a flat-1R `RiskExecutor` → R-expectancy); **realistic brokers** (Stage 2) consume the derived **position-event table** (real frictions → currency equity), and a **Broker/Account** composite aggregates per-symbol P&L into account equity. Several can attach at once for directly comparable curves.
### cdylib
**Avoid:** —
@@ -61,7 +65,7 @@ A directed wiring link in a harness that forwards **one field** (`from_field`) o
### equity stream
**Avoid:** —
A broker node's output over time — synthetic pips for the sim-optimal broker (its `exposure·return` integral), currency for realistic brokers. An equity *curve* is explicitly not a strategy's output (the intent/exposure stream is).
A downstream node's output over time — an **R-curve** for the R-evaluator (Stage 1, its per-trade R integral), **currency** for realistic brokers (Stage 2). An equity *curve* is explicitly not a strategy's output (the `bias` stream is).
### experiment
**Avoid:** —
@@ -72,8 +76,8 @@ A Rust (builder-API) definition of anything beyond a single backtest — sweep,
The set of harness instances produced by varying the structural axes (strategy × instrument × broker × window), expressed as plain Rust loops. The outer orchestration over the structural dimension; the tuning sweep is the inner loop.
### exposure stream
**Avoid:** intent stream
A strategy's primary, backtestable DAG output: one signed, bounded `f64 ∈ [-1,+1]` per cycle the desired fractional position (intent). The DAG expresses one state at t (C8: ≤1 record per `eval`), so exposure, not a position-event sequence, is what it emits. The sim-optimal broker integrates `exposure·return` into pip equity to measure signal quality; the position table is its derived first difference.
**Avoid:** — (superseded)
**Superseded by `bias` (2026-06 R-reframe).** The pre-reframe primary output: a signed, bounded `f64 ∈ [-1,+1]` per cycle read as the desired fractional *position* (conflating direction + conviction + size). Reframed to `bias` (unsized direction + conviction), sizing moved downstream to the `Sizer`/`RiskExecutor`; the term and the `Exposure` node persist in pre-reframe code until the Stage-1 rename.
### firing policy
**Avoid:** —
@@ -121,11 +125,23 @@ The egui-native visual face (`aura play`) that plays any harness — program str
### position table
**Avoid:** —
A broker-independent, time-ordered table of position events (scalar columns: `event_ts, action, position_id, instrument_id, volume`) — the **derived** first difference of a strategy's exposure stream, a **decoupled position-management layer** feeding realistic brokers / deploy. Computed, not emitted per `eval` (one decision instant may yield >1 event); **not** the strategy's direct DAG output (that is the intent/exposure stream).
A broker-independent, time-ordered table of position events (scalar columns: `event_ts, action, position_id, instrument_id, volume`) — the **derived** first difference of the executed **book** (book-tracking `deal = target book in_flight`; a close sizes the actual book), a **decoupled** Stage-2 position-management layer feeding realistic brokers / deploy. Computed, not emitted per `eval` (one decision instant may yield >1 event); **not** the strategy's direct DAG output (that is the `bias` stream).
### R
**Avoid:** —
The native unit of strategy performance: 1R = the loss if the protective stop is hit, so a trade's outcome is a multiple of R (1R stopped out, +2R, …) and the primary question is *"how much R out per 1R risked?"*. Risk-normalized and account-/instrument-agnostic — the Stage-1 yardstick replacing pips, defined by the stop (Van Tharp R-multiples).
### R-evaluator
**Avoid:** —
The Stage-1 signal-quality node: integrates the per-trade R-outcomes of a flat-1R `RiskExecutor` into an R-expectancy / R-curve — the deterministic, account-/instrument-agnostic yardstick. The R-reframe successor of the `sim-optimal broker` (pip integral); unlike it the R-evaluator requires a stop, so it consumes a RiskExecutor, not raw bias.
### RiskExecutor
**Avoid:** risk-manager
The per-symbol composite turning a bias into a managed position — `stop-rule → Sizer → Veto → position-management` — with the only feedback (equity → Sizer, Stage 2) cut by a `z⁻¹` register on the fill edge and encapsulated inside. RiskExecutors nest in a Broker/Account composite that aggregates per-symbol P&L into account equity; the account mode (netting/hedging) constrains how many exist per (strategy, symbol).
### realistic broker
**Avoid:** —
A broker node that consumes the derived position-event table and applies real spread / commission / slippage / lot / margin (and may reject or modify positions), emitting a currency equity stream for viability and deploy. Contrasted with the sim-optimal broker (which consumes the exposure stream directly).
A Stage-2 broker node that consumes the derived position-event table and applies real spread / commission / slippage / lot / margin (and may reject or modify positions), emitting a currency equity stream for viability and deploy. Contrasted with the R-evaluator (Stage 1, which consumes a flat-1R RiskExecutor and measures signal quality in R).
### resampler
**Avoid:** —
@@ -153,7 +169,7 @@ A node that exposes session context as scalar streams (`bars_since_open`, `in_se
### signal
**Avoid:** —
A node whose output is a score, feeding the `signals (scores) → decision/sizing node → exposure stream` chain. A specific node role — distinct from a general node and from a strategy.
A node whose output is a score, feeding the `signals (scores) → decision node → bias stream` chain. A specific node role — distinct from a general node and from a strategy.
### sim
**Avoid:** —
@@ -161,12 +177,16 @@ The disjoint, executable unit of one deterministic harness run; the unit of para
### sim-optimal broker
**Avoid:** —
The deterministic, frictionless, perfect-fill broker that consumes the **exposure stream** + prices and integrates `exposure·return` into synthetic equity in pips — the neutral, currency-free yardstick that measures **signal quality**. Distinct from the Aura.toml "default broker" (a config role) and from realistic brokers (which consume the derived position-event table).
**Pre-reframe term, succeeded by the `R-evaluator`.** The deterministic, frictionless, perfect-fill broker (`SimBroker`) that consumes the **exposure stream** + prices and integrates `exposure·return` into synthetic pip equity to measure signal quality. The R-reframe replaces pips with R (the R-evaluator integrates per-trade R-outcomes from a flat-1R RiskExecutor); `SimBroker` persists in pre-reframe code until the Stage-1 rename.
### sink
**Avoid:** —
A node in its **recording role**: in `eval` it reads its inputs (and `ctx.now()`) and pushes the record to an out-of-graph destination it holds as a field (a channel, a chart handle, the run registry) — a role, not a type, so a node may be a pure consumer (no output) or record *and* forward an output in the same `eval` (the C8 "both" case). The sole recording and observability mechanism: displayable = exactly what a sink recorded.
### Sizer
**Avoid:** risk-manager
The node that sizes a trade from bias + the stop — in R (flat-1R, Stage 1) or in lots from account equity (fixed-fractional, Stage 2) — owning the size, not the direction (bias) or the gate (Veto). "risk-manager" is avoided: in LEAN/nautilus that names the Veto layer, not the sizer.
### SoA
**Avoid:** Structure-of-Arrays
The columnar Structure-of-Arrays layout in which the four scalar base types are streamed on the hot path. Composite streams are bundles of base columns; the layout is what makes streaming cache- and SIMD-friendly.
@@ -175,9 +195,13 @@ The columnar Structure-of-Arrays layout in which the four scalar base types are
**Avoid:** —
Anything that produces timestamped scalar streams — market data and non-financial feeds (e.g. a news-bias node) are treated identically; a pure producer node. `data-server` is aura's first source.
### Stage 1 / Stage 2
**Avoid:** —
The two-stage cleave of evaluation: **Stage 1** (R / signal quality) is flat-1R, feed-forward (no equity feedback), measured by the R-evaluator in R-expectancy — the primary research loop; **Stage 2** (currency / deploy viability) is fixed-fractional sizing that reads equity and compounds, with realistic brokers and real frictions, entered only once `E[R] > 0`. The cleave quarantines the only feedback into Stage 2 (flat-1R vs compounding is a structural axis, C11); aura's own synthesis, closest precedent vectorbt's signal vs money-management split.
### strategy
**Avoid:** —
A reusable composite-node blueprint — broker-, data-, and viz-independent, inputs declared as named roles — whose output is the intent/exposure stream (not an equity curve; the position table is a derived downstream layer). Frozen with a broker into a bot for deploy.
A reusable composite-node blueprint — broker-, data-, and viz-independent, inputs declared as named roles — whose output is the **bias** stream (unsized direction + conviction; not an equity curve, not a size; sizing and the position table are derived downstream layers). Frozen with a broker into a bot for deploy.
### structural axes
**Avoid:** —
@@ -187,6 +211,10 @@ The harness's structural parameterization — which strategy, instrument(s), bro
**Avoid:** param-sweep, parameter sweep
An orchestration axis varying tuning params (grid or random) within a fixed structure. The inner, param-tuning loop, distinct from the structural experiment matrix.
### veto
**Avoid:** risk-manager
The distinct pre-trade gate in the execution chain (`… → Sizer → Veto → position-management`): position / exposure / notional caps that may reject or scale a sized intent before it reaches the broker. Kept separate from the Sizer — it is what LEAN calls "Risk Management" and nautilus the RiskEngine.
### walk-forward
**Avoid:** —
An orchestration axis: rolling in-sample optimize + out-of-sample test across moving windows, stitched into one out-of-sample verdict plus parameter stability.