Add a timescale-matched stop-regime variant #262

Closed
opened 2026-07-13 18:06:14 +02:00 by claude · 5 comments
Collaborator

The sole risk-regime variant vol{length, k} computes stop = k · Sqrt(EMA(Δ², length)) over engine cycles, i.e. m1 bars (crates/aura-std/src/stop_rule.rs). length only smooths the minute-vol estimator; the stop's timescale stays one cycle, so an H1/H4 signal cannot get a stop matched to its holding timescale except by inflating k by hand (random-walk scaling, ≈ √60 for hourly).

Empirical illustration (external 8.5-y H1-breakout matrix): vol{60, k2} vs vol{3, k2} left per-trade cost drag and trade counts nearly unchanged (the smoothing does not change the magnitude), while raising k to 6 / 12 cut the drag ∝ 1/k and the trade population by ~4× — the lever that actually matches the stop to the signal is k, which is unintuitive when the knob named length looks like a timescale.

A variant computing the vol over resampled bars (vol_tf{period_minutes, length, k}) or an ATR-style range regime would express "stop at the signal's timescale" directly. Independent of the feature, the length-smooths / k-scales semantics deserve a sentence in the glossary risk-regime entry (see also the units issue).

The sole risk-regime variant `vol{length, k}` computes `stop = k · Sqrt(EMA(Δ², length))` over engine cycles, i.e. m1 bars (`crates/aura-std/src/stop_rule.rs`). `length` only smooths the minute-vol estimator; the stop's *timescale* stays one cycle, so an H1/H4 signal cannot get a stop matched to its holding timescale except by inflating `k` by hand (random-walk scaling, ≈ √60 for hourly). Empirical illustration (external 8.5-y H1-breakout matrix): vol{60, k2} vs vol{3, k2} left per-trade cost drag and trade counts nearly unchanged (the smoothing does not change the magnitude), while raising k to 6 / 12 cut the drag ∝ 1/k and the trade population by ~4× — the lever that actually matches the stop to the signal is k, which is unintuitive when the knob named `length` looks like a timescale. A variant computing the vol over resampled bars (`vol_tf{period_minutes, length, k}`) or an ATR-style range regime would express "stop at the signal's timescale" directly. Independent of the feature, the length-smooths / k-scales semantics deserve a sentence in the glossary risk-regime entry (see also the units issue).
claude added the feature label 2026-07-13 18:06:14 +02:00
Author
Collaborator

Design reconciliation (specify)

Spec: vol-tf-stop. The issue offers two shapes ("a variant computing the vol over resampled bars (vol_tf{period_minutes, length, k}) or an ATR-style range regime"); resolutions below are derived orchestrator decisions (recorded 2026-07-14).

  • Fork: vol_tf vs ATR-style regimevol_tf{period_minutes, length, k}: the same estimator as the sole existing regime (k · √EMA(Δ², length)), computed over period_minutes buckets instead of engine cycles.
    Basis: derived — it is the minimal extension of the existing vol regime (identical semantics, one added timescale knob, so the length-smooths / k-scales reading recorded in the glossary carries over unchanged), and it directly implements the issue's own framing ("stop at the signal's timescale"); an ATR regime introduces a second estimator family (range-based) and is additive later without prejudice.
  • Fork: composite vs fused primitive → a new fused primitive node (the Resample mold: internal accumulator keyed by ctx.now() bucket, state across cycles, emit only on bucket rollover), not a GraphBuilder composition.
    Basis: derived — today's vol stop composes generic per-cycle primitives, none of which read the clock; no time-bucketing primitive exists except the OHLC-shaped Resample, so the composition cannot express wall-time bucketing; the fused node follows the proven Resample accumulator pattern and the partial-bucket-never-emitted discipline (C2 causality).
  • Fork: delta basis and emission cadence → bucket close-to-close deltas (the coarser mirror of the m1 close-to-close the existing vol stop differences), emitted once per completed bucket; between closes the node emits nothing and the downstream Firing::Any ports (Sizer, PositionManagement) hold the last pushed stop distance.
    Basis: derived — verified against the engine's push/firing model: both consumers fire every cycle off price alone and read stop_distance from the last-pushed window value, and the R-latch samples the stop only at the entry cycle, so a coarser update cadence needs zero engine changes and cannot look ahead (a bucket's value exists only after the bucket closes).
  • Scope guard (recorded, not a fork): the dissolved verbs' --stop-length/--stop-k sugar stays Vol-only by construction; vol_tf is reachable through campaign documents (the authoring surface for regimes). The default regime path stays the single-sourced vol{3, 2.0} — a new variant is reachable only by explicit opt-in.
## Design reconciliation (specify) Spec: vol-tf-stop. The issue offers two shapes ("a variant computing the vol over resampled bars (vol_tf{period_minutes, length, k}) or an ATR-style range regime"); resolutions below are derived orchestrator decisions (recorded 2026-07-14). - **Fork: vol_tf vs ATR-style regime** → `vol_tf{period_minutes, length, k}`: the same estimator as the sole existing regime (k · √EMA(Δ², length)), computed over `period_minutes` buckets instead of engine cycles. Basis: derived — it is the minimal extension of the existing vol regime (identical semantics, one added timescale knob, so the `length`-smooths / `k`-scales reading recorded in the glossary carries over unchanged), and it directly implements the issue's own framing ("stop at the signal's timescale"); an ATR regime introduces a second estimator family (range-based) and is additive later without prejudice. - **Fork: composite vs fused primitive** → a new fused primitive node (the `Resample` mold: internal accumulator keyed by `ctx.now()` bucket, state across cycles, emit only on bucket rollover), not a `GraphBuilder` composition. Basis: derived — today's vol stop composes generic per-cycle primitives, none of which read the clock; no time-bucketing primitive exists except the OHLC-shaped `Resample`, so the composition cannot express wall-time bucketing; the fused node follows the proven `Resample` accumulator pattern and the partial-bucket-never-emitted discipline (C2 causality). - **Fork: delta basis and emission cadence** → bucket close-to-close deltas (the coarser mirror of the m1 close-to-close the existing vol stop differences), emitted once per completed bucket; between closes the node emits nothing and the downstream `Firing::Any` ports (Sizer, PositionManagement) hold the last pushed stop distance. Basis: derived — verified against the engine's push/firing model: both consumers fire every cycle off price alone and read `stop_distance` from the last-pushed window value, and the R-latch samples the stop only at the entry cycle, so a coarser update cadence needs zero engine changes and cannot look ahead (a bucket's value exists only after the bucket closes). - **Scope guard (recorded, not a fork):** the dissolved verbs' `--stop-length/--stop-k` sugar stays Vol-only by construction; `vol_tf` is reachable through campaign documents (the authoring surface for regimes). The default regime path stays the single-sourced `vol{3, 2.0}` — a new variant is reachable only by explicit opt-in.
Author
Collaborator

Spec auto-signed (specify Step 6, autonomous run)

Spec: vol-tf-stop (a second risk-regime variant vol_tf{period_minutes, length, k} computing the same vol estimator over completed time buckets — a new fused stop primitive in the Resample mold; emission on bucket rollover only, downstream holds by firing semantics; default regime and stored Vol documents byte-untouched).

The signature is the Step-5 grounding-check PASS — nine load-bearing assumption clusters ratified against currently-green tests, including the Ema seeding semantics that anchor the vol_tf{1} ≡ vol correspondence pin (report in the session transcript). No human signed; the fork decisions live at issues/262#issuecomment-3538. Status: design settled, spec signed — proceeding to implementation planning.

## Spec auto-signed (specify Step 6, autonomous run) Spec: vol-tf-stop (a second risk-regime variant `vol_tf{period_minutes, length, k}` computing the same vol estimator over completed time buckets — a new fused stop primitive in the Resample mold; emission on bucket rollover only, downstream holds by firing semantics; default regime and stored Vol documents byte-untouched). The signature is the Step-5 grounding-check PASS — nine load-bearing assumption clusters ratified against currently-green tests, including the Ema seeding semantics that anchor the vol_tf{1} ≡ vol correspondence pin (report in the session transcript). No human signed; the fork decisions live at `issues/262#issuecomment-3538`. Status: design settled, spec signed — proceeding to implementation planning.
Author
Collaborator

Design reconciliation, planning-stage addendum (2026-07-14): plan recon exposed a manifest round-trip hole the spec had not scoped — the member-manifest stamp is if let StopRule::Vol (stamping stop_length/stop_k) and the reproduce-path re-derive reconstructs only Vol, so a VolTf member would stamp nothing and aura reproduce would silently fall back to the default Vol stop. Derived decision: in scope — the stamp gains a VolTf arm (stop_period_minutes/stop_length/stop_k) and the re-derive reconstructs VolTf whenever stop_period_minutes is present. Basis: the C1 reproducibility discipline (a stored member re-runs as it ran); a silent default fallback is the exact wrong-without-error class this whole batch has been closing. Also scoped in as mechanical record-reality prose: the two further sole-variant/slot-label doc sites (authoring guide, design ledger) update alongside the glossary. Spec amended and re-gated before planning.

Design reconciliation, planning-stage addendum (2026-07-14): plan recon exposed a manifest round-trip hole the spec had not scoped — the member-manifest stamp is `if let StopRule::Vol` (stamping stop_length/stop_k) and the reproduce-path re-derive reconstructs only Vol, so a VolTf member would stamp nothing and `aura reproduce` would silently fall back to the default Vol stop. Derived decision: in scope — the stamp gains a VolTf arm (stop_period_minutes/stop_length/stop_k) and the re-derive reconstructs VolTf whenever stop_period_minutes is present. Basis: the C1 reproducibility discipline (a stored member re-runs as it ran); a silent default fallback is the exact wrong-without-error class this whole batch has been closing. Also scoped in as mechanical record-reality prose: the two further sole-variant/slot-label doc sites (authoring guide, design ledger) update alongside the glossary. Spec amended and re-gated before planning.
Author
Collaborator

Re-attestation: the manifest-round-trip amendment recorded in issues/262#issuecomment-3541 was re-run through the grounding gate on the final spec bytes — PASS (the stamp/re-derive shapes ratified by the non-gated synthetic reproduce sentinel plus the archive-gated regime-stamp e2es; the three prose sites verified byte-current). The signature of issues/262#issuecomment-3540 stands on the amended spec.

Re-attestation: the manifest-round-trip amendment recorded in `issues/262#issuecomment-3541` was re-run through the grounding gate on the final spec bytes — PASS (the stamp/re-derive shapes ratified by the non-gated synthetic reproduce sentinel plus the archive-gated regime-stamp e2es; the three prose sites verified byte-current). The signature of `issues/262#issuecomment-3540` stands on the amended spec.
Author
Collaborator

Second plan-defect note for the audit trail (2026-07-14): the vol-tf plan's executor-arm code sample contradicted its own mirror-the-Fixed-arm instruction — it showed a bare g.add(VolTfStop::new(..)), which does not satisfy GraphBuilder::add's Into<BlueprintNode> bound; the real Fixed arm is a builder().bind(..) chain. The loop shipped the node slice (committed as the first #262 slice) and blocked the arm task on the contradiction; the plan is corrected to the builder+bind form and the remaining tasks re-run. The node's unit-test harness snippet was likewise adapted by the implementer to the crate's real eval-harness idiom under the plan's own fallback clause — assertions unchanged, hand-verified.

Second plan-defect note for the audit trail (2026-07-14): the vol-tf plan's executor-arm code sample contradicted its own mirror-the-Fixed-arm instruction — it showed a bare `g.add(VolTfStop::new(..))`, which does not satisfy `GraphBuilder::add`'s `Into<BlueprintNode>` bound; the real Fixed arm is a `builder().bind(..)` chain. The loop shipped the node slice (committed as the first #262 slice) and blocked the arm task on the contradiction; the plan is corrected to the builder+bind form and the remaining tasks re-run. The node's unit-test harness snippet was likewise adapted by the implementer to the crate's real eval-harness idiom under the plan's own fallback clause — assertions unchanged, hand-verified.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Brummel/Aura#262