| Rule | Threshold | Observed (30d) | Fires |
|---|---|---|---|
| expectancy per probe | > 0 bp | +18.35 bp | clear |
| TP1 capture rate | ≥ 40% | 45.00% | clear |
| win rate | ≥ 40% | 45.00% | clear |
| sample size | ≥ 30 trades | 20 | need more |
| Reason | n | % | Maker/Taker |
|---|---|---|---|
| TP2 | 3 | 15% | maker |
| TRAIL_STOP | 1 | 5% | taker |
| BE_STOP | 5 | 25% | taker |
| SL | 5 | 25% | taker |
| KILL_STRUCT_BREAK_4H | 5 | 25% | taker |
| SCRATCH_MILD | 1 | 5% | taker |
| TIMEOUT_FLAT | 0 | 0% | — |
| Pass | RSI (ovr/trig) | ret_4h filter | n | TP1 | WR | exp (bp) | Verdict |
|---|---|---|---|---|---|---|---|
| v1 | 30 / 35 | ≥ −6% | 53 | 17.0% | 17.0% | −60.1 | DISABLE |
| v2 | 30 / 35 | ≥ −6% | 144 | 27.1% | 31.9% | −43.7 | DISABLE |
| v3 | 25 / 32 | ≥ −6% | 81 | 29.6% | 33.3% | −16.6 | DISABLE |
| v4 ★ | 22 / 30 | [−8%, −1%] | 20 | 45.0% | 45.0% | +18.4 | POSITIVE |
| v5 sens | 24 / 32 | [−8%, −1%] | 26 | 34.6% | 34.6% | −11.9 | DISABLE |
| Arm | n | TP1 | Exp (bp) | Verdict |
|---|---|---|---|---|
| CDV baseline (taker, 45-120m) | 10,444 | 0.3-1.2% | ~−19 | DISABLE |
| CDV probe-press | 251 | 40.6% | −13.8 | DISABLE |
| CDV probe-harvest (taker) | 1,358 | 37.2% | −34.4 | DISABLE |
| CDV probe-harvest + maker | 2,243 | 33.2% | −19.7 | DISABLE |
| CDV confirmed-only (pre-entry gate) | 103 | 31.1% | −21.2 | DISABLE |
| OFI continuation (1m microstructure) | 112 | 15.2% | −19.2 | DISABLE |
| Swing RSI capitulation (4-24h) | 20 | 45.0% | +18.4 | POSITIVE |
| Step | Actor | Action | Cadence |
|---|---|---|---|
| 1 | Bot | Market scan — OHLCV, trend data, symbol stats, volatility, spread/liquidity | continuous |
| 2 | LLM 1 | Regime verdict · allow_trading flag · allow_symbols list | every 4h |
| 3 | LLM 2 | Build trade ideas only for allowed symbols | on candidate signal |
| 4 | LLM 3 | Filter weak / duplicate ideas, set size | on each idea |
| 5 | LLM 4 | Convert approved idea into exact order plan | on approval |
| 6 | Bot | Place order · manage fills · manage stops · manage TP · cancel if invalid | live, no LLM |
| 7 | LLM 5 | Score the trade · update symbol / setup / regime quality | after exit + weekly roll-up |
python openclaw_v1/spot_aggro/llm_sequence/run_sequence.py status · smoke · cycle · reviewruntime/llm_sequence/runs/*.json| # | Check | Pass when |
|---|---|---|
| 1 | Higher highs | price still making HH on recent bars |
| 2 | Higher lows | price still making HL on recent bars |
| 3 | Buy pressure | buyers still stronger than sellers |
| 4 | No rejection | no sharp rejection candle / no breakdown |
| Leg | Size | Condition |
|---|---|---|
| Probe | $5 | entry fills (maker-only) |
| Add 1 | $3 | only when trade is confirmed |
| Add 2 | $2 | only when trade is still strong after TP1 zone or breakout continuation |
| # | Action | Trigger |
|---|---|---|
| 1 | Enter with $5 (probe) | signal + maker fill |
| 2 | Add $3 if trade looks strong | confirmation |
| 3 | Add $2 if still strong | TP1 zone / breakout continuation |
| 4 | At +1.50%, sell 60% | TP1 hit |
| 5 | Move stop to breakeven / small profit | right after TP1 |
| 6 | At +2.00%, sell 25% | TP2 hit |
| 7 | Let last 15% run with 0.50% trailing stop | post-TP2 if strength filter passes |
| 8 | If strength disappears, exit immediately | any time <3 of 4 strength checks |
| # | Check | Pass rule | If fails |
|---|---|---|---|
| 1 | Price direction agreement | Both exchanges moving same way | skip |
| 2 | Order book agreement | Both books support the same side | skip |
| 3 | Divergence check | OKX moving AND CDC moving same direction | skip (fake move) |
| Step | Actor | Action |
|---|---|---|
| 1 | OKX | scan for setup |
| 2 | Crypto.com | confirm (direction + book + divergence) |
| 3 | Gate | pass / fail |
| 4 | OKX | execute maker entry |
| 5 | Crypto.com | monitor divergence while in trade |
| 6 | Bot | exit / blacklist if mismatch grows |
| Constraint | Value | Implication |
|---|---|---|
| Market-data WS channel | separate from user WS | Run on its own connection, not mixed with order-side traffic |
| Subscription limit | 400 per connection | Stay under 400 symbols × channels; shard if needed |
| Heartbeat requirement | reply every 30 s | Dedicated heartbeat handler — do not share with execution loop |
| Role | dedicated confirmation service | Isolate from execution path; pause = skip, not block |
runtime/backtest/cache/cdc_*_1m.json) and data_puller.fetch_cdc_candles
is already implemented. Not yet wired into the swing-rsi live gate — the current backtest
runs with pull_cdc=False. Next step: enable CDC fetch in the simulator, add the
3-check entry gate, and re-run 90d validation. WebSocket live-gate layer
(divergence monitoring while in trade) is a separate phase.
| Verdict | Effect | Ack required |
|---|---|---|
| APPROVE_NEXT_LAYER | advance to next maturity state | YES |
| APPROVE_SCALE_UP | MICRO_LIVE → APPROVED_FOR_SCALE | YES |
| HOLD_CURRENT_LAYER | stay, no state change | no |
| REJECT_AND_REWORK | send back to research/test | no |
| FREEZE_STRATEGY | any → FROZEN (pause) | YES |
| DISABLE_LIVE | any → DISABLED (hard stop) | YES |
| ROLLBACK_TO_SAFE_MODE | any → ROLLED_BACK | YES |
| Artifact | L1 → Paper | L2 → Micro-live | L3 → Scale | Safety |
|---|---|---|---|---|
| canonical_config | ✓ | ✓ | ✓ | — |
| run_manifest | ✓ | ✓ | ✓ | — |
| test_report | ✓ | ✓ | ✓ | — |
| governance_verdict | ✓ | ✓ | ✓ | — |
| tripwire_sheet | ✓ | — | ✓ | ✓ |
| incident_log | — | ✓ | ✓ | ✓ |
| audit_trail | — | ✓ | ✓ | — |
| exchange_divergence_report | — | ✓ | — | ✓ |
| symbol_risk_report | — | — | ✓ | — |
| scale_recommendation | — | — | ✓ | — |
| rollback_record | — | — | — | ✓ |
| Failure | Proposed L0 verdict |
|---|---|
| test_l1_fail | REJECT_AND_REWORK |
| test_l2_fail | REJECT_AND_REWORK |
| test_l3_fail | ROLLBACK_TO_SAFE_MODE |
| exchange_feed_drift | FREEZE_STRATEGY |
| okx_cdc_disagreement | FREEZE_STRATEGY |
| orphan_position | DISABLE_LIVE |
| duplicate_orders | DISABLE_LIVE |
| tripwire_breach_hard | DISABLE_LIVE |
| daily_loss_cap_hit | HOLD_CURRENT_LAYER |
| live_paper_drift_high | ROLLBACK_TO_SAFE_MODE |
python openclaw_v1/spot_aggro/governance_l0/run_governance.py --strategy swing_rsi {status|propose|demo|approve|hold|reject|freeze|disable|rollback|verify}runtime/governance_l0/artifacts/ and runtime/governance_l0/verdicts/events.trade_opened(...).
events.trade_closed(...).
10800s.
Shows last 3h · today (UTC) · since start · WR · best/worst symbol · exit distribution.
runtime/notifier/openclaw_v1.spot_aggro.notifier.events and call
trade_opened() on every fill and trade_closed() on every exit.
That's the only change needed — the notifier owns Telegram + event log + PnL loop.
All calls are best-effort (never raise) and fail-open (Telegram failure doesn't block the bot).
safety.py still applies: max gross $1000 across all positionslocalStorage for convenience. To apply them to the executor,
run the CLI command or download the JSON and drop it in runtime/live_executor/.
| Event | Trigger | Message |
|---|---|---|
| 😴 Sleep | Kernel-Power event 42 | "Laptop entering sleep" + network/power/executor state |
| ⏰ Wake | Kernel-Power event 107 | "Laptop woke from sleep" + current executor state |
| ⚠️ Crash | Kernel-Power event 41 | "Unexpected shutdown detected" (ran on next boot) |
| 📡 Network | NIC state change (heartbeat detects) | "Network went DOWN / came back up" |
| 🌐 Internet | ping 1.1.1.1 fails / recovers | "Internet unreachable / reachable again" |
| 🔋 DC | Unplugged from AC | "Switched to battery" — sleep may override powercfg on low battery |
| 🔌 AC | Reconnected to AC | "Back on AC power" |
| 💓 Heartbeat | Every ~3h | "Host heartbeat — all checks ok" |
| 🤖 Executor state | Scheduled Task state change | "Executor task state changed Running → Ready" (etc) |
FLIP to confirm. Auto-reads AUTHORIZATION_PHRASE from run_live.py — you never paste it.
FLIP TO LIVE — Swing RSI.lnk
FLIP TO DRY-RUN — Swing RSI.lnk
EMERGENCY STOP — Swing RSI.lnk
PAUSED flag file the executor reads before every probe.
Fires Telegram.
PAUSE — Swing RSI.lnk
RESUME — Swing RSI.lnk
50102 Timestamp request expired — your clock drifted past OKX's 30s window.
Triggers a UAC prompt (needs admin), runs, verifies offset, then exits.
FIX CLOCK — Swing RSI.lnk · script: Fix-SystemClock.ps1
State: Running but the Python
child has actually died (e.g. Ctrl-C / 0xC000013A). Heartbeat only caught it every 5 min
by TaskState; Governor checks the actual Python PID from the wrapper log.
| # | Check | Fail behavior |
|---|---|---|
| 1 | Task exists | Diagnose TASK_MISSING + Telegram |
| 2 | PAUSED flag absent | Pause = intentional; governor does nothing |
| 3 | Task State = Running | Diagnose TASK_NOT_RUNNING |
| 4 | Python PID from wrapper log alive | Diagnose PYTHON_DEAD |
| 5 | Wrapper log age < 6 min | Diagnose WRAPPER_STALE |
| 6 | Internet reachable (ping 1.1.1.1) | Skip heal; wait for network |
| Streak | Action |
|---|---|
| 1 | Start-ScheduledTask |
| 2 | Stop → Start |
| 3+ | Stop → purge orphan python procs → Start |
⚫ Governor: giving up for 1 hour and holds off further heals — prevents restart
storms when a deeper problem is loose.
| Trigger | Message |
|---|---|
| healed (streak 1-2) | 🟡 Governor: auto-healed executor |
| healed (streak 3+) | 🔴 Governor: repeated heals — 3× |
| heal raised | ❌ Governor: heal FAILED |
| healthy after outage | 🟢 Governor: executor healthy again |
| budget exhausted | ⚫ Governor: giving up for 1 hour |
| no internet | 📡 Governor: internet unreachable |
Start-ScheduledTask fired → task back to Running → Telegram
🟡 auto-healed sent. End-to-end ✓.
Governor-Executor.ps1 ·
Task: SwingRsiGovernor ·
Audit: runtime/live_executor/logs/governor_YYYY-MM-DD.log ·
State: runtime/live_executor/governor_state.json
| Task | Purpose | Trigger |
|---|---|---|
SwingRsiExecutor | Main executor (DryRun default) | at logon + on demand |
SwingRsiExecutorWatchdog | Restarts main if stale > 10 min | every 5 min |
SwingRsiHealth_Sleep | Telegram on sleep | Kernel-Power event 42 |
SwingRsiHealth_Wake | Telegram on wake | Kernel-Power event 107 |
SwingRsiHealth_Crash | Telegram on crash-boot | Kernel-Power event 41 |
SwingRsiHealth_Heartbeat | Network/power/executor diff + periodic alive ping | every 5 min |
runtime/live_executor/logs/health_YYYY-MM-DD.log ·
heartbeat_YYYY-MM-DD.log ·
wrapper_YYYY-MM-DD.logruntime/live_executor/health_state.json (previous values for change detection)openclaw_v1/spot_aggro/live_executor/deploy/windows/*.ps1
| 4H trend | bullish |
| 1H RSI zone | 38-45 (aggro 35-38) |
| 1H close | strong (upper third) |
| invalidation | no breakdown under prev low |
| reject | if RSI already rebounded >52 in last 3 bars |
| 4H structure | bullish |
| breakout | 24h high × 1.025 in last 12h |
| retest zone | prior 24h high ±0.5% |
| 1H RSI | 45-55, turning up |
| retest holds | low ≥ prior_24h_high × 0.995 |
| price vs 80-bar SMA | must be above |
| ret_48h (1H) | ≥ −2% |
| last 1H upper wick | < 2% of close |
| 1H RSI (proxy for 4H) | ≥ 40 |
| Probe | $0.13 |
| Add 1 | $0.08 (on confirmation) |
| Add 2 | $0.05 (on continuation) |
| Max assembled | $0.26 |
| TP1 | +1.5% · sell 60% |
| TP2 | +2.0% · sell 25% |
| Runner | 15% · trail 0.5% below high |
| Hard SL | −0.8% |
| Hold | 1H: 6-24h · 4H: 1-3 days |
| Layer | v5 status | Note |
|---|---|---|
| Universe (20 syms) | LIVE | run_live.py UNIVERSE |
| Setup A predicate | LIVE | 1H-native in signal_loop.evaluate_signal |
| Setup B predicate | LIVE | 1H-native breakout+retest |
| Direction filter | LIVE | 1H-native proxy (80-SMA + ret_48h + wick + RSI) |
| OKX candle fetch | LIVE | switched from 1m to 1H bars · 300 × 1H = 12.5d |
| Sizing $0.13/$0.08/$0.05 | PARTIAL | Probe from user_config.json ($5/$3/$2 default); adjust via Per-Trade Notional card |
| TP1 +1.5% take 60% · BE entry+0.20% | LIVE | order_manager.py · v5 constants |
| TP2 +2.0% take 25% (of total) | LIVE | _take_tp2_partial() added; leaves 15% runner |
| Runner 15% · trail 0.5% below high | LIVE | Trail arms on TP2 hit; TRAIL_GIVEBACK_PCT=0.005 |
| Hard SL −0.8% | LIVE | SL_PCT=-0.008 |
| Fast-kill 2-of-4 | LIVE | _evaluate_fast_kill() · 4 triggers × 6-min window · pre-TP1 only |
| Full 4H aggregation (simulator) | LIVE | simulator_swing_v5.py predicates from 1m cache |
| Full 4H backtest runner | LIVE | run_swing_v5.py · results in v5 Backtest card below |
| Symbol blacklist | PENDING | v5 strike rules per spec — next pass |
FLAT_TIME_EXIT_MIN=60 (was 18)
+ 3 guards (price<entry AND no-reclaim AND weak-momentum). All other v6 settings held constant
(TP1 +0.8% / TP2 +1.4% / SL −1.0% / fast-kill 8min / Setup A 40-48 / Setup B 1.5% / 1.0%).
| Metric | v5 | v6 | v7 | v6→v7 |
|---|---|---|---|---|
| n trades | 61 | 103 | 101 | flat |
| Trades/day (9-sym) | 0.76 | 1.29 | 1.26 | flat ✓ |
| TP1 capture | 21.3% | 15.5% | 40.6% | +25.1 pp ✓ |
| TP2 capture | 9.8% | 6.8% | 17.8% | +11.0 pp ✓ |
| Win rate | 21.3% | 15.5% | 40.6% | +25.1 pp ✓ |
| Setup A fires | 61 | 103 | 101 | |
| Setup B fires | 0 | 0 | 0 | freeze — no breakouts in cache |
| Expectancy (bp/probe) | −41.0 | −18.3 | −18.8 | flat ✗ |
| Total PnL | −$0.0325 | −$0.0245 | −$0.0247 | flat |
| Reason | v5 % | v6 % | v7 % | v6→v7 |
|---|---|---|---|---|
| FLAT_TIME_EXIT | — | 55% | 13% | −42 pp ✓ |
| SL | 57% | 8% | 25% | +17 pp (trades held longer hit SL) |
| BE_STOP | 11% | 9% | 23% | +14 pp (more reaching BE) |
| TRAIL_STOP | 10% | 7% | 18% | +11 pp (more runners) |
| FAST_KILL | 21% | 21% | 21% | unchanged ✓ |
runtime/backtest/runs/1776730155920_v5_swing.json
okx_client.py — REST + HMAC auth, dry_run default, audit logsignal_loop.py — 1m candle poll, swing_rsi evaluator (reuses sim predicate)order_manager.py — probe/add1/add2, TP1 maker (60%), TP2 / trail / SL takersafety.py — $1000 gross cap, −$3 daily cap, −$15 session hard-disable, 5 concurrent max, 120s per-symbol cooldownrun_live.py — CLI: status · dry-run · live --authorize "…"HOST_247.md — VPS setup + systemd unit + watchdog + kill-switch| Cap | Value | Behavior |
|---|---|---|
| max gross exposure | $1000 | new entries refused if total open notional would exceed |
| daily loss cap | −$3 | all new entries blocked until next UTC day (open positions managed) |
| session hard-disable | −$15 | full shutdown + flatten-on-exit |
| max concurrent positions | 5 | 6th entry refused |
| per-symbol cooldown | 120s | no re-entry same symbol within 2 min |
| flatten on exit | ON | SIGINT/SIGTERM → cancel all + market-sell positions |
run_live.py will NOT place real orders unless you pass --live --authorize "…"
with the exact phrase below. Default is dry-run.
run_live.py constant AUTHORIZATION_PHRASE on the host>" \openclaw_v1/spot_aggro/live_executor/run_live.py as
the constant AUTHORIZATION_PHRASE. It is intentionally
not published in this public panel. Edit that constant to rotate.
deploy/bootstrap.sh — one-shot Ubuntu VPS bootstrapdeploy/swing-rsi-executor.service — systemd unit (DRY-RUN default)deploy/watch-executor.sh — 5-min watchdog + Telegram alertsdeploy/env.example — all required env varsRUNBOOK.md — exact 10-step launch sequenceGAPS.md — v1 limitations, honestlyHOST_247.md — manual setup notesruntime/live_executor/logs/dry_run_YYYY-MM-DD.jsonl,
live_YYYY-MM-DD.jsonl,
safety_state.jsonopenclaw_v1/spot_aggro/backtest/simulator_swing_horizon.py