From f35ed70f72e44dfc36a5a37649bed9abbb96854b Mon Sep 17 00:00:00 2001 From: DBarr3 <143002219+DBarr3@users.noreply.github.com> Date: Wed, 12 Aug 2026 08:50:02 -0400 Subject: [PATCH] feat(library): add event_volatility macro-event strategy corpus 11 new source/IR pairs for red-folder release trading: - event_impulse_pullback_long/short - reaction-only continuation - cpi_impulse_pullback_long/short - release-aware twin-armed trap - event_false_first_move_long/short - failed-break reversal - event_second_leg_long/short - compression-then-break continuation - event_liquidity_halt / event_release_integrity_halt / event_whipsaw_halt - PAUSE-only event controls All entries stay inside the baseline v0.1.0 subset and compile to byte-stable 0.1.0 IR via compile_to_dict(). Adds the macro-event signal contract (docs/event_signal_contract.md), library README signal tables, execution tests for twin-arm mutual exclusivity, entry-window gating, and the integrity halt. Co-Authored-By: Claude Fable 5 --- .github/ISSUE_TEMPLATE/strategy-library.yml | 1 + README.md | 6 +- docs/event_signal_contract.md | 108 ++++++++++++++++++ nano/library/README.md | 28 ++++- .../cpi_impulse_pullback_long.nano | 43 +++++++ .../cpi_impulse_pullback_long_ir.json | 19 +++ .../cpi_impulse_pullback_short.nano | 38 ++++++ .../cpi_impulse_pullback_short_ir.json | 19 +++ .../event_false_first_move_long.nano | 39 +++++++ .../event_false_first_move_long_ir.json | 18 +++ .../event_false_first_move_short.nano | 36 ++++++ .../event_false_first_move_short_ir.json | 18 +++ .../event_impulse_pullback_long.nano | 41 +++++++ .../event_impulse_pullback_long_ir.json | 17 +++ .../event_impulse_pullback_short.nano | 35 ++++++ .../event_impulse_pullback_short_ir.json | 17 +++ .../event_liquidity_halt.nano | 33 ++++++ .../event_liquidity_halt_ir.json | 11 ++ .../event_release_integrity_halt.nano | 32 ++++++ .../event_release_integrity_halt_ir.json | 11 ++ .../event_second_leg_long.nano | 38 ++++++ .../event_second_leg_long_ir.json | 17 +++ .../event_second_leg_short.nano | 33 ++++++ .../event_second_leg_short_ir.json | 17 +++ .../event_volatility/event_whipsaw_halt.nano | 33 ++++++ .../event_whipsaw_halt_ir.json | 11 ++ tests/test_library.py | 67 +++++++++++ 27 files changed, 782 insertions(+), 4 deletions(-) create mode 100644 docs/event_signal_contract.md create mode 100644 nano/library/event_volatility/cpi_impulse_pullback_long.nano create mode 100644 nano/library/event_volatility/cpi_impulse_pullback_long_ir.json create mode 100644 nano/library/event_volatility/cpi_impulse_pullback_short.nano create mode 100644 nano/library/event_volatility/cpi_impulse_pullback_short_ir.json create mode 100644 nano/library/event_volatility/event_false_first_move_long.nano create mode 100644 nano/library/event_volatility/event_false_first_move_long_ir.json create mode 100644 nano/library/event_volatility/event_false_first_move_short.nano create mode 100644 nano/library/event_volatility/event_false_first_move_short_ir.json create mode 100644 nano/library/event_volatility/event_impulse_pullback_long.nano create mode 100644 nano/library/event_volatility/event_impulse_pullback_long_ir.json create mode 100644 nano/library/event_volatility/event_impulse_pullback_short.nano create mode 100644 nano/library/event_volatility/event_impulse_pullback_short_ir.json create mode 100644 nano/library/event_volatility/event_liquidity_halt.nano create mode 100644 nano/library/event_volatility/event_liquidity_halt_ir.json create mode 100644 nano/library/event_volatility/event_release_integrity_halt.nano create mode 100644 nano/library/event_volatility/event_release_integrity_halt_ir.json create mode 100644 nano/library/event_volatility/event_second_leg_long.nano create mode 100644 nano/library/event_volatility/event_second_leg_long_ir.json create mode 100644 nano/library/event_volatility/event_second_leg_short.nano create mode 100644 nano/library/event_volatility/event_second_leg_short_ir.json create mode 100644 nano/library/event_volatility/event_whipsaw_halt.nano create mode 100644 nano/library/event_volatility/event_whipsaw_halt_ir.json diff --git a/.github/ISSUE_TEMPLATE/strategy-library.yml b/.github/ISSUE_TEMPLATE/strategy-library.yml index f963f5e..7700ef6 100644 --- a/.github/ISSUE_TEMPLATE/strategy-library.yml +++ b/.github/ISSUE_TEMPLATE/strategy-library.yml @@ -17,6 +17,7 @@ body: - volatility - volume - risk + - event_volatility - new category proposal validations: required: true diff --git a/README.md b/README.md index f4ced09..4a442e3 100644 --- a/README.md +++ b/README.md @@ -78,9 +78,9 @@ The [strategy library](nano/library/README.md) is Nano's community on-ramp: a sm The same corpus is browsable at **[aethersystems.net/nano](https://aethersystems.net/nano)** — search and filter by category, cadence or signal, read the source and compiled IR side by side, and open any strategy directly in an editor. Nothing to install, no account needed. -| Momentum | Mean reversion | Trend | Volatility | Volume | Risk | -| --- | --- | --- | --- | --- | --- | -| 4 strategies | 3 strategies | 3 strategies | 2 strategies | 2 strategies | 1 strategy | +| Momentum | Mean reversion | Trend | Volatility | Volume | Risk | Event volatility | +| --- | --- | --- | --- | --- | --- | --- | +| 4 strategies | 3 strategies | 3 strategies | 2 strategies | 2 strategies | 1 strategy | 11 strategies | The library is a conformance corpus, not a performance claim, live signal service, or trading recommendation. diff --git a/docs/event_signal_contract.md b/docs/event_signal_contract.md new file mode 100644 index 0000000..1627b06 --- /dev/null +++ b/docs/event_signal_contract.md @@ -0,0 +1,108 @@ +# Macro-event signal contract + +The `event_volatility/` library category consumes a **host event engine**: a deterministic runtime that owns the economic-release schedule, measures the post-release tape, and injects nonnegative bounded signal series into the Nano `MarketFrame`. Nano never fetches the release, never reads a clock, and never sees an order book — exactly as with every other host-provided signal. + +This document is the contract those signals must satisfy. It is written from the strategy side: what each name means, what range the host must guarantee, and which measurements must be published as separate bull/bear pairs so baseline IR (which cannot carry negative literals) can express both directions. + +## Design rules + +1. **Nonnegative and bounded.** Every score is `0..1` (or `0/1` for flags, or a nonnegative ratio where noted). Signed quantities are forbidden; a signed surprise like `CORE_SURPRISE_Z = -1.4` must be published as the pair `CPI_COOL_SCORE = 0.86` / `CPI_HOT_SCORE = 0.0`. +2. **Bull/bear pairs are mutually exclusive by construction.** The host computes both sides from the same inputs and guarantees at most one side of a pair is above its qualification threshold at any tick. +3. **Missing is missing.** A signal the host cannot compute honestly (no release packet, not enough history, feed gap) is omitted from the frame. It is never filled with 0, a neutral constant, or a stale value. Nano's missing-signal semantics then make dependent conditions unknowable, and the strategy abstains. +4. **Versioned scales.** Any threshold or normalization constant (forecast-error scale, spread-stress baseline, whipsaw normalization) is versioned in the host. It is frozen during an event window and never silently retuned between events. +5. **The `(N)` annotation convention applies.** Event signals are bare names; the host owns every window and lookback. + +## Reference points + +- **Event anchor** — median executable mid from T-10s through T-1s relative to the scheduled release time. +- **Pre-event range** — high/low of a versioned T-5m window before the release. +- **First impulse** — maximum directional excursion from the event anchor during the initial observation window. + +## Integrity and timing + +| Signal | Range | Meaning | +| --- | --- | --- | +| `EVENT_READY` | 0/1 | A scheduled high-impact event window is armed and verified. | +| `ENTRY_WINDOW_OPEN` | 0/1 | Inside the host-enforced entry window (T+5s..T+180s in v1). | +| `RELEASE_CONFIRMED` | 0/1 | The release packet status is CONFIRMED from an execution-grade source. Calendar scrapes never set this. | +| `RELEASE_CONFLICT` | 0/1 | Any integrity failure: source conflict, CONFLICTED/LATE packet, schedule disagreement, failed payload hash. | +| `RELEASE_LATENCY_SCORE` | 0..1 | 1 = timely receipt relative to the provider publication timestamp. | +| `CALENDAR_INTEGRITY` | 0..1 | Agreement between the arming calendar and the release schedule source. | +| `SECONDS_SINCE_EVENT` | ≥0 | Whole seconds since the scheduled release. | + +## Release interpretation (CPI family) + +Computed deterministically from standardized forecast errors across headline and core fields; every component is preserved separately in the evidence packet. + +| Signal | Range | Meaning | +| --- | --- | --- | +| `CPI_COOL_SCORE` | 0..1 | Cooler-than-consensus strength. Published beside `CPI_HOT_SCORE`; at most one is high. | +| `CPI_HOT_SCORE` | 0..1 | Hotter-than-consensus strength. | +| `CPI_HEADLINE_CORE_AGREEMENT` | 0..1 | Sign/magnitude agreement between headline and core surprises. | +| `CPI_REVISION_BULL_SCORE` | 0..1 | Bullish weight of prior-month revisions. | +| `CPI_REVISION_BEAR_SCORE` | 0..1 | Bearish weight of prior-month revisions. | +| `CPI_CONFLICT_SCORE` | 0..1 | Internal disagreement of the print (headline vs core vs revisions). | + +## Price reaction + +| Signal | Range | Meaning | +| --- | --- | --- | +| `UPSIDE_IMPULSE_ATR` | ≥0 | Max upward excursion from the event anchor divided by the pre-event 1m ATR. | +| `DOWNSIDE_IMPULSE_ATR` | ≥0 | Max downward excursion from the event anchor divided by the pre-event 1m ATR. | +| `IMPULSE_EFFICIENCY` | 0..1 | Net displacement divided by total path length. | +| `RETRACE_HOLD_SCORE` | 0..1 | `1 - retracement / impulse`, clamped. | +| `BREAK_FAILURE_SCORE` | 0..1 | Excursion outside the pre-event range followed by a deterministic close/reclaim back through the boundary. | +| `EVENT_ANCHOR_RECLAIM` | 0..1 | Strength of a reclaim of the event anchor from below. | +| `EVENT_ANCHOR_REJECT` | 0..1 | Strength of a rejection at the event anchor from above. | +| `SECOND_LEG_SCORE` | 0..1 | Raised only after impulse, controlled retrace, 30-90s compression, and a fresh break of the first-impulse extreme have occurred **in order**. | +| `OVERSHOOT_SCORE` | 0..1 | Excursion relative to the historical event-move distribution. | +| `VOLATILITY_COMPRESSION` | 0..1 | Contraction of realized range after the first impulse. | +| `PRE_EVENT_RANGE_BREAK_UP` | 0..1 | Upside break of the pre-event range. | +| `PRE_EVENT_RANGE_BREAK_DOWN` | 0..1 | Downside break of the pre-event range. | +| `WHIPSAW_SCORE` | 0..1 | Normalized event-anchor crossings and direction flips in the trailing observation window. 0 = one-way tape, 1 = pure churn. | + +## Liquidity and flow + +Consumed from the host's existing futures feature fabric; never rederived by the event engine. + +| Signal | Range | Meaning | +| --- | --- | --- | +| `LIQUIDITY_OK` | 0/1 | Spread and depth renormalized against the pre-event baseline. | +| `SPREAD_STRESS` | ≥0 | Executable spread relative to pre-event baseline; 0 = normal, 1+ = severe. | +| `DEPTH_COLLAPSE_SCORE` | 0..1 | Loss of top-of-book depth vs baseline. | +| `BULL_FLOW_CONFIRM` | 0..1 | Bullish futures order-flow confirmation. | +| `BEAR_FLOW_CONFIRM` | 0..1 | Bearish futures order-flow confirmation. | +| `ABSORPTION_SCORE` | 0..1 | Passive absorption of aggressive flow. | +| `QUEUE_DEPLETION_SCORE` | 0..1 | Queue consumption rate at the touch. | +| `VOLUME_ACCELERATION` | ≥0 | Volume rate vs pre-event baseline. | +| `CANCEL_STRESS` | 0..1 | Cancellation intensity vs baseline. | + +## Cross-market + +Published only when the underlying markets are genuinely live and entitled; absent otherwise. + +| Signal | Range | Meaning | +| --- | --- | --- | +| `BULL_CROSS_CONFIRM` | 0..1 | MES/MNQ and flow agreement on the upside. | +| `BEAR_CROSS_CONFIRM` | 0..1 | MES/MNQ and flow agreement on the downside. | +| `MES_MNQ_AGREEMENT` | 0..1 | Directional agreement between the two index futures. | +| `NQ_RELATIVE_STRENGTH` | 0..1 | NQ outperforming ES on the event path. | +| `NQ_RELATIVE_WEAKNESS` | 0..1 | NQ underperforming ES on the event path. | + +## Options context + +Grounding/weighting evidence only; options signals never independently create execution authority in v1. + +| Signal | Range | Meaning | +| --- | --- | --- | +| `OPTIONS_FLOW_AVAILABLE` | 0/1 | A real options evidence plane is live. | +| `OPTIONS_UNUSUAL_SCORE` | 0..100 | Deterministic unusualness score. | +| `OPTIONS_BULL_SCORE` / `OPTIONS_BEAR_SCORE` | 0..1 | Directional options positioning. | +| `OPTIONS_IV_SHOCK` | ≥0 | Pre-release IV elevation. | +| `OPTIONS_IV_CRUSH` | 0..1 | Post-release IV collapse. | +| `GAMMA_POSITIVE_SCORE` / `GAMMA_NEGATIVE_SCORE` | 0..1 | Dealer gamma regime, only with provider-backed Greeks. | +| `CALL_WALL_DISTANCE_SCORE` / `PUT_WALL_DISTANCE_SCORE` | 0..1 | Proximity to major walls. | + +## Control strategies + +`event_liquidity_halt`, `event_release_integrity_halt`, and `event_whipsaw_halt` are published Nano strategies that emit `PAUSE`. They are auditable explanations, not the only safety mechanism: the host must enforce the same gates directly, and controls are never candidates for an execution slot. diff --git a/nano/library/README.md b/nano/library/README.md index 80fc351..c68579d 100644 --- a/nano/library/README.md +++ b/nano/library/README.md @@ -11,7 +11,7 @@ Every entry has two files: ## Learn, compare, contribute -The current library contains 15 strategies across six familiar categories. Browse an entry to see the source, its expected IR, and the feed convention it assumes. When you are ready, a well-documented strategy pair is the most direct contribution to Nano. +The current library contains 26 strategies across seven familiar categories. Browse an entry to see the source, its expected IR, and the feed convention it assumes. When you are ready, a well-documented strategy pair is the most direct contribution to Nano. [Add a strategy →](../../CONTRIBUTING.md#add-a-strategy) · [Open a strategy proposal →](https://github.com/DBarr3/Nano/issues/new?template=strategy-library.yml) @@ -25,6 +25,7 @@ The current library contains 15 strategies across six familiar categories. Brows | `volatility/` | `atr_volatility_halt`, `bb_squeeze_breakout` | | `volume/` | `volume_spike_confirmation`, `obv_trend` | | `risk/` | `max_drawdown_breaker` | +| `event_volatility/` | `event_impulse_pullback_long`, `event_impulse_pullback_short`, `cpi_impulse_pullback_long`, `cpi_impulse_pullback_short`, `event_false_first_move_long`, `event_false_first_move_short`, `event_second_leg_long`, `event_second_leg_short`, `event_liquidity_halt`, `event_release_integrity_halt`, `event_whipsaw_halt` | ## Signal conventions @@ -49,6 +50,31 @@ Library entries compare **host-provided named signal series** with numeric liter | OBV trend | `OBV_SLOPE(20)` | Linear-regression slope of OBV | | equity drawdown | `DRAWDOWN` | Portfolio drawdown percentage | +### Macro-event signals (`event_volatility/`) + +Event strategies consume a **host event engine** rather than bar indicators: the host arms a scheduled release window, measures the post-release tape deterministically, and publishes nonnegative bounded scores. Bull and bear terms are always separate series (never one signed value), which is what keeps twin-armed branches mutually exclusive and inside baseline IR. The full measurement definitions live in [`docs/event_signal_contract.md`](../../docs/event_signal_contract.md). + +| Event measurement | Nano signal | Feed convention | +| --- | --- | --- | +| armed event window | `EVENT_READY` | 0 or 1; scheduled high-impact window verified | +| entry window | `ENTRY_WINDOW_OPEN` | 0 or 1; host-enforced T+5s..T+180s | +| confirmed release | `RELEASE_CONFIRMED` | 0 or 1; release packet status CONFIRMED only | +| release integrity | `RELEASE_CONFLICT` | 0 or 1; any source/hash/schedule conflict | +| cool CPI print | `CPI_COOL_SCORE` | 0..1 from standardized forecast errors | +| hot CPI print | `CPI_HOT_SCORE` | 0..1; published beside `CPI_COOL_SCORE` | +| upward impulse | `UPSIDE_IMPULSE_ATR` | max upward excursion from event anchor / pre-event 1m ATR | +| downward impulse | `DOWNSIDE_IMPULSE_ATR` | max downward excursion from event anchor / pre-event 1m ATR | +| retracement hold | `RETRACE_HOLD_SCORE` | 1 - retracement/impulse, clamped 0..1 | +| failed breakout | `BREAK_FAILURE_SCORE` | 0..1; range break then deterministic reclaim | +| range break up/down | `PRE_EVENT_RANGE_BREAK_UP` / `_DOWN` | 0..1 against the versioned T-5m range | +| anchor reclaim/reject | `EVENT_ANCHOR_RECLAIM` / `EVENT_ANCHOR_REJECT` | 0..1 at the T-10s..T-1s median mid anchor | +| second leg | `SECOND_LEG_SCORE` | 0..1; impulse, compression, then fresh extreme, in order | +| cross-market agreement | `BULL_CROSS_CONFIRM` / `BEAR_CROSS_CONFIRM` | 0..1 MES/MNQ + flow agreement | +| order-flow confirmation | `BULL_FLOW_CONFIRM` / `BEAR_FLOW_CONFIRM` | 0..1 from the host futures feature fabric | +| liquidity normalized | `LIQUIDITY_OK` | 0 or 1; spread and depth renormalized | +| spread stress | `SPREAD_STRESS` | 0 = baseline, 1+ = severely stressed | +| tape churn | `WHIPSAW_SCORE` | 0..1 normalized anchor crossings in the window | + Two v0.1 details matter: 1. Baseline IR cannot carry a negative literal. The v1.0 grammar supports unary minus, but a library entry using it would leave baseline IR — so signals with negative natural ranges are still shifted (`WILLR_POS`) or negated (`ZSCORE_NEG`) by the feed. Document the transform in a `//` comment. diff --git a/nano/library/event_volatility/cpi_impulse_pullback_long.nano b/nano/library/event_volatility/cpi_impulse_pullback_long.nano new file mode 100644 index 0000000..d8501ff --- /dev/null +++ b/nano/library/event_volatility/cpi_impulse_pullback_long.nano @@ -0,0 +1,43 @@ +// Release-aware twin-armed continuation, bull branch. Armed before CPI next +// to cpi_impulse_pullback_short; neither may open exposure before the number +// and the host's release scores make at most one branch qualify. +// RELEASE_CONFIRMED = 1 only when the MacroReleasePacket status is CONFIRMED +// from the official/vendor release adapter - never from a scraped calendar. +// CPI_COOL_SCORE = bounded 0..1 cooler-than-consensus score computed +// deterministically from standardized forecast errors across headline and +// core fields; the matching CPI_HOT_SCORE is published separately so the +// branches stay mutually exclusive (both are never high together). +// UPSIDE_IMPULSE_ATR, RETRACE_HOLD_SCORE, BULL_CROSS_CONFIRM, LIQUIDITY_OK as +// in event_impulse_pullback_long. +// REGIME: CPI releases where the print is genuinely cool AND the tape agrees. +// Do NOT fire on a cool print alone - the impulse and retrace terms must +// confirm - and do NOT fire when the release packet is missing, provisional, +// or conflicted: RELEASE_CONFIRMED stays 0 and this branch honestly abstains. +// CONDITIONS: armed event, open entry window, confirmed release, cool CPI, +// upward impulse at least 0.8 pre-event ATRs, held retracement, cross-market +// agreement, normalized liquidity. +// INVALIDATION: host event risk model owns stop, hard flat, and the +// one-position-per-event lock. +// SHAPE: 5s cadence after the observe-only impulse window; cool print, leg +// up, shallow pullback that holds, continuation. +// NOT event_impulse_pullback_long: same tape shape, but this variant demands +// execution-grade release provenance and the fundamental sign to match the +// move. When both qualify, the proposal board still selects only one. +// CALIBRATED ON: MES around US CPI, 5s cadence. The 0.72 release threshold is +// a versioned fixed scale until enough forecast-error history exists; never +// silently retune it between events. +strategy CpiImpulsePullbackLong { + + agent MacroEvent + + every 5s { + + if EVENT_READY > 0.5 and ENTRY_WINDOW_OPEN > 0.5 and RELEASE_CONFIRMED > 0.5 and CPI_COOL_SCORE > 0.72 and UPSIDE_IMPULSE_ATR > 0.8 and RETRACE_HOLD_SCORE > 0.6 and BULL_CROSS_CONFIRM > 0.55 and LIQUIDITY_OK > 0.5 { + + buy(MES, 0.78) + + } + + } + +} diff --git a/nano/library/event_volatility/cpi_impulse_pullback_long_ir.json b/nano/library/event_volatility/cpi_impulse_pullback_long_ir.json new file mode 100644 index 0000000..ba8a73d --- /dev/null +++ b/nano/library/event_volatility/cpi_impulse_pullback_long_ir.json @@ -0,0 +1,19 @@ +{ + "type": "Strategy", + "nanoIrVersion": "0.1.0", + "name": "CpiImpulsePullbackLong", + "effects": ["intent.emit", "log.append"], + "nodes": [ + { "type": "Schedule", "interval": "5s" }, + { "type": "Condition", "signal": "EVENT_READY", "operator": ">", "value": 0.5 }, + { "type": "Condition", "signal": "ENTRY_WINDOW_OPEN", "operator": ">", "value": 0.5 }, + { "type": "Condition", "signal": "RELEASE_CONFIRMED", "operator": ">", "value": 0.5 }, + { "type": "Condition", "signal": "CPI_COOL_SCORE", "operator": ">", "value": 0.72 }, + { "type": "Condition", "signal": "UPSIDE_IMPULSE_ATR", "operator": ">", "value": 0.8 }, + { "type": "Condition", "signal": "RETRACE_HOLD_SCORE", "operator": ">", "value": 0.6 }, + { "type": "Condition", "signal": "BULL_CROSS_CONFIRM", "operator": ">", "value": 0.55 }, + { "type": "Condition", "signal": "LIQUIDITY_OK", "operator": ">", "value": 0.5 }, + { "type": "Intent", "action": "BUY", "asset": "MES", "confidence": 0.78 }, + { "type": "Agent", "name": "MacroEvent" } + ] +} diff --git a/nano/library/event_volatility/cpi_impulse_pullback_short.nano b/nano/library/event_volatility/cpi_impulse_pullback_short.nano new file mode 100644 index 0000000..c91e3a8 --- /dev/null +++ b/nano/library/event_volatility/cpi_impulse_pullback_short.nano @@ -0,0 +1,38 @@ +// Release-aware twin-armed continuation, bear branch. Mirror of +// cpi_impulse_pullback_long. CPI_HOT_SCORE = bounded 0..1 +// hotter-than-consensus score from the same standardized forecast errors +// that produce CPI_COOL_SCORE; the host publishes the pair so at most one +// branch can qualify on a given print. RELEASE_CONFIRMED = 1 only when the +// MacroReleasePacket status is CONFIRMED. DOWNSIDE_IMPULSE_ATR, +// RETRACE_HOLD_SCORE, BEAR_CROSS_CONFIRM, LIQUIDITY_OK as in +// event_impulse_pullback_short. +// REGIME: CPI releases where the print is genuinely hot AND the tape agrees. +// Do NOT fire on a hot print alone, and do NOT fire when the release packet +// is missing, provisional, or conflicted - this branch abstains. +// CONDITIONS: armed event, open entry window, confirmed release, hot CPI, +// downward impulse at least 0.8 pre-event ATRs, held retracement, +// cross-market agreement, normalized liquidity. +// INVALIDATION: host event risk model owns stop, hard flat, and the +// one-position-per-event lock. +// SHAPE: 5s cadence after the observe-only impulse window; hot print, leg +// down, weak bounce that fails, continuation. +// NOT event_impulse_pullback_short: same tape shape, but this variant demands +// execution-grade release provenance and the fundamental sign to match. +// CALIBRATED ON: MES around US CPI, 5s cadence. The 0.72 release threshold is +// a versioned fixed scale until enough forecast-error history exists; never +// silently retune it between events. +strategy CpiImpulsePullbackShort { + + agent MacroEvent + + every 5s { + + if EVENT_READY > 0.5 and ENTRY_WINDOW_OPEN > 0.5 and RELEASE_CONFIRMED > 0.5 and CPI_HOT_SCORE > 0.72 and DOWNSIDE_IMPULSE_ATR > 0.8 and RETRACE_HOLD_SCORE > 0.6 and BEAR_CROSS_CONFIRM > 0.55 and LIQUIDITY_OK > 0.5 { + + sell(MES, 0.78) + + } + + } + +} diff --git a/nano/library/event_volatility/cpi_impulse_pullback_short_ir.json b/nano/library/event_volatility/cpi_impulse_pullback_short_ir.json new file mode 100644 index 0000000..9a432dc --- /dev/null +++ b/nano/library/event_volatility/cpi_impulse_pullback_short_ir.json @@ -0,0 +1,19 @@ +{ + "type": "Strategy", + "nanoIrVersion": "0.1.0", + "name": "CpiImpulsePullbackShort", + "effects": ["intent.emit", "log.append"], + "nodes": [ + { "type": "Schedule", "interval": "5s" }, + { "type": "Condition", "signal": "EVENT_READY", "operator": ">", "value": 0.5 }, + { "type": "Condition", "signal": "ENTRY_WINDOW_OPEN", "operator": ">", "value": 0.5 }, + { "type": "Condition", "signal": "RELEASE_CONFIRMED", "operator": ">", "value": 0.5 }, + { "type": "Condition", "signal": "CPI_HOT_SCORE", "operator": ">", "value": 0.72 }, + { "type": "Condition", "signal": "DOWNSIDE_IMPULSE_ATR", "operator": ">", "value": 0.8 }, + { "type": "Condition", "signal": "RETRACE_HOLD_SCORE", "operator": ">", "value": 0.6 }, + { "type": "Condition", "signal": "BEAR_CROSS_CONFIRM", "operator": ">", "value": 0.55 }, + { "type": "Condition", "signal": "LIQUIDITY_OK", "operator": ">", "value": 0.5 }, + { "type": "Intent", "action": "SELL", "asset": "MES", "confidence": 0.78 }, + { "type": "Agent", "name": "MacroEvent" } + ] +} diff --git a/nano/library/event_volatility/event_false_first_move_long.nano b/nano/library/event_volatility/event_false_first_move_long.nano new file mode 100644 index 0000000..f789bc9 --- /dev/null +++ b/nano/library/event_volatility/event_false_first_move_long.nano @@ -0,0 +1,39 @@ +// False-first-move reversal, long side. The release first breaks the +// pre-event range DOWN, the breakout fails, and price reclaims the event +// anchor with bullish flow. PRE_EVENT_RANGE_BREAK_DOWN = downside break of +// the versioned T-5m pre-event range, 0..1. BREAK_FAILURE_SCORE = excursion +// outside the range followed by a deterministic close/reclaim back through +// the boundary, 0..1. EVENT_ANCHOR_RECLAIM = reclaim strength of the event +// anchor (median executable mid, T-10s..T-1s), 0..1. BULL_FLOW_CONFIRM = +// futures order-flow confirmation from the existing feature fabric, 0..1. +// REGIME: red-folder releases where the first move traps breakout sellers - +// common on headline/core disagreement. Do NOT fire on a clean downside +// continuation; BREAK_FAILURE_SCORE and EVENT_ANCHOR_RECLAIM must both prove +// the failure first. +// CONDITIONS: armed event, open entry window, downside range break, proven +// break failure, anchor reclaim, bullish flow, normalized liquidity. +// INVALIDATION: host event risk model owns stop, hard flat, and re-entry +// lock. Losing the reclaimed anchor is the natural stop reference. +// SHAPE: 5s cadence; spike down through the pre-event low, sharp rejection, +// reclaim of anchor, then reversal higher. +// NOT event_impulse_pullback_long: that rule needs an upward first impulse; +// this one requires the first impulse to have been DOWN and to have failed. +// They cannot both qualify on the same event path. +// CALIBRATED ON: MES/MNQ around US red-folder releases, 5s cadence. +// Break/reclaim scores are range-relative and travel across index futures; +// re-verify before promotion. +strategy EventFalseFirstMoveLong { + + agent MacroEvent + + every 5s { + + if EVENT_READY > 0.5 and ENTRY_WINDOW_OPEN > 0.5 and PRE_EVENT_RANGE_BREAK_DOWN > 0.6 and BREAK_FAILURE_SCORE > 0.7 and EVENT_ANCHOR_RECLAIM > 0.6 and BULL_FLOW_CONFIRM > 0.55 and LIQUIDITY_OK > 0.5 { + + buy(MES, 0.74) + + } + + } + +} diff --git a/nano/library/event_volatility/event_false_first_move_long_ir.json b/nano/library/event_volatility/event_false_first_move_long_ir.json new file mode 100644 index 0000000..8275761 --- /dev/null +++ b/nano/library/event_volatility/event_false_first_move_long_ir.json @@ -0,0 +1,18 @@ +{ + "type": "Strategy", + "nanoIrVersion": "0.1.0", + "name": "EventFalseFirstMoveLong", + "effects": ["intent.emit", "log.append"], + "nodes": [ + { "type": "Schedule", "interval": "5s" }, + { "type": "Condition", "signal": "EVENT_READY", "operator": ">", "value": 0.5 }, + { "type": "Condition", "signal": "ENTRY_WINDOW_OPEN", "operator": ">", "value": 0.5 }, + { "type": "Condition", "signal": "PRE_EVENT_RANGE_BREAK_DOWN", "operator": ">", "value": 0.6 }, + { "type": "Condition", "signal": "BREAK_FAILURE_SCORE", "operator": ">", "value": 0.7 }, + { "type": "Condition", "signal": "EVENT_ANCHOR_RECLAIM", "operator": ">", "value": 0.6 }, + { "type": "Condition", "signal": "BULL_FLOW_CONFIRM", "operator": ">", "value": 0.55 }, + { "type": "Condition", "signal": "LIQUIDITY_OK", "operator": ">", "value": 0.5 }, + { "type": "Intent", "action": "BUY", "asset": "MES", "confidence": 0.74 }, + { "type": "Agent", "name": "MacroEvent" } + ] +} diff --git a/nano/library/event_volatility/event_false_first_move_short.nano b/nano/library/event_volatility/event_false_first_move_short.nano new file mode 100644 index 0000000..cb465df --- /dev/null +++ b/nano/library/event_volatility/event_false_first_move_short.nano @@ -0,0 +1,36 @@ +// False-first-move reversal, short side. The release first breaks the +// pre-event range UP, the breakout fails, and price rejects the event anchor +// with bearish flow. PRE_EVENT_RANGE_BREAK_UP = upside break of the versioned +// T-5m pre-event range, 0..1. BREAK_FAILURE_SCORE = excursion outside the +// range followed by a deterministic close/reclaim back through the boundary, +// 0..1. EVENT_ANCHOR_REJECT = rejection strength at the event anchor (median +// executable mid, T-10s..T-1s), 0..1. BEAR_FLOW_CONFIRM = futures order-flow +// confirmation from the existing feature fabric, 0..1. +// REGIME: red-folder releases where the first move traps breakout buyers. +// Do NOT fire on a clean upside continuation; BREAK_FAILURE_SCORE and +// EVENT_ANCHOR_REJECT must both prove the failure first. +// CONDITIONS: armed event, open entry window, upside range break, proven +// break failure, anchor rejection, bearish flow, normalized liquidity. +// INVALIDATION: host event risk model owns stop, hard flat, and re-entry +// lock. Reclaiming the rejected anchor is the natural stop reference. +// SHAPE: 5s cadence; spike up through the pre-event high, sharp rejection, +// loss of anchor, then reversal lower. +// NOT event_impulse_pullback_short: that rule needs a downward first impulse; +// this one requires the first impulse to have been UP and to have failed. +// CALIBRATED ON: MES/MNQ around US red-folder releases, 5s cadence. +// Break/reclaim scores are range-relative; re-verify before promotion. +strategy EventFalseFirstMoveShort { + + agent MacroEvent + + every 5s { + + if EVENT_READY > 0.5 and ENTRY_WINDOW_OPEN > 0.5 and PRE_EVENT_RANGE_BREAK_UP > 0.6 and BREAK_FAILURE_SCORE > 0.7 and EVENT_ANCHOR_REJECT > 0.6 and BEAR_FLOW_CONFIRM > 0.55 and LIQUIDITY_OK > 0.5 { + + sell(MES, 0.74) + + } + + } + +} diff --git a/nano/library/event_volatility/event_false_first_move_short_ir.json b/nano/library/event_volatility/event_false_first_move_short_ir.json new file mode 100644 index 0000000..853b3fb --- /dev/null +++ b/nano/library/event_volatility/event_false_first_move_short_ir.json @@ -0,0 +1,18 @@ +{ + "type": "Strategy", + "nanoIrVersion": "0.1.0", + "name": "EventFalseFirstMoveShort", + "effects": ["intent.emit", "log.append"], + "nodes": [ + { "type": "Schedule", "interval": "5s" }, + { "type": "Condition", "signal": "EVENT_READY", "operator": ">", "value": 0.5 }, + { "type": "Condition", "signal": "ENTRY_WINDOW_OPEN", "operator": ">", "value": 0.5 }, + { "type": "Condition", "signal": "PRE_EVENT_RANGE_BREAK_UP", "operator": ">", "value": 0.6 }, + { "type": "Condition", "signal": "BREAK_FAILURE_SCORE", "operator": ">", "value": 0.7 }, + { "type": "Condition", "signal": "EVENT_ANCHOR_REJECT", "operator": ">", "value": 0.6 }, + { "type": "Condition", "signal": "BEAR_FLOW_CONFIRM", "operator": ">", "value": 0.55 }, + { "type": "Condition", "signal": "LIQUIDITY_OK", "operator": ">", "value": 0.5 }, + { "type": "Intent", "action": "SELL", "asset": "MES", "confidence": 0.74 }, + { "type": "Agent", "name": "MacroEvent" } + ] +} diff --git a/nano/library/event_volatility/event_impulse_pullback_long.nano b/nano/library/event_volatility/event_impulse_pullback_long.nano new file mode 100644 index 0000000..07a2c1c --- /dev/null +++ b/nano/library/event_volatility/event_impulse_pullback_long.nano @@ -0,0 +1,41 @@ +// Reaction-only red-folder continuation. Requires no release values: the host +// event engine verifies a scheduled high-impact window (EVENT_READY), then +// measures the first post-release impulse. UPSIDE_IMPULSE_ATR = max upward +// excursion from the event anchor (median executable mid, T-10s..T-1s) +// divided by the pre-event 1m ATR. RETRACE_HOLD_SCORE = 1 - retracement / +// impulse, clamped to 0..1. BULL_CROSS_CONFIRM = deterministic MES/MNQ and +// futures-flow agreement, 0..1. ENTRY_WINDOW_OPEN = 1 only inside the +// host-enforced T+5s..T+180s entry window. LIQUIDITY_OK = 1 when spread and +// depth have renormalized. +// REGIME: scheduled macro releases (CPI, PPI, NFP, FOMC stage A) with a +// decisive first impulse that holds its retracement. Do NOT fire outside an +// armed event window - EVENT_READY and ENTRY_WINDOW_OPEN are host gates, not +// suggestions. +// CONDITIONS: armed event, open entry window, upward impulse at least 0.8 +// pre-event ATRs, at least 60 percent of the impulse held through the first +// pullback, cross-market agreement, normalized liquidity. +// INVALIDATION: host event risk model owns stop, hard flat at T+10m, and the +// one-position-per-event lock. This rule only proposes. +// SHAPE: 5s decision cadence after the observe-only impulse window; a strong +// leg up, a shallow pullback that holds, then continuation. +// NOT cpi_impulse_pullback_long: that variant additionally requires a +// CONFIRMED release packet and a cool CPI print. This one trades the tape +// reaction alone so it can run while the release adapter is unavailable. +// CALIBRATED ON: MES/MNQ around US red-folder releases, 5s cadence. Impulse +// and retrace thresholds are event-scaled (ATR-relative) and travel better +// than absolute points, but re-verify per event type before promotion. +strategy EventImpulsePullbackLong { + + agent MacroEvent + + every 5s { + + if EVENT_READY > 0.5 and ENTRY_WINDOW_OPEN > 0.5 and UPSIDE_IMPULSE_ATR > 0.8 and RETRACE_HOLD_SCORE > 0.6 and BULL_CROSS_CONFIRM > 0.55 and LIQUIDITY_OK > 0.5 { + + buy(MES, 0.78) + + } + + } + +} diff --git a/nano/library/event_volatility/event_impulse_pullback_long_ir.json b/nano/library/event_volatility/event_impulse_pullback_long_ir.json new file mode 100644 index 0000000..b69dc74 --- /dev/null +++ b/nano/library/event_volatility/event_impulse_pullback_long_ir.json @@ -0,0 +1,17 @@ +{ + "type": "Strategy", + "nanoIrVersion": "0.1.0", + "name": "EventImpulsePullbackLong", + "effects": ["intent.emit", "log.append"], + "nodes": [ + { "type": "Schedule", "interval": "5s" }, + { "type": "Condition", "signal": "EVENT_READY", "operator": ">", "value": 0.5 }, + { "type": "Condition", "signal": "ENTRY_WINDOW_OPEN", "operator": ">", "value": 0.5 }, + { "type": "Condition", "signal": "UPSIDE_IMPULSE_ATR", "operator": ">", "value": 0.8 }, + { "type": "Condition", "signal": "RETRACE_HOLD_SCORE", "operator": ">", "value": 0.6 }, + { "type": "Condition", "signal": "BULL_CROSS_CONFIRM", "operator": ">", "value": 0.55 }, + { "type": "Condition", "signal": "LIQUIDITY_OK", "operator": ">", "value": 0.5 }, + { "type": "Intent", "action": "BUY", "asset": "MES", "confidence": 0.78 }, + { "type": "Agent", "name": "MacroEvent" } + ] +} diff --git a/nano/library/event_volatility/event_impulse_pullback_short.nano b/nano/library/event_volatility/event_impulse_pullback_short.nano new file mode 100644 index 0000000..7f1fe5c --- /dev/null +++ b/nano/library/event_volatility/event_impulse_pullback_short.nano @@ -0,0 +1,35 @@ +// Bearish mirror of event_impulse_pullback_long. DOWNSIDE_IMPULSE_ATR = max +// downward excursion from the event anchor divided by the pre-event 1m ATR. +// BEAR_CROSS_CONFIRM = deterministic MES/MNQ and futures-flow agreement on +// the downside, 0..1. All signals are nonnegative host measurements; bull and +// bear terms are published separately so the two branches stay mutually +// exclusive and inspectable. +// REGIME: scheduled macro releases with a decisive first impulse lower that +// holds its retracement. Do NOT fire outside an armed event window. +// CONDITIONS: armed event, open entry window, downward impulse at least 0.8 +// pre-event ATRs, at least 60 percent of the impulse held through the first +// pullback, bearish cross-market agreement, normalized liquidity. +// INVALIDATION: host event risk model owns stop, hard flat at T+10m, and the +// one-position-per-event lock. +// SHAPE: 5s decision cadence after the observe-only impulse window; a strong +// leg down, a shallow bounce that fails, then continuation. +// NOT event_false_first_move_short: that rule sells a FAILED upside breakout; +// this one sells confirmed downside continuation. The host's mutually +// exclusive impulse terms prevent both arming on the same tape. +// CALIBRATED ON: MES/MNQ around US red-folder releases, 5s cadence. +// ATR-relative thresholds; re-verify per event type before promotion. +strategy EventImpulsePullbackShort { + + agent MacroEvent + + every 5s { + + if EVENT_READY > 0.5 and ENTRY_WINDOW_OPEN > 0.5 and DOWNSIDE_IMPULSE_ATR > 0.8 and RETRACE_HOLD_SCORE > 0.6 and BEAR_CROSS_CONFIRM > 0.55 and LIQUIDITY_OK > 0.5 { + + sell(MES, 0.78) + + } + + } + +} diff --git a/nano/library/event_volatility/event_impulse_pullback_short_ir.json b/nano/library/event_volatility/event_impulse_pullback_short_ir.json new file mode 100644 index 0000000..f2361c9 --- /dev/null +++ b/nano/library/event_volatility/event_impulse_pullback_short_ir.json @@ -0,0 +1,17 @@ +{ + "type": "Strategy", + "nanoIrVersion": "0.1.0", + "name": "EventImpulsePullbackShort", + "effects": ["intent.emit", "log.append"], + "nodes": [ + { "type": "Schedule", "interval": "5s" }, + { "type": "Condition", "signal": "EVENT_READY", "operator": ">", "value": 0.5 }, + { "type": "Condition", "signal": "ENTRY_WINDOW_OPEN", "operator": ">", "value": 0.5 }, + { "type": "Condition", "signal": "DOWNSIDE_IMPULSE_ATR", "operator": ">", "value": 0.8 }, + { "type": "Condition", "signal": "RETRACE_HOLD_SCORE", "operator": ">", "value": 0.6 }, + { "type": "Condition", "signal": "BEAR_CROSS_CONFIRM", "operator": ">", "value": 0.55 }, + { "type": "Condition", "signal": "LIQUIDITY_OK", "operator": ">", "value": 0.5 }, + { "type": "Intent", "action": "SELL", "asset": "MES", "confidence": 0.78 }, + { "type": "Agent", "name": "MacroEvent" } + ] +} diff --git a/nano/library/event_volatility/event_liquidity_halt.nano b/nano/library/event_volatility/event_liquidity_halt.nano new file mode 100644 index 0000000..231b946 --- /dev/null +++ b/nano/library/event_volatility/event_liquidity_halt.nano @@ -0,0 +1,33 @@ +// Event liquidity circuit breaker. SPREAD_STRESS = current executable spread +// relative to its pre-event baseline, 0 = normal, 1+ = severely stressed, +// computed by the host from the existing futures feature fabric (BBO +// evidence), never rederived here. +// REGIME: any armed macro event window. This is a control, not a directional +// hypothesis - it emits PAUSE and must never be promoted into the execution +// slot or counted as a setup. The host enforces the same liquidity gate +// directly; this published rule is the auditable explanation. +// CONDITIONS: none beyond the stress reading. It is armed whenever the event +// window is live. +// INVALIDATION: none - a breaker is not a trade. It releases when +// SPREAD_STRESS falls back under the threshold. +// SHAPE: 1s, because spread blowouts around a release happen and clear inside +// single seconds; a 5s control would react after the damage. +// NOT event_whipsaw_halt: that halts on direction churn of the tape; this +// halts on the cost of trading it. Both should be armed during every event. +// CALIBRATED ON: MES/MNQ around US red-folder releases. 0.8 means the spread +// is near its stressed ceiling relative to the pre-event baseline; the +// baseline normalization travels across instruments, the ceiling does not - +// re-verify per instrument class. +strategy EventLiquidityHalt { + + every 1s { + + if SPREAD_STRESS > 0.8 { + + pause() + + } + + } + +} diff --git a/nano/library/event_volatility/event_liquidity_halt_ir.json b/nano/library/event_volatility/event_liquidity_halt_ir.json new file mode 100644 index 0000000..a05938b --- /dev/null +++ b/nano/library/event_volatility/event_liquidity_halt_ir.json @@ -0,0 +1,11 @@ +{ + "type": "Strategy", + "nanoIrVersion": "0.1.0", + "name": "EventLiquidityHalt", + "effects": ["intent.emit", "log.append"], + "nodes": [ + { "type": "Schedule", "interval": "1s" }, + { "type": "Condition", "signal": "SPREAD_STRESS", "operator": ">", "value": 0.8 }, + { "type": "Intent", "action": "PAUSE" } + ] +} diff --git a/nano/library/event_volatility/event_release_integrity_halt.nano b/nano/library/event_volatility/event_release_integrity_halt.nano new file mode 100644 index 0000000..5d8d6d9 --- /dev/null +++ b/nano/library/event_volatility/event_release_integrity_halt.nano @@ -0,0 +1,32 @@ +// Release integrity circuit breaker. RELEASE_CONFLICT = 1 when the host's +// release plane detects any integrity failure: conflicting values between +// sources, a CONFLICTED or LATE MacroReleasePacket status, calendar/source +// disagreement about the schedule, or a failed payload hash check. The host +// folds every integrity failure into this single flag so the halt cannot +// miss a new failure mode. +// REGIME: any armed macro event window. Control only - emits PAUSE, never +// promoted, never counted as a setup. The host's fail-closed gates enforce +// the same rule directly; this published rule is the auditable explanation. +// CONDITIONS: none beyond the conflict flag. +// INVALIDATION: none - releases only if the host downgrades the conflict, +// which in v1 it does not do during the event window. +// SHAPE: 1s, so a conflicted release halts proposals before the first 5s +// qualify tick can act on poisoned numbers. +// NOT event_liquidity_halt: that halts on market conditions; this halts on +// data trust. A perfectly liquid tape with a conflicted release must still +// halt every release-aware branch. +// CALIBRATED ON: not calibrated - the flag is binary by contract and travels +// unchanged across all event types and instruments. +strategy EventReleaseIntegrityHalt { + + every 1s { + + if RELEASE_CONFLICT > 0.5 { + + pause() + + } + + } + +} diff --git a/nano/library/event_volatility/event_release_integrity_halt_ir.json b/nano/library/event_volatility/event_release_integrity_halt_ir.json new file mode 100644 index 0000000..5f4fa49 --- /dev/null +++ b/nano/library/event_volatility/event_release_integrity_halt_ir.json @@ -0,0 +1,11 @@ +{ + "type": "Strategy", + "nanoIrVersion": "0.1.0", + "name": "EventReleaseIntegrityHalt", + "effects": ["intent.emit", "log.append"], + "nodes": [ + { "type": "Schedule", "interval": "1s" }, + { "type": "Condition", "signal": "RELEASE_CONFLICT", "operator": ">", "value": 0.5 }, + { "type": "Intent", "action": "PAUSE" } + ] +} diff --git a/nano/library/event_volatility/event_second_leg_long.nano b/nano/library/event_volatility/event_second_leg_long.nano new file mode 100644 index 0000000..12078ee --- /dev/null +++ b/nano/library/event_volatility/event_second_leg_long.nano @@ -0,0 +1,38 @@ +// Second-leg acceleration, long side. Waits out the first impulse and its +// compression instead of paying the worst post-release spread. +// SECOND_LEG_SCORE = post-retracement extension beyond the first impulse +// extreme after a 30-90s compression, 0..1 - the host only raises it when +// impulse, controlled retrace, compression, and the fresh break have all +// occurred in order. UPSIDE_IMPULSE_ATR = first-impulse magnitude in +// pre-event 1m ATRs. BULL_FLOW_CONFIRM = futures order-flow confirmation, +// 0..1. +// REGIME: CPI, NFP, and FOMC statement legs where the real move develops +// after the first shakeout. Do NOT fire on the first impulse itself - +// SECOND_LEG_SCORE stays 0 until the compression-then-break sequence is +// complete. +// CONDITIONS: armed event, open entry window, decisive first impulse up, +// completed second-leg sequence, bullish flow, normalized liquidity. +// INVALIDATION: host event risk model owns stop, hard flat, and re-entry +// lock. Falling back inside the compression is the natural stop reference. +// SHAPE: 5s cadence; impulse up, 30-90s of compression holding most of the +// move, then a break of the first impulse high. +// NOT event_impulse_pullback_long: that rule enters on the first held +// pullback; this one requires the later break of the first-move extreme and +// therefore enters deeper into the entry window at a better-proven price. +// CALIBRATED ON: MES/MNQ around US red-folder releases, 5s cadence. +// Sequence-based score travels across event types; re-verify thresholds. +strategy EventSecondLegLong { + + agent MacroEvent + + every 5s { + + if EVENT_READY > 0.5 and ENTRY_WINDOW_OPEN > 0.5 and UPSIDE_IMPULSE_ATR > 0.8 and SECOND_LEG_SCORE > 0.7 and BULL_FLOW_CONFIRM > 0.55 and LIQUIDITY_OK > 0.5 { + + buy(MES, 0.7) + + } + + } + +} diff --git a/nano/library/event_volatility/event_second_leg_long_ir.json b/nano/library/event_volatility/event_second_leg_long_ir.json new file mode 100644 index 0000000..06a2da6 --- /dev/null +++ b/nano/library/event_volatility/event_second_leg_long_ir.json @@ -0,0 +1,17 @@ +{ + "type": "Strategy", + "nanoIrVersion": "0.1.0", + "name": "EventSecondLegLong", + "effects": ["intent.emit", "log.append"], + "nodes": [ + { "type": "Schedule", "interval": "5s" }, + { "type": "Condition", "signal": "EVENT_READY", "operator": ">", "value": 0.5 }, + { "type": "Condition", "signal": "ENTRY_WINDOW_OPEN", "operator": ">", "value": 0.5 }, + { "type": "Condition", "signal": "UPSIDE_IMPULSE_ATR", "operator": ">", "value": 0.8 }, + { "type": "Condition", "signal": "SECOND_LEG_SCORE", "operator": ">", "value": 0.7 }, + { "type": "Condition", "signal": "BULL_FLOW_CONFIRM", "operator": ">", "value": 0.55 }, + { "type": "Condition", "signal": "LIQUIDITY_OK", "operator": ">", "value": 0.5 }, + { "type": "Intent", "action": "BUY", "asset": "MES", "confidence": 0.7 }, + { "type": "Agent", "name": "MacroEvent" } + ] +} diff --git a/nano/library/event_volatility/event_second_leg_short.nano b/nano/library/event_volatility/event_second_leg_short.nano new file mode 100644 index 0000000..739abb6 --- /dev/null +++ b/nano/library/event_volatility/event_second_leg_short.nano @@ -0,0 +1,33 @@ +// Second-leg acceleration, short side. Mirror of event_second_leg_long. +// SECOND_LEG_SCORE = post-retracement extension beyond the first impulse +// extreme after a 30-90s compression, 0..1; direction is supplied by the +// impulse and flow terms, so the same sequence score serves both branches. +// DOWNSIDE_IMPULSE_ATR = first-impulse magnitude lower in pre-event 1m ATRs. +// BEAR_FLOW_CONFIRM = futures order-flow confirmation, 0..1. +// REGIME: CPI, NFP, and FOMC statement legs where the real move lower +// develops after the first shakeout. Do NOT fire on the first impulse itself. +// CONDITIONS: armed event, open entry window, decisive first impulse down, +// completed second-leg sequence, bearish flow, normalized liquidity. +// INVALIDATION: host event risk model owns stop, hard flat, and re-entry +// lock. Reclaiming the compression is the natural stop reference. +// SHAPE: 5s cadence; impulse down, 30-90s compression holding most of the +// move, then a break of the first impulse low. +// NOT event_false_first_move_short: that rule sells a failed UPSIDE breakout; +// this one sells continuation of a proven DOWNSIDE impulse after compression. +// CALIBRATED ON: MES/MNQ around US red-folder releases, 5s cadence. +// Sequence-based score travels across event types; re-verify thresholds. +strategy EventSecondLegShort { + + agent MacroEvent + + every 5s { + + if EVENT_READY > 0.5 and ENTRY_WINDOW_OPEN > 0.5 and DOWNSIDE_IMPULSE_ATR > 0.8 and SECOND_LEG_SCORE > 0.7 and BEAR_FLOW_CONFIRM > 0.55 and LIQUIDITY_OK > 0.5 { + + sell(MES, 0.7) + + } + + } + +} diff --git a/nano/library/event_volatility/event_second_leg_short_ir.json b/nano/library/event_volatility/event_second_leg_short_ir.json new file mode 100644 index 0000000..8f12fd2 --- /dev/null +++ b/nano/library/event_volatility/event_second_leg_short_ir.json @@ -0,0 +1,17 @@ +{ + "type": "Strategy", + "nanoIrVersion": "0.1.0", + "name": "EventSecondLegShort", + "effects": ["intent.emit", "log.append"], + "nodes": [ + { "type": "Schedule", "interval": "5s" }, + { "type": "Condition", "signal": "EVENT_READY", "operator": ">", "value": 0.5 }, + { "type": "Condition", "signal": "ENTRY_WINDOW_OPEN", "operator": ">", "value": 0.5 }, + { "type": "Condition", "signal": "DOWNSIDE_IMPULSE_ATR", "operator": ">", "value": 0.8 }, + { "type": "Condition", "signal": "SECOND_LEG_SCORE", "operator": ">", "value": 0.7 }, + { "type": "Condition", "signal": "BEAR_FLOW_CONFIRM", "operator": ">", "value": 0.55 }, + { "type": "Condition", "signal": "LIQUIDITY_OK", "operator": ">", "value": 0.5 }, + { "type": "Intent", "action": "SELL", "asset": "MES", "confidence": 0.7 }, + { "type": "Agent", "name": "MacroEvent" } + ] +} diff --git a/nano/library/event_volatility/event_whipsaw_halt.nano b/nano/library/event_volatility/event_whipsaw_halt.nano new file mode 100644 index 0000000..3c17a6e --- /dev/null +++ b/nano/library/event_volatility/event_whipsaw_halt.nano @@ -0,0 +1,33 @@ +// Whipsaw circuit breaker. WHIPSAW_SCORE = normalized count of event-anchor +// crossings and direction flips inside the trailing observation window, +// 0 = one-way tape, 1 = pure churn, computed deterministically by the host +// from the same executable-mid series that produces the impulse measurements. +// A tape that keeps crossing its own anchor has no continuation, no failed +// break, and no second leg to trade - every directional hypothesis degrades +// into coin flips at event spreads. +// REGIME: any armed macro event window. Control only - emits PAUSE, never +// promoted, never counted as a setup. The host enforces the same churn gate +// directly; this published rule is the auditable explanation. +// CONDITIONS: none beyond the churn reading. +// INVALIDATION: none - releases when the tape picks a side and WHIPSAW_SCORE +// decays under the threshold. +// SHAPE: 5s, matching the qualify cadence - whipsaw is a property of the +// window, not of a single second. +// NOT event_liquidity_halt: spreads can be perfectly normal while the tape +// chops; churn and cost are independent reasons to stand down. Both armed. +// CALIBRATED ON: MES/MNQ around US red-folder releases, 5s cadence. 0.7 +// tolerates the ordinary post-release shakeout but halts sustained chop; +// the anchor-crossing normalization travels across index futures. +strategy EventWhipsawHalt { + + every 5s { + + if WHIPSAW_SCORE > 0.7 { + + pause() + + } + + } + +} diff --git a/nano/library/event_volatility/event_whipsaw_halt_ir.json b/nano/library/event_volatility/event_whipsaw_halt_ir.json new file mode 100644 index 0000000..b9f0087 --- /dev/null +++ b/nano/library/event_volatility/event_whipsaw_halt_ir.json @@ -0,0 +1,11 @@ +{ + "type": "Strategy", + "nanoIrVersion": "0.1.0", + "name": "EventWhipsawHalt", + "effects": ["intent.emit", "log.append"], + "nodes": [ + { "type": "Schedule", "interval": "5s" }, + { "type": "Condition", "signal": "WHIPSAW_SCORE", "operator": ">", "value": 0.7 }, + { "type": "Intent", "action": "PAUSE" } + ] +} diff --git a/tests/test_library.py b/tests/test_library.py index 760acaf..1e110aa 100644 --- a/tests/test_library.py +++ b/tests/test_library.py @@ -27,6 +27,7 @@ "volatility", "volume", "risk", + "event_volatility", } @@ -144,6 +145,72 @@ def test_golden_cross_ignores_negative_spread(): assert result.intents[0].timestamp == 172800 +def test_cpi_twin_arms_are_mutually_exclusive(): + # The host publishes CPI_COOL_SCORE and CPI_HOT_SCORE separately so the + # bull and bear branches can never both qualify on one print. Feed one + # tape where every shared gate passes: only the branch whose release + # score is high may fire. + long_graph = _load("event_volatility/cpi_impulse_pullback_long.nano") + short_graph = _load("event_volatility/cpi_impulse_pullback_short.nano") + shared = { + "EVENT_READY": (1.0, 1.0), + "ENTRY_WINDOW_OPEN": (1.0, 1.0), + "RELEASE_CONFIRMED": (1.0, 1.0), + "RETRACE_HOLD_SCORE": (0.8, 0.8), + "LIQUIDITY_OK": (1.0, 1.0), + } + cool_print = MarketFrame( + timestamps=(0, 5), + signals={ + **shared, + "CPI_COOL_SCORE": (0.86, 0.86), + "CPI_HOT_SCORE": (0.0, 0.0), + "UPSIDE_IMPULSE_ATR": (1.4, 1.4), + "DOWNSIDE_IMPULSE_ATR": (0.1, 0.1), + "BULL_CROSS_CONFIRM": (0.7, 0.7), + "BEAR_CROSS_CONFIRM": (0.1, 0.1), + }, + ) + long_result = execute(long_graph, cool_print) + short_result = execute(short_graph, cool_print) + assert [i.action for i in long_result.intents] == ["BUY", "BUY"] + assert short_result.intents == () + + +def test_event_entry_fires_only_inside_entry_window(): + # ENTRY_WINDOW_OPEN is the host's T+5s..T+180s gate: identical impulse + # tape, but the window closes on the last tick and the rule must abstain. + graph = _load("event_volatility/event_impulse_pullback_long.nano") + frame = MarketFrame( + timestamps=(0, 5, 10), + signals={ + "EVENT_READY": (1.0, 1.0, 1.0), + "ENTRY_WINDOW_OPEN": (0.0, 1.0, 0.0), + "UPSIDE_IMPULSE_ATR": (1.2, 1.2, 1.2), + "RETRACE_HOLD_SCORE": (0.75, 0.75, 0.75), + "BULL_CROSS_CONFIRM": (0.7, 0.7, 0.7), + "LIQUIDITY_OK": (1.0, 1.0, 1.0), + }, + ) + result = execute(graph, frame) + assert [(i.action, i.timestamp) for i in result.intents] == [("BUY", 5)] + assert result.intents[0].asset == "MES" + assert result.intents[0].confidence == 0.78 + + +def test_event_release_integrity_halt_pauses_on_conflict(): + graph = _load("event_volatility/event_release_integrity_halt.nano") + frame = MarketFrame( + timestamps=(0, 1, 2), + signals={"RELEASE_CONFLICT": (0.0, 1.0, 1.0)}, + ) + result = execute(graph, frame) + assert [(i.action, i.timestamp) for i in result.intents] == [ + ("PAUSE", 1), + ("PAUSE", 2), + ] + + def test_atr_halt_emits_no_intent_in_calm_regime(): graph = _load("volatility/atr_volatility_halt.nano") frame = MarketFrame(