4acea45519
Cycle-close audit for the verb-axis-generalization cycle (a2294c7,e7efe1f,b849bb7). Architect drift review: what holds — all four verbs route through the one validate_and_register_axes seam into the campaign executor; RGrid gone workspace-wide; zero too_many_arguments allows in verb_sugar.rs; no r_sma_open embed at the verb dispatch sites (the aura-graph default embed survives by design). Five drift items found, all resolved fix-path in this commit: - README (blueprint-verbs section + mc row), glossary (walk-forward entry), and ledger (verb-dissolution passage) reconciled to the shipped generic grammar; the ledger HISTORY note now separates the two supersessions correctly (#159 retired the built-in --strategy demo surface; #220 de-welded the verbs) instead of mis-attributing the weld removal to #159. - Four stale characterization doc-comments in cli_run.rs reworded: the retired welded grammar is now named as the pinned grades' provenance, not the current spelling; one dangling reference to a deleted test repointed to the live anchor. - The quadruplicated dispatch blocks extracted into two shared helpers beside validate_and_register_axes: exit_axis_register_error (the AxisRegisterError exit-map, byte-identical stderr + exit codes) and campaign_window_ms (from_choice -> full_window -> unix-ms clip); generalize's explicit unclipped (Some, Some) passthrough arm is untouched — only its fallback arm, which already ran the identical mechanics, calls the helper. Regression gate green, no baseline moved (nothing to ratify): cargo test --workspace exit 0, 62 test-result groups, 0 failures; clippy --workspace --all-targets -D warnings clean; cargo doc --workspace --no-deps 0 warnings. Spent cycle spec + plan working files discarded per lifecycle. refs #220
126 lines
7.2 KiB
Markdown
126 lines
7.2 KiB
Markdown
# aura
|
|
|
|
**aura is a "game engine for traders."** It is a Rust framework — and a
|
|
playground — for authoring trading strategies as composable dataflow nodes,
|
|
backtesting them deterministically and massively in parallel, validating them
|
|
(sweep / Monte-Carlo / walk-forward), and freezing a validated strategy into a
|
|
standalone bot with a broker connection. Its differentiator is the **World**: a
|
|
program that constructs and orchestrates whole *families* of backtests, not the
|
|
single run.
|
|
|
|
This README is a discoverability map of the shipped `aura` CLI — *what commands
|
|
exist and what they do*. It deliberately keeps per-flag detail light; the two
|
|
authoritative sources for exact syntax are always:
|
|
|
|
- `aura <command> --help` — the exhaustive flag grammar.
|
|
- The design ledger (`docs/design/INDEX.md`) and glossary (`docs/glossary.md`)
|
|
— the concepts and invariants behind the surface.
|
|
|
|
## Build & run
|
|
|
|
aura is a Cargo workspace. Build everything and you get one binary named `aura`:
|
|
|
|
```sh
|
|
cargo build --workspace # binary at target/debug/aura
|
|
cargo build --workspace --release # optimized, at target/release/aura
|
|
```
|
|
|
|
Invoke it as `aura <command> …` (examples below use the plain name).
|
|
|
|
## Concepts in one breath
|
|
|
|
- **Blueprint** — a serialized signal graph as data: a param-generic
|
|
`price → bias` node graph. A blueprint file (`blueprint.json`) is the unit a
|
|
downstream consumer loads and drives verbs over.
|
|
- **Open vs. closed** — a blueprint with unbound (free) numeric knobs is *open*;
|
|
one with every knob bound is *closed*. Different verbs want different states
|
|
(see each verb below).
|
|
- **Family** — the set of runs one verb produces over a blueprint (a sweep grid,
|
|
a Monte-Carlo seed set, a walk-forward window sequence). Families are persisted
|
|
in a content-addressed store and can be listed, ranked, and reproduced.
|
|
- **Axis** — one named, sweepable knob of a blueprint (e.g. `graph.fast.length`),
|
|
bound with a comma-separated value list.
|
|
|
|
## Running & orchestrating a loaded blueprint
|
|
|
|
These verbs all take the **blueprint file as their first positional argument**
|
|
and drive a family of runs over it. `walkforward`, `mc`, and `generalize` share
|
|
`sweep`'s generic grammar — the blueprint positional plus `--real` and a
|
|
repeatable `--axis <name>=<csv>` (`generalize` takes `--real <SYM1,SYM2,…>`, at
|
|
least two instruments, with a single value per axis) — see `--help`.
|
|
|
|
| Command | Purpose |
|
|
|---|---|
|
|
| `aura run <bp.json>` | Run one backtest of a **closed** blueprint and print its report. An open (free-knob) blueprint is refused with a clean error — bind it, or use `sweep`. |
|
|
| `aura sweep <bp.json> --list-axes` | **Discover** the blueprint's open, sweepable knobs. Prints each as `<name>:<kind>`. Run this first to learn the axis names. |
|
|
| `aura sweep <bp.json> --axis <name>=<csv> [--axis …]` | Run a **grid family** over the named axes and persist it. |
|
|
| `aura mc <bp.json> --seeds <n>` | Run a **synthetic Monte-Carlo family** of `n` seeded realizations. Wants a **closed** blueprint (the inverse of sweep). |
|
|
| `aura mc <bp.json> --real <sym> --axis <name>=<csv> [--axis …]` | Run a **Monte-Carlo R-bootstrap campaign** over recorded data — driven through the same generated-campaign pipeline as `sweep`; `--block-len`/`--resamples`/`--seed` tune the bootstrap. |
|
|
| `aura walkforward <bp.json> --axis <name>=<csv> [--axis …]` | Run an **in-sample-refit walk-forward family** — rolling optimize + out-of-sample test across windows, stitched into one verdict + parameter stability. `--select` chooses the per-window objective. |
|
|
| `aura runs families` | List every persisted family (id, kind, member count). |
|
|
| `aura runs family <id> [rank <metric>]` | List one family's members, optionally ranked best-first by an R metric (e.g. `sqn_normalized`, `expectancy_r`). |
|
|
| `aura reproduce <family-id>` | Re-derive every member of a persisted family from the content-addressed store and check it is bit-identical (the C18/C1 determinism guarantee). |
|
|
|
|
**Important contract — every open knob is mandatory.** On `sweep` and
|
|
`walkforward`, the knobs enumerated by `--list-axes` are *all* required: you must
|
|
supply an `--axis` for each open knob. There is no default value — pin a knob you
|
|
don't want to vary with a single-value axis (`--axis name=4`). Omitting one is a
|
|
clean error naming the missing knob, not a silent default.
|
|
|
|
Use `aura <cmd> --help` for the full data-window (`--real`/`--from`/`--to`),
|
|
naming (`--name`/`--trace`), and selection (`--select`) flags.
|
|
|
|
## Authoring & introspecting topology
|
|
|
|
A blueprint is authored declaratively from a **JSON op-list**: an ordered list
|
|
of by-identifier construction ops replayed against the standard node vocabulary.
|
|
|
|
| Command | Purpose |
|
|
|---|---|
|
|
| `aura graph build` | Read an op-list document on **stdin**, build the blueprint, and print its canonical JSON to **stdout** (no trailing newline — it is the content-addressed artifact). |
|
|
| `aura graph introspect --vocabulary` | List every node type available to op-lists. |
|
|
| `aura graph introspect --node <T>` | Show one type's input ports, output fields, and param paths (with the bind-value form). |
|
|
| `aura graph introspect --unwired` | Read a *partial* op-list on stdin and list its still-open interior slots. |
|
|
| `aura graph introspect --content-id` | Read an op-list on stdin and print the SHA-256 content id of the blueprint it would build. |
|
|
| `aura graph introspect --identity-id` | Read an op-list on stdin and print the SHA-256 **identity id** — the topology's debug-name-blind id, so two documents (or an op-script and a Rust-built blueprint) expressing the same topology print the same id. Combinable with `--content-id` (both ids, one per line, content id first). |
|
|
|
|
### Op-list shape
|
|
|
|
Each element is one op, tagged by `"op"`. Node params are bound with the **typed
|
|
`Scalar` form** — a tagged, capitalized-kind object: `{"I64": 5}`, `{"F64":
|
|
1.5}`, `{"Bool": true}`. A worked example (an SMA-crossover → bias signal):
|
|
|
|
```json
|
|
[
|
|
{"op":"source","role":"price","kind":"F64"},
|
|
{"op":"add","type":"SMA","name":"fast","bind":{"length":{"I64":2}}},
|
|
{"op":"add","type":"SMA","name":"slow","bind":{"length":{"I64":4}}},
|
|
{"op":"add","type":"Sub"},
|
|
{"op":"add","type":"Bias"},
|
|
{"op":"feed","role":"price","into":["fast.series","slow.series"]},
|
|
{"op":"connect","from":"fast.value","to":"sub.lhs"},
|
|
{"op":"connect","from":"slow.value","to":"sub.rhs"},
|
|
{"op":"connect","from":"sub.value","to":"bias.signal"},
|
|
{"op":"expose","from":"bias.bias","as":"bias"}
|
|
]
|
|
```
|
|
|
|
Piping this document into `aura graph build` emits a `blueprint.json` you can
|
|
then feed to `run` / `sweep` / `mc` / `walkforward` above:
|
|
|
|
```sh
|
|
aura graph build < crossover.ops.json > crossover.bp.json
|
|
aura sweep crossover.bp.json --list-axes
|
|
```
|
|
|
|
The op kinds are `source`, `input`, `add`, `feed`, `connect`, and `expose`. See
|
|
`aura graph introspect --node <T>` for a type's exact ports and the op-script
|
|
grammar in the design ledger for the full semantics.
|
|
|
|
## Where to go deeper
|
|
|
|
- `aura <command> --help` — exhaustive, always-current flag grammar.
|
|
- `docs/design/INDEX.md` — the design ledger: architecture, invariants, the World.
|
|
- `docs/glossary.md` — canonical terminology (blueprint, family, axis, sweep /
|
|
Monte-Carlo / walk-forward, R, content-id, …).
|