Files
ite-workflows/runbooks/spy-0dte-scalp.md
2026-09-01 15:33:36 -04:00

7.9 KiB
Raw Blame History

SPY 0DTE Scalp Runbook — E2E Fast Path (MARI-native)

v2 — 2026-09-01 13:45 ET. v1 built 2026-08-28 from spy-1787942969793 (closed un-filled at 3:00 wall). v2 folds in the 2026-09-01 double-failure post-mortem (spy-1788280948132, spy-1788282204586 — both discarded un-filled, zero fills, $0 cost). Lives in runbooks/ — MARI-native execution jurisdiction, NOT ICM: no stage-review gates; the platform's Arm/Enter cards are the only human gates. Per MEMORY.md RUN RULES, reading this file is the FIRST tool call of every scalp, before recon, before record — no exceptions.

The speed rule

Never discover inside a trade window. Design + record the plan BEFORE the intended entry window; arm = one pasted line. Measured 2026-09-01: prompt→ready 5m41s (two full ~700KB chain pulls + one schema retry) then ~21 min dead in the arm handoff = setup near-invalidation by ready time. Targets under this runbook: prompt→plan-ready ≤90s, prompt→armed ≈2–3 min. The Arm card click is the irreducible floor (app-owned pack preflight, safety rail) — everything else compresses.

0. T+0 gate + handshake (v2 — this failed twice before it was written down)

  • First tool call of the run = read this runbook. It must land visibly in the transcript before any recon or record call.
  • Handshake: member parks the Live Trading window OPEN + CONNECTED before saying go. The go prompt carries symbol + account, nothing else.
  • MARI never asks "which window are you in" mid-flight. If the cockpit is not connected at arm time, the window is already burning → stale-kill per §4, re-stage, don't negotiate.

1. Recon burst (≤60s, ONE parallel tool block)

  • Same block: snapshot(SPY) + ttg_trade_workflow_prepare_context + options_snapshot_chain for ONE side only — the side the snapshot's direction call already picked. Never both chains. Never a mid-flow re-pull, including at stale checks (the 9/1 re-validation pull at 12:53 was pure waste; snapshot + last known quotes answer staleness).
  • Direction call: price vs VWAP + day-low/high structure. Trend-day tape → trade the break (continuation), not the bounce. Mid-range chop → stand down. Bounce in progress toward invalidation → do NOT chase; record a CONDITIONAL plan whose entry zone only fills on a re-press (9/1: zone 0.42–0.58 on 761P after a 4-minute bounce), or stand down entirely.
  • Liquidity check (both expiries, Friday rule):
    • ttg-options → options_snapshot_chain, params: underlyingAsset: "SPY", contract_type: "put"|"call", expiration_date EXACT string "2026-09-01"-style (range objects = HTTP 500), limit: 250, sort: "strike_price".
    • 0DTE near-money: 1–2¢ spreads, 300–600K vol = elite. Next-week: premium ~$4 → +20% in 15 min needs ~$1.60 SPY move vs ~$0.30 on 0DTE. 0DTE is the 15-min vehicle; next-week is for plays/swings.
  • Vehicle pick: ATM-ish strike, delta −0.3 to −0.5 at expected trigger price, spread ≤ 2¢.

2. Record the plan (schema-exact v2, FIRST TRY)

ttg_trade_workflow_record_plan — template (validated shape, both 8/28 and 9/1):

brokerId: "tos-paper", connectedBrokerPackId: "tos-paper",
accountCode: "D-67336185"        // 185; "D-67336186" = 186
assetClass: "option", symbol: "SPY", side: "buy",
tradeStyle: "scalp",             // NOT "style"
instrumentRef: {symbol: "SPY", strike: 761, type: "put",
                expiration: "2026-09-01"},   // MUST be object, never string
levels: {
  entry: {zone: {low: 0.42, high: 0.58}, type: "limit"},  // premium zone
  stop: {offset: 0.10},            // POSITIVE number — it's a distance below fill.
                                   // 9/1 cost 45s on "-0.1": rejected, full retry cycle.
  targets: [{offset: 0.12, portionPct: 50}, {offset: 0.18, portionPct: 50}],  // max 2
  timeStopSec: 900,                // REQUIRED for scalp/day; in-trade from fill
  breakevenAfterT1: true
},
risk: {maxDollars: 20},            // engine computes qty — NEVER send qty
timeLimitSec: 600,                 // ENTRY WINDOW seconds (NOT the time stop)
rationale: "≥40 chars — SPY-level triggers, invalidations, walls, order-safety directives here"

Validation gotchas (each has cost an iteration): tradeStyle not style; no top-level entry/stop/target/qty; instrumentRef object not string; stop offset positive; engine enforces R:R > 1 — every target offset must exceed the stop offset. Response: planId spy-<epoch-ms>, status draft in PLANS/. SPY-level triggers go in rationale.

3. Arm — CONFIRMED 2026-09-01 (twice), no longer a hypothesis

  • Main-chat "arm" CANNOT fire the card. The Arm card exists ONLY in the Live Trading window's own MARI chat. Member types arm <planId> THERE → card renders → Arm click (preflight auto-runs) → Enter.
  • MARI waits via await_event (revision change), never sleep-polling; plan-ready message carries planId + the literal arm line so the paste is 5 seconds.
  • NEVER fake arming from main chat (update_plan status:"open" skips preflight/stream verify — dangerous). Main-window MARI cannot arm; the cockpit orchestrator owns execution.
  • Stale-kill: if not armed by the entry-window deadline → ttg_trade_workflow_discard_plan (verified live 3× on 9/1), stand down, never manage a dead window, never chase the bounce afterward.
  • Post-flight rule (added 9/1 14:31, after third un-armed discard): stale-kill ends the flight. Debrief question AFTER the kill, never mid-flight: was the member in the cockpit at plan-ready? (a) Yes + arm line didn't render → platform delta, fold into §3. (b) No → handshake breach: "go" means member is IN the cockpit chat at that moment. MARI never asks mid-flight, never re-stages on a spent "go" — re-stage only on the member's renewed go.
  • ARM RENDER CONFIRMED 9/1 14:38 (debrief): cockpit paste → card DID render, with lag ("eventually"). The 3rd kill was a RACE: card in flight when the deadline hit. Fix = paste-confirm handshake: plan-ready message asks for one-word reply "pasted" in MAIN chat the moment the arm line is in the cockpit chat. "Pasted" ⇒ kill deadline extends +2 min (render-lag budget: card render + Arm click + preflight). No "pasted" by deadline ⇒ kill stands, no renegotiation.
  • Card-after-kill: if the Arm card renders after a stale-kill, the plan is already discarded (discard is authoritative; verified status=draft at kill). DO NOT click Arm — dismiss/ignore the card. No orders can exist; flat is guaranteed.

4. Manage (standing protocol — member directives, encode in rationale every time)

  1. On fill: verify BOTH working and filled orders. Stop must read SELL TO CLOSE — never sell-to-open, never a short entry.
  2. T1 fills → scale stop to remaining qty (+ breakevenAfterT1 moves it to BE). T2/stop-out → cancel ALL working orders the instant flat or profit taken. Working + filled checked both after every event. No orphans, ever.
  3. Walls: timeStopSec from fill + explicit wall-clock hard flat in rationale. Bail on tape deterioration before the stop (slow grind back = failed setup).
  4. Management loop = await_event cycles at 1s belt/watcher cadence; terse timestamped updates only while the window is live.

5. Post-mortem discipline (v2)

After every e2e run — fill or not: procedure deltas fold into THIS file; MEMORY.md Lessons gets a one-line pointer only. Lessons = history + pointers. Runbook = procedure. A procedure that lives only in Lessons will lose to run momentum — verified 9/1 when the loaded lesson was ignored mid-flight.

15-min target math (10–25% premium band)

  • 0DTE ATM-ish premium P, delta Δ: +20% ≈ 0.20·P / Δ SPY move. At P≈$0.85, Δ≈−0.50 → ~$0.34 SPY. Routine in 15 min on a break.
  • Engine R:R rule forces target offset > stop offset: size stop −10 to −16% and T1 +19 to +22% to stay inside the band AND clear R:R>1 (verified combos: stop 0.18 / T1 0.20 / T2 0.40 on ~$0.84 fill; stop 0.10 / T1 0.12 / T2 0.18 on ~$0.54 mid).