docs: C10 — strategy result is a broker-independent position table
Supersede 'broker is part of the strategy'. A strategy outputs a time-ordered table of position events (event_ts, action[buy/sell/close], position_id, instrument_id, volume; open time = opening event's event_ts, so no open_ts; unsigned volume, direction in action). Brokers become downstream swappable plugins: a deterministic frictionless sim-optimal broker yields synthetic pip-equity for neutral comparison/optimization; realistic broker plugins add currency friction/constraints for viability/deploy. Stays within C7 (scalar columns). Updates CLAUDE.md invariant 7, the walking-skeleton line, provenance, and the day-in-the-life doc. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+41
-22
@@ -5,16 +5,18 @@ contract states what it **guarantees**, what it **forbids**, and **why**. A
|
||||
change that breaks a contract is a design decision (amend the contract here with
|
||||
its new rationale), never a silent refactor.
|
||||
|
||||
Provenance: contracts C1–C15 were settled in the initial rough-sketch design
|
||||
interview (2026-06-03), walking the design tree root-to-leaf. The `CLAUDE.md`
|
||||
Provenance: contracts C1–C18 were settled in the initial rough-sketch design
|
||||
interview (2026-06-03), walking the design tree root-to-leaf (C16–C18 and the
|
||||
C10 refinement to a broker-independent position table came in follow-up turns).
|
||||
The `CLAUDE.md`
|
||||
**Domain invariants** section is the compressed, always-loaded summary of the
|
||||
subset that agents must never violate; this file is the fuller form with
|
||||
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 → deterministic backtest → equity
|
||||
metric).
|
||||
the **walking skeleton**: ingest → one signal → deterministic backtest →
|
||||
position table → sim-optimal broker → synthetic pip-equity metric).
|
||||
|
||||
---
|
||||
|
||||
@@ -136,24 +138,41 @@ forcing feedback through a visible delay node keeps the per-cycle determinism
|
||||
intact and the one legitimate feedback path explicit. Graph-as-data enables
|
||||
visualization, freezing, and re-parameterization for sweeps.
|
||||
|
||||
### C10 — The execution chain; broker is part of the strategy
|
||||
**Guarantee.** Execution is in-graph: `signals (scores) → decision node (score →
|
||||
target position, sizing, risk) → broker node (intent → fills → position / trade
|
||||
/ equity streams)`. The broker node is a fixed part of the strategy and
|
||||
identical in sim and live (one accounting path → one equity-curve shape). It is
|
||||
parameterized by a swappable **broker profile** (fees, spread/fill rules, order
|
||||
types, lot/margin); "same strategy, different broker" = swap the profile. The
|
||||
portfolio is multi-instrument (positions per symbol-key). Fills cross the real
|
||||
spread from `data-server` (buy @ ask, sell @ bid; M1 carries `spread`, tick
|
||||
carries ask/bid), causally (only prices that occurred ≤ now).
|
||||
**Forbids.** A `SimBroker`/`LiveBroker` swap; computing equity by two different
|
||||
code paths; synthetic spread when real bid/ask is available; in-graph live order
|
||||
routing.
|
||||
**Why.** Realistic P&L does not exist without committing to a broker model, so
|
||||
the broker is part of the testable artifact. One accounting path guarantees the
|
||||
equity curve looks the same in both modes by construction. Live order routing /
|
||||
reconciliation is an external adapter outside the strategy graph; the displayed
|
||||
equity stays the modeled one.
|
||||
### C10 — Strategy result is a broker-independent position table; brokers are downstream plugins
|
||||
**Guarantee.** A strategy's result is **not** an equity curve but a
|
||||
**broker-independent, time-ordered table of position events**. The chain is
|
||||
`signals (scores) → decision/sizing node → position-event output`. An event is
|
||||
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 the `event_ts` of its
|
||||
opening event (there is no separate `open_ts`); a `close` references a
|
||||
`position_id` and may be partial via its own `volume`. The **set of open
|
||||
positions at time t** (opens minus closes with `event_ts ≤ t`) is the strategy's
|
||||
*state* at t; the ordered sequence of these states is the result. Position
|
||||
sizing and risk live here (they set `volume`); the portfolio is multi-instrument.
|
||||
|
||||
A **broker is a downstream, swappable plugin** that consumes the position table
|
||||
and produces an equity curve — never part of the strategy. Two classes:
|
||||
**(a) the sim-optimal broker** — deterministic, frictionless, perfect-fill
|
||||
execution producing a **synthetic equity curve in pips** (no real currency, no
|
||||
real-broker constraints); the neutral yardstick for comparing and optimizing
|
||||
strategy *logic*. **(b) realistic broker plugins** (Pepperstone, …) — apply real
|
||||
spread / commission / slippage / lot / margin, may reject or modify positions,
|
||||
and produce a currency equity curve for viability and deployment. Pip PnL uses
|
||||
per-instrument pip metadata (reference data beside the hot path, C7). Live: a
|
||||
realistic broker plugin consumes the position events in real time and routes
|
||||
orders; reconciliation with the real account is an external adapter.
|
||||
**Forbids.** Treating an equity curve as the strategy's output; baking a broker
|
||||
into the strategy; storing `open_ts` (derive it from the opening event); a
|
||||
signed-volume direction trick (use `action`); broker-specific assumptions
|
||||
leaking into the strategy logic.
|
||||
**Why.** A strategy can be judged neutrally only if its result is independent of
|
||||
any real broker's frictions. The position table is that broker-independent
|
||||
invariant: one table feeds many brokers, each yielding its own equity — so "same
|
||||
strategy, different broker" and "same decisions sim vs live" both fall out. The
|
||||
sim-optimal pip curve is a level, currency-free playing field for comparison;
|
||||
realistic plugins then test real-world viability. This supersedes the earlier
|
||||
"broker is part of the strategy" framing.
|
||||
|
||||
### C11 — Generalized sources; record-then-replay determinism boundary
|
||||
**Guarantee.** A source is anything that produces timestamped scalar streams —
|
||||
|
||||
@@ -69,9 +69,12 @@ recorded before it enters a backtest, and only with your per-session consent.
|
||||
2. **Claude** (via the skills pipeline) writes `nodes/third-candle-long/`,
|
||||
implements `schema` + `eval` against `aura-core`.
|
||||
3. **Backtest:** `aura backtest nodes/third-candle-long --symbol GER40
|
||||
--from 2020 --to 2024 --broker pepperstone` → a metrics table (trades,
|
||||
hit-rate, P&L, max-DD, Sharpe) + a run record (manifest + metrics) under
|
||||
`runs/`.
|
||||
--from 2020 --to 2024` → the strategy produces a broker-independent
|
||||
**position table** (open/close events); the default **sim-optimal broker**
|
||||
projects it into a synthetic **pip**-equity, yielding a metrics table
|
||||
(trades, hit-rate, pip-P&L, max-DD, Sharpe) + a run record (manifest +
|
||||
metrics) under `runs/`. Add `--broker pepperstone` to project the same table
|
||||
through a realistic broker (currency, friction) for viability. (Contract C10.)
|
||||
4. **Sweep + Monte-Carlo:** `aura sweep … --grid lookback=5..50,thresh=0.5..0.9
|
||||
--mc-seeds 1000` → a distribution of metrics, best params, robustness bands.
|
||||
5. **Compose:** "combine it with `momentum-filter` as a weighted sum" → Claude
|
||||
|
||||
Reference in New Issue
Block a user