@senpi/runtime 3.0.0-dev.openclaw-upgrade-mai.20260623210452 → 3.0.0-dev.runtime-phase-2.20260623210537

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/README.md +9 -10
  2. package/dist/actions/decision-engine.d.ts.map +1 -1
  3. package/dist/actions/decision-engine.js +0 -3
  4. package/dist/actions/decision-engine.js.map +1 -1
  5. package/dist/actions/open-position/open-position.action.d.ts.map +1 -1
  6. package/dist/actions/open-position/open-position.action.js +2 -6
  7. package/dist/actions/open-position/open-position.action.js.map +1 -1
  8. package/dist/cli/guide-commands.d.ts.map +1 -1
  9. package/dist/cli/guide-commands.js +56 -43
  10. package/dist/cli/guide-commands.js.map +1 -1
  11. package/dist/cli/senpi-commands.d.ts.map +1 -1
  12. package/dist/cli/senpi-commands.js +108 -0
  13. package/dist/cli/senpi-commands.js.map +1 -1
  14. package/dist/constants/dsl/index.d.ts +0 -2
  15. package/dist/constants/dsl/index.d.ts.map +1 -1
  16. package/dist/constants/dsl/index.js +0 -2
  17. package/dist/constants/dsl/index.js.map +1 -1
  18. package/dist/dsl/engine-client/config-mapping.d.ts +0 -7
  19. package/dist/dsl/engine-client/config-mapping.d.ts.map +1 -1
  20. package/dist/dsl/engine-client/config-mapping.js +2 -16
  21. package/dist/dsl/engine-client/config-mapping.js.map +1 -1
  22. package/dist/dsl/events/handlers.d.ts +2 -18
  23. package/dist/dsl/events/handlers.d.ts.map +1 -1
  24. package/dist/dsl/events/handlers.js +213 -302
  25. package/dist/dsl/events/handlers.js.map +1 -1
  26. package/dist/dsl/monitor/create-monitor.d.ts +0 -15
  27. package/dist/dsl/monitor/create-monitor.d.ts.map +1 -1
  28. package/dist/dsl/monitor/create-monitor.js +9 -44
  29. package/dist/dsl/monitor/create-monitor.js.map +1 -1
  30. package/dist/dsl/monitor/process-one-position.d.ts.map +1 -1
  31. package/dist/dsl/monitor/process-one-position.js +1 -24
  32. package/dist/dsl/monitor/process-one-position.js.map +1 -1
  33. package/dist/dsl/plugin/index.d.ts +1 -16
  34. package/dist/dsl/plugin/index.d.ts.map +1 -1
  35. package/dist/dsl/plugin/index.js +4 -35
  36. package/dist/dsl/plugin/index.js.map +1 -1
  37. package/dist/dsl/plugin/options.d.ts +0 -18
  38. package/dist/dsl/plugin/options.d.ts.map +1 -1
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +0 -4
  41. package/dist/index.js.map +1 -1
  42. package/dist/runtime/create-scanner-module.d.ts +3 -4
  43. package/dist/runtime/create-scanner-module.d.ts.map +1 -1
  44. package/dist/runtime/create-scanner-module.js +5 -14
  45. package/dist/runtime/create-scanner-module.js.map +1 -1
  46. package/dist/runtime/create-scanner-providers-for-run.d.ts.map +1 -1
  47. package/dist/runtime/create-scanner-providers-for-run.js +1 -12
  48. package/dist/runtime/create-scanner-providers-for-run.js.map +1 -1
  49. package/dist/runtime/load-runtime-config.js +1 -1
  50. package/dist/runtime/load-runtime-config.js.map +1 -1
  51. package/dist/runtime/map-strategies-registration.js +8 -7
  52. package/dist/runtime/map-strategies-registration.js.map +1 -1
  53. package/dist/runtime/map-strategies.d.ts.map +1 -1
  54. package/dist/runtime/map-strategies.js +3 -12
  55. package/dist/runtime/map-strategies.js.map +1 -1
  56. package/dist/runtime/reconcile-state.d.ts +0 -44
  57. package/dist/runtime/reconcile-state.d.ts.map +1 -1
  58. package/dist/runtime/reconcile-state.js +44 -80
  59. package/dist/runtime/reconcile-state.js.map +1 -1
  60. package/dist/runtime/risk-guard.d.ts.map +1 -1
  61. package/dist/runtime/risk-guard.js +12 -17
  62. package/dist/runtime/risk-guard.js.map +1 -1
  63. package/dist/runtime/runtime-schema.d.ts +995 -2855
  64. package/dist/runtime/runtime-schema.d.ts.map +1 -1
  65. package/dist/runtime/runtime-schema.js +40 -133
  66. package/dist/runtime/runtime-schema.js.map +1 -1
  67. package/dist/runtime/runtime.d.ts +0 -26
  68. package/dist/runtime/runtime.d.ts.map +1 -1
  69. package/dist/runtime/runtime.js +5 -233
  70. package/dist/runtime/runtime.js.map +1 -1
  71. package/dist/runtime/scanner-registry.d.ts +1 -1
  72. package/dist/runtime/scanner-registry.d.ts.map +1 -1
  73. package/dist/runtime/scanner-registry.js +12 -3
  74. package/dist/runtime/scanner-registry.js.map +1 -1
  75. package/dist/runtime/supervisor/long-running-supervisor.d.ts.map +1 -1
  76. package/dist/runtime/supervisor/long-running-supervisor.js +1 -1
  77. package/dist/runtime/supervisor/long-running-supervisor.js.map +1 -1
  78. package/dist/runtime/supervisor/orphan-sweep.js +1 -1
  79. package/dist/runtime/supervisor/orphan-sweep.js.map +1 -1
  80. package/dist/runtime/supervisor/supervisor-utils.d.ts +1 -1
  81. package/dist/runtime/supervisor/supervisor-utils.d.ts.map +1 -1
  82. package/dist/runtime/supervisor/supervisor-utils.js +1 -1
  83. package/dist/runtime/supervisor/supervisor-utils.js.map +1 -1
  84. package/dist/runtime-api/intake/intake-mount.d.ts.map +1 -1
  85. package/dist/runtime-api/intake/intake-mount.js +36 -28
  86. package/dist/runtime-api/intake/intake-mount.js.map +1 -1
  87. package/dist/runtime-api/intake/process-signal-post.d.ts.map +1 -1
  88. package/dist/runtime-api/intake/process-signal-post.js +0 -0
  89. package/dist/runtime-api/intake/process-signal-post.js.map +1 -1
  90. package/dist/runtime-api/intake/scanner-launcher.d.ts +4 -18
  91. package/dist/runtime-api/intake/scanner-launcher.d.ts.map +1 -1
  92. package/dist/runtime-api/intake/scanner-launcher.js +3 -24
  93. package/dist/runtime-api/intake/scanner-launcher.js.map +1 -1
  94. package/dist/runtime-api/intake/types.d.ts +0 -6
  95. package/dist/runtime-api/intake/types.d.ts.map +1 -1
  96. package/dist/runtime-api/routes/signals.schema.d.ts +0 -1
  97. package/dist/runtime-api/routes/signals.schema.d.ts.map +1 -1
  98. package/dist/runtime-api/routes/signals.schema.js +0 -5
  99. package/dist/runtime-api/routes/signals.schema.js.map +1 -1
  100. package/dist/scanners/external/liquidation-watchdog/README.md +107 -0
  101. package/dist/scanners/external/liquidation-watchdog/liquidation-watchdog.yaml +48 -0
  102. package/dist/scanners/external/liquidation-watchdog/producer.mjs +336 -0
  103. package/dist/scanners/external/momentum/README.md +148 -0
  104. package/dist/scanners/external/momentum/momentum.yaml +116 -0
  105. package/dist/scanners/external/momentum/producer.mjs +251 -0
  106. package/dist/scanners/external/scaffold/__main__.py +24 -65
  107. package/dist/scanners/external/scaffold/delivery.py +22 -56
  108. package/dist/scanners/external/scaffold/entrypoint_loader.py +48 -42
  109. package/dist/scanners/external/scaffold/journal.py +2 -13
  110. package/dist/scanners/external/scaffold/scaffold.py +128 -159
  111. package/dist/scanners/external/scaffold/signal_envelope.py +34 -177
  112. package/dist/scanners/external/shared/ingest.mjs +112 -0
  113. package/dist/scanners/external-scanner-receiver.d.ts +0 -6
  114. package/dist/scanners/external-scanner-receiver.d.ts.map +1 -1
  115. package/dist/scanners/external-scanner-receiver.js +1 -14
  116. package/dist/scanners/external-scanner-receiver.js.map +1 -1
  117. package/dist/scripts/run-dsl-standalone-live.d.ts +1 -1
  118. package/dist/scripts/run-dsl-standalone-live.js +3 -5
  119. package/dist/scripts/run-dsl-standalone-live.js.map +1 -1
  120. package/dist/senpi/client.d.ts +0 -12
  121. package/dist/senpi/client.d.ts.map +1 -1
  122. package/dist/senpi/client.js +2 -31
  123. package/dist/senpi/client.js.map +1 -1
  124. package/dist/state/state-manager.d.ts +0 -17
  125. package/dist/state/state-manager.d.ts.map +1 -1
  126. package/dist/state/state-manager.js +0 -28
  127. package/dist/state/state-manager.js.map +1 -1
  128. package/dist/strategy/strategy-state.d.ts.map +1 -1
  129. package/dist/strategy/strategy-state.js +1 -7
  130. package/dist/strategy/strategy-state.js.map +1 -1
  131. package/dist/tracking/constants.d.ts.map +1 -1
  132. package/dist/tracking/constants.js +0 -2
  133. package/dist/tracking/constants.js.map +1 -1
  134. package/dist/types/dsl/index.d.ts +1 -1
  135. package/dist/types/dsl/index.d.ts.map +1 -1
  136. package/dist/types/scanner.d.ts +0 -7
  137. package/dist/types/scanner.d.ts.map +1 -1
  138. package/examples/README.md +89 -0
  139. package/examples/scanners-consumer-quickstart.mjs +134 -0
  140. package/examples/scanners-emerging-movers-v4.mjs +287 -0
  141. package/examples/scanners-liquidation-watchdog.mjs +341 -0
  142. package/examples/scanners-live-mcp.mjs +208 -0
  143. package/examples/scanners-multi-strategy.mjs +165 -0
  144. package/examples/scanners-position-tracker-e2e.mjs +225 -0
  145. package/examples/scanners-scheduled-events.mjs +96 -0
  146. package/examples/scanners-senpi-provider-client.mjs +182 -0
  147. package/examples/scanners-single-strategy.mjs +198 -0
  148. package/examples/strategies/README.md +12 -17
  149. package/examples/strategies/dsl-showcase.yaml +68 -0
  150. package/examples/strategies/dsl.yaml +51 -0
  151. package/examples/strategies/fox-minimal-loosened.yaml +240 -0
  152. package/examples/strategies/fox-minimal.yaml +242 -0
  153. package/examples/strategies/minimal.yaml +46 -0
  154. package/examples/strategies/momentum/how-it-works.md +48 -0
  155. package/examples/strategies/momentum/momentum-guarded.yaml +161 -0
  156. package/examples/strategies/risk-showcase.yaml +93 -0
  157. package/examples/strategies/viper.yaml +67 -0
  158. package/examples/strategies/wolf.yaml +72 -0
  159. package/examples/yamls/sample-with-dsl-and-emerging-movers.yaml +123 -0
  160. package/package.json +1 -1
  161. package/dist/runtime/reconcile-decide.d.ts +0 -73
  162. package/dist/runtime/reconcile-decide.d.ts.map +0 -1
  163. package/dist/runtime/reconcile-decide.js +0 -166
  164. package/dist/runtime/reconcile-decide.js.map +0 -1
  165. package/dist/runtime/reconcile-run.d.ts +0 -62
  166. package/dist/runtime/reconcile-run.d.ts.map +0 -1
  167. package/dist/runtime/reconcile-run.js +0 -173
  168. package/dist/runtime/reconcile-run.js.map +0 -1
  169. package/dist/scanners/external/scaffold/ctx.py +0 -78
  170. package/dist/scanners/external/scaffold/requirements.txt +0 -11
  171. package/dist/scanners/external/scaffold/senpi_mcp.py +0 -250
  172. package/dist/scanners/external/scaffold/state_manager.py +0 -175
  173. package/dist/utils/keyed-mutex.d.ts +0 -37
  174. package/dist/utils/keyed-mutex.d.ts.map +0 -1
  175. package/dist/utils/keyed-mutex.js +0 -77
  176. package/dist/utils/keyed-mutex.js.map +0 -1
  177. package/examples/strategies/iguana/README.md +0 -135
  178. package/examples/strategies/iguana/recipe.yaml +0 -137
  179. package/examples/strategies/iguana/scanners/scan.py +0 -243
  180. package/examples/strategies/iguana/scanners/scoring.py +0 -152
  181. package/examples/strategies/raptor/README.md +0 -156
  182. package/examples/strategies/raptor/recipe.yaml +0 -154
  183. package/examples/strategies/raptor/scanners/scan.py +0 -349
  184. package/examples/strategies/raptor/scanners/scoring.py +0 -452
  185. package/examples/strategies/spider/README.md +0 -97
  186. package/examples/strategies/spider/scalp/recipe.yaml +0 -129
  187. package/examples/strategies/spider/scalp/scanners/scan.py +0 -219
  188. package/examples/strategies/spider/scalp/scanners/scoring.py +0 -179
  189. package/examples/strategies/spider/swing/recipe.yaml +0 -141
  190. package/examples/strategies/spider/swing/scanners/scan.py +0 -334
  191. package/examples/strategies/spider/swing/scanners/scoring.py +0 -184
  192. package/examples/strategies/turbine/README.md +0 -167
  193. package/examples/strategies/turbine/recipe-runners.yaml +0 -123
  194. package/examples/strategies/turbine/recipe-volume.yaml +0 -129
  195. package/examples/strategies/turbine/scanners/scan.py +0 -283
  196. package/examples/strategies/turbine/scanners/scoring.py +0 -190
@@ -0,0 +1,242 @@
1
+ name: fox-minimal
2
+ version: 1.0.0
3
+ description: >
4
+ FOX v1.6 — autonomous momentum trading via @senpi-ai/runtime.
5
+ Emerging movers detect first jumps, LLM entry filter applies the five-layer
6
+ gauntlet, DSL v5.3.1 manages trailing exits, watchdog guards margin health,
7
+ market-regime provides macro context, sm-flip detects conviction reversals.
8
+
9
+ strategy:
10
+ wallet: "${FOX_WALLET}"
11
+ slots: 1
12
+ margin_per_slot: 100
13
+ trading_risk: aggressive
14
+ enabled: true
15
+
16
+ scanners:
17
+ # References in depends_on/actions use these scanner names, not the built-in types.
18
+ # ── Primary signal: emerging movers (every 90s, matching Fox 3-min cron) ──
19
+ - name: emerging_movers
20
+ type: emerging_movers
21
+ interval: 90s
22
+ depends_on:
23
+ - scanner: market_regime
24
+ required: false
25
+ max_age: 2h
26
+ on_missing: degrade
27
+ on_stale: degrade
28
+ blocked_assets: []
29
+ config:
30
+ topN: 50
31
+ minRankJump: 5
32
+ minTopTradersGain: 0.1
33
+ minScansBeforeSignals: 2
34
+ historyLimit: 60
35
+ immediateJumpThreshold: 10
36
+ deepClimbRankThreshold: 25
37
+ contribExplosionMultiplier: 3
38
+ contribAccelThreshold: 0.003
39
+ minVelocityForDeepClimber: 0.0003
40
+ erraticReversalThreshold: 5
41
+ climbStreakScans: 3
42
+ rankClimbThreshold: 3
43
+ firstJumpMinPrevRank: 30
44
+ minLeverage: 7
45
+ blacklist: ["XPL", "kPEPE"]
46
+
47
+ # ── Macro context: BTC+ETH regime classification (every 4h) ──
48
+ - name: market_regime
49
+ type: market_regime
50
+ interval: 14400s
51
+ config:
52
+ btcWeight: 0.6
53
+ ethWeight: 0.4
54
+ emaFast: 9
55
+ emaSlow: 21
56
+ neutralThreshold: 0.3
57
+
58
+ # ── SM conviction reversal detection (every 5 min) ──
59
+ - name: sm_flip
60
+ type: sm_flip
61
+ interval: 300s
62
+ config:
63
+ minConviction: 4
64
+
65
+ # ── Margin safety net (every 5 min) ──
66
+ - name: watchdog
67
+ type: liquidation_watchdog
68
+ interval: 300s
69
+ config:
70
+ bufferWarningPct: 50
71
+ bufferCriticalPct: 30
72
+ liqDistanceWarningPct: 30
73
+ roeDangerPct: -15
74
+
75
+ # ── Infrastructure: prescreener for opportunity scanner (every 60s) ──
76
+ - name: prescreener
77
+ type: prescreener
78
+ interval: 60s
79
+ config:
80
+ topN: 30
81
+ minDayVolume: 500000
82
+ minLeverage: 2
83
+ minOpenInterest: 0
84
+
85
+ # ── Secondary deep scan: 4-pillar opportunity scoring (every 15 min) ──
86
+ - name: opportunity
87
+ type: opportunity
88
+ interval: 900s
89
+ depends_on:
90
+ - scanner: prescreener
91
+ required: true
92
+ max_age: 5m
93
+ - scanner: market_regime
94
+ required: false
95
+ max_age: 4h
96
+ on_missing: degrade
97
+ on_stale: degrade
98
+ config:
99
+ minCompositeScore: 60
100
+ maxCandidates: 15
101
+ minDayVolume: 500000
102
+
103
+ actions:
104
+ # ── Entry: LLM five-layer gauntlet on emerging mover signals ──
105
+ - name: fox_entry
106
+ action_type: OPEN_POSITION
107
+ decision_mode: llm
108
+ decision_model: claude-sonnet-4-6
109
+ scanners: [emerging_movers]
110
+ min_confidence: 7
111
+ params:
112
+ order_type: FEE_OPTIMIZED_LIMIT
113
+ fee_optimized_limit_options:
114
+ ensure_execution_as_taker: true
115
+ execution_timeout_seconds: 15
116
+ context:
117
+ - type: signal
118
+ scanner: emerging_movers
119
+ - type: context
120
+ scanner: market_regime
121
+ decision_prompt: |
122
+ You are the FOX v1.6 entry filter. Evaluate emerging mover signals through
123
+ a strict five-layer gauntlet. Speed is edge — enter on FIRST signal or skip.
124
+
125
+ SIGNAL DATA:
126
+ {{emerging_movers}}
127
+
128
+ MARKET REGIME:
129
+ {{regime}}
130
+
131
+ ═══ LAYER 1: FIRST JUMP DETECTION (mandatory) ═══
132
+ - Must have FIRST_JUMP reason (jumped 10+ ranks from #25+ in one scan)
133
+ - Previous rank must be ≥ 20 (outside top 20)
134
+ - rankJumpThisScan ≥ 15 OR contribVelocity > 15 (small jumps eliminated)
135
+ - Asset already at #1-10 for 2+ scans → SKIP (move is over)
136
+
137
+ ═══ LAYER 2: SCORING (minimum 7 points, 8 for NEUTRAL regime) ═══
138
+ FIRST_JUMP: +3 (mandatory)
139
+ IMMEDIATE_MOVER: +2
140
+ contribVelocity > 10: +2
141
+ CONTRIB_EXPLOSION: +2
142
+ DEEP_CLIMBER: +1
143
+ RANK_UP: +1
144
+ CLIMBING: +1
145
+ ACCEL: +1
146
+ STREAK: +1
147
+ BTC 1h bias aligned: +1
148
+ UTC 04:00-13:59: +1 (time-of-day bonus)
149
+ UTC 18:00-02:00: -2 (evening penalty — needs score 9+ effective)
150
+
151
+ Minimum requirements: score ≥ 7, reasons ≥ 3, contribVelocity > 7 (hard gate)
152
+
153
+ ═══ LAYER 3: VELOCITY & PRICE ACTION ═══
154
+ - Negative velocity without big jump → SKIP
155
+ - IMMEDIATE_MOVER/FIRST_JUMP: vel > 0 sufficient
156
+ - DEEP_CLIMBER: vel ≥ 0.03% (0.0003 decimal)
157
+ - Erratic rank history (zigzag) → SKIP unless CONTRIB_EXPLOSION
158
+
159
+ ═══ LAYER 4: LEVERAGE & ASSET CHECKS ═══
160
+ - Max leverage for asset must be ≥ 7x — skip if capped at 3-5x
161
+ - XYZ equities: ignore trader count, require score ≥ 10,
162
+ use leverageType "ISOLATED" and dex "xyz"
163
+ - ≥ 10 SM traders required (crypto only, waived for XYZ)
164
+
165
+ ═══ LAYER 5: MARKET REGIME ═══
166
+ - BEARISH (bear ≥ 60, conf ≥ 50): SHORT only
167
+ - BULLISH (bull ≥ 60, conf ≥ 50): LONG only
168
+ - NEUTRAL or stale (> 1h): both directions if score ≥ 8
169
+
170
+ ═══ ROTATION (slots full + explosive FIRST_JUMP) ═══
171
+ - Weakest position has negative ROE → CUT and ENTER new
172
+ - Weakest has positive ROE or SM conviction 3+ → HOLD
173
+ - Never rotate positions younger than 10 minutes
174
+
175
+ ═══ ANTI-PATTERNS (hard blocks) ═══
176
+ - Rank #1-10 for 2+ scans → move is over
177
+ - 4+ reasons at rank #5 → already peaked
178
+ - Counter to BTC hourly trend → hard block
179
+ - Burned/blacklisted asset → SKIP
180
+
181
+ Respond:
182
+ {
183
+ "execute": true/false,
184
+ "actionType": "OPEN_POSITION",
185
+ "confidence": 1-10,
186
+ "reasoning": "one sentence",
187
+ "payload": {
188
+ "signals": [
189
+ {
190
+ "asset": "<ticker>",
191
+ "direction": "LONG" or "SHORT",
192
+ "reason": "one sentence",
193
+ "rotate_out": "<asset_to_cut>",
194
+ "leverage": <number, optional — your recommended leverage>,
195
+ "margin": <number, optional — $ margin amount>
196
+ }
197
+ ]
198
+ }
199
+ }
200
+
201
+ # ── SM flip: immediate close on conviction reversal ──
202
+ - name: sm_flip_close
203
+ action_type: CLOSE_POSITION
204
+ decision_mode: rule
205
+ scanners: [sm_flip]
206
+ min_confidence: 1
207
+ params:
208
+ order_type: FEE_OPTIMIZED_LIMIT
209
+ fee_optimized_limit_options:
210
+ ensure_execution_as_taker: true
211
+ execution_timeout_seconds: 10
212
+
213
+ # ── Watchdog: emergency close on margin danger ──
214
+ - name: watchdog_close
215
+ action_type: CLOSE_POSITION
216
+ decision_mode: rule
217
+ scanners: [watchdog]
218
+ min_confidence: 1
219
+ params:
220
+ order_type: MARKET
221
+
222
+ # ── DSL — trailing exit
223
+ exit:
224
+ engine: dsl
225
+ interval_seconds: 30
226
+ order_type: FEE_OPTIMIZED_LIMIT
227
+ fee_optimized_limit_options:
228
+ ensure_execution_as_taker: true
229
+ execution_timeout_seconds: 15
230
+ dsl_preset:
231
+ phase1:
232
+ enabled: true
233
+ max_loss_pct: 2.0
234
+ retrace_threshold: 7
235
+ consecutive_breaches_required: 3
236
+ phase2:
237
+ enabled: true
238
+ tiers:
239
+ - { trigger_pct: 7, lock_hw_pct: 40 }
240
+ - { trigger_pct: 12, lock_hw_pct: 55 }
241
+ - { trigger_pct: 15, lock_hw_pct: 75 }
242
+ - { trigger_pct: 20, lock_hw_pct: 85 }
@@ -0,0 +1,46 @@
1
+ name: minimal
2
+ version: 1.0.0
3
+ description: Watch-only strategy — logs signals, opens no positions.
4
+
5
+ strategy:
6
+ wallet: "${WALLET_ADDRESS}"
7
+ slots: 1
8
+ trading_risk: conservative
9
+ enabled: true
10
+
11
+ scanners:
12
+ - name: emerging_movers
13
+ type: emerging_movers
14
+ interval: 60s
15
+ config:
16
+ topN: 20
17
+ minRankJump: 5
18
+ minScansBeforeSignals: 2
19
+
20
+ actions:
21
+ - name: log_signals
22
+ action_type: OPEN_POSITION
23
+ decision_mode: no_decision
24
+ scanners: [emerging_movers]
25
+ min_confidence: 0
26
+
27
+ exit:
28
+ engine: dsl
29
+ interval_seconds: 60
30
+ order_type: FEE_OPTIMIZED_LIMIT
31
+ fee_optimized_limit_options:
32
+ ensure_execution_as_taker: true
33
+ execution_timeout_seconds: 30
34
+ dsl_preset:
35
+ phase1:
36
+ enabled: true
37
+ max_loss_pct: 5.0
38
+ retrace_threshold: 7
39
+ consecutive_breaches_required: 1
40
+ phase2:
41
+ enabled: true
42
+ tiers:
43
+ - { trigger_pct: 7, lock_hw_pct: 40 }
44
+ - { trigger_pct: 12, lock_hw_pct: 55 }
45
+ - { trigger_pct: 15, lock_hw_pct: 75 }
46
+ - { trigger_pct: 20, lock_hw_pct: 85 }
@@ -0,0 +1,48 @@
1
+ # `momentum-guarded` — How it works
2
+
3
+ Companion notes for [`examples/strategies/momentum-guarded.yaml`](../momentum-guarded.yaml).
4
+
5
+ ## The trading thesis
6
+
7
+ Catch **short-horizon directional breakouts** on liquid Hyperliquid perps the moment a 1h candle prints an outsized move vs. the prior close — but only when the move passes both an LLM sanity check and a real-time risk gauntlet, and only with a trailing-exit playbook strict enough to survive momentum reversals.
8
+
9
+ ## Signal flow (entry side)
10
+
11
+ 1. **External producer** ([`src/scanners/external/momentum/producer.mjs`](../../../src/scanners/external/momentum/producer.mjs)) runs out-of-process — pulls instruments + 1h candles from Senpi MCP, computes last-vs-prev close % move, and ingests `MOMENTUM_BREAKOUT` signals via `senpi.ingestExternalScannerData`. Re-run on a cron / `watch`.
12
+ 2. The runtime's `external_momentum` scanner of type `external_scanner` accepts the push, validates the payload schema (`sourceMeta`, `sourceFactors`, …), and emits a `scanner:run:complete` event carrying the signals.
13
+ 3. `momentum_entry` (an `OPEN_POSITION` action with `decision_mode: llm`) consumes the signals, runs each through a 6-step gauntlet (move magnitude ≥1.5%, direction matches sign, day notional ≥1M, max leverage ≥5, producer score ≥0.4, pick highest-score), and returns at most one trade. `min_confidence: 7` blocks lukewarm LLM verdicts.
14
+ 4. **Risk gates** fire before the position opens. With `slots: 3` and `margin_per_slot: 300` (~$900 deployed of a $5k budget), the gauntlet of guardrails is:
15
+ - `daily_loss_limit_pct: 4` — closes the gate if today's PnL drops 4% of day-open account value.
16
+ - `drawdown_halt_pct: 20` — closes the gate at 20% PnL drawdown from peak (peak carries ~24h, not reset at midnight).
17
+ - `max_entries_per_day: 6` — caps churn on noisy breakout days.
18
+ - `bypass_max_entries_per_day_on_profit` (here `false`) — when `true`, at that daily cap the max-entries gate stays OPEN if intraday `today_snapshot.pnl.delta_since_open > 0` (reuses the same PnL snapshot as daily loss in this recipe).
19
+ - `max_consecutive_losses: 3` + `cooldown_minutes: 90` — three losers in a row pauses entries for 90 min so the strategy doesn't tilt.
20
+ - `per_asset_cooldown_minutes: 45` — no re-entry on the same ticker for 45 min after a close (avoids whipsaw fills).
21
+
22
+ Order matters: **CLOSED beats COOLDOWN beats OPEN**; the first non-OPEN gate short-circuits.
23
+ 5. If everything passes, `FEE_OPTIMIZED_LIMIT` posts the order with a 15s execution timeout (taker fallback guaranteed).
24
+
25
+ ## Position management (exit side)
26
+
27
+ Once filled, the **DSL exit engine** owns the position (`position_tracker` keeps it in sync even for manually-opened positions on the same wallet):
28
+
29
+ - **Phase 1** — fixed stop at `-2.5%` plus a `7%` retrace floor; needs `3` consecutive breaches before firing (debounce against single-tick spikes).
30
+ - **Phase 2** — once price advances, trailing floors lock in profit on a four-tier ladder:
31
+ - +6% → lock 35% of high-water
32
+ - +10% → lock 55%
33
+ - +15% → lock 70%
34
+ - +20% → lock 85%
35
+ - **Time-based cuts** — momentum that fails to develop is the silent killer:
36
+ - `dead_weight_cut` after 30 min flat → close.
37
+ - `weak_peak_cut` after 45 min if peak < +2% → close.
38
+ - `hard_timeout` at 2 hours → close regardless.
39
+
40
+ ## What this looks like in practice
41
+
42
+ - A trader runs the producer every minute via cron.
43
+ - 90% of producer ticks emit zero signals; the runtime stays idle.
44
+ - When BTC prints a +2% 1h candle on healthy volume, the LLM accepts, the risk gauntlet checks daily PnL/drawdown/entries/cooldowns, and one slot fires a long.
45
+ - DSL trails the move. If BTC stalls, time-cuts close it within ~30–45 min instead of bleeding margin. If BTC runs to +12%, the +10% tier locks in 55% of the high-water, so a retrace to +5% still books profit.
46
+ - A bad day (3 stop-outs) trips the consecutive-loss cooldown — the runtime stops trying for 90 min and resumes fresh.
47
+
48
+ Net effect: **a small, slot-bounded, risk-gated breakout sniper** with strict trailing protection — appropriate for a $5k moderate-risk wallet that wants asymmetric upside without unsupervised drawdown.
@@ -0,0 +1,161 @@
1
+ name: momentum-guarded
2
+ version: 1.0.0
3
+ description: >
4
+ Risk-managed external momentum strategy. An out-of-process producer
5
+ (src/scanners/external/momentum/producer.mjs) pushes MOMENTUM_BREAKOUT
6
+ signals into the runtime; an LLM gauntlet decides which breakouts deserve
7
+ capital; the risk component gates every entry against daily loss, drawdown,
8
+ per-day entry count, consecutive-loss cooldown, and per-asset cooldown;
9
+ the DSL exit engine manages trailing exits on accepted fills.
10
+
11
+ notifications:
12
+ telegram_chat_id: "${TELEGRAM_CHAT_ID}"
13
+
14
+ strategy:
15
+ wallet: "${WALLET_ADDRESS}"
16
+ slots: 3
17
+ margin_per_slot: 300
18
+ trading_risk: moderate
19
+ enabled: true
20
+
21
+ # ── RISK ──
22
+ # Real-time gates enforced on every OPEN_POSITION attempt. Any non-OPEN gate
23
+ # short-circuits and skips the entry. See docs/risk-component.md.
24
+ risk:
25
+ data_retention_hours: 72
26
+
27
+ guard_rails:
28
+ # Daily loss halt — stop trading if daily PnL drops > 4% of day-open account value.
29
+ daily_loss_limit_pct: 4
30
+
31
+ # Cap entries per UTC day so a noisy producer day can't churn the wallet.
32
+ max_entries_per_day: 6
33
+ # At cap: if true, gate stays OPEN when today_snapshot.pnl.delta_since_open > 0 (see docs/risk-component.md).
34
+ bypass_max_entries_per_day_on_profit: false
35
+
36
+ # Consecutive-loss cooldown — three losers in a row pauses entries for 90 min.
37
+ max_consecutive_losses: 3
38
+ cooldown_minutes: 90
39
+
40
+ # Drawdown halt — 20% PnL drawdown from peak halts entries; peak carries ~24h.
41
+ drawdown_halt_pct: 20
42
+ drawdown_reset_on_day_rollover: false
43
+
44
+ # Per-asset cooldown — no re-entry on the same asset for 45 min after a close.
45
+ per_asset_cooldown_minutes: 45
46
+
47
+ # ── SCANNERS ──
48
+ scanners:
49
+ # Onchain position tracker — emits position lifecycle events into the DSL exit engine.
50
+ - name: position_tracker
51
+ type: position_tracker
52
+ interval: 10s
53
+
54
+ # External producer feed — schema for inbound MOMENTUM_BREAKOUT signals
55
+ # delivered via senpi.ingestExternalScannerData.
56
+ - name: external_momentum
57
+ type: external_scanner
58
+ outputs:
59
+ signals: true
60
+ context: false
61
+ config:
62
+ fields:
63
+ sourceScannerId: { type: string, required: true }
64
+ sourceSignalType: { type: string, required: true }
65
+ sourceTimestamp: { type: number, required: true }
66
+ sourceFactors: { type: object, required: true }
67
+ sourceMeta: { type: object, required: true }
68
+
69
+ # ── ACTIONS ──
70
+ actions:
71
+ # Position lifecycle tracking — feeds the DSL exit engine.
72
+ - name: position_tracker_action
73
+ action_type: POSITION_TRACKER
74
+ decision_mode: rule
75
+ scanners: [position_tracker]
76
+
77
+ # Entry: LLM gauntlet on momentum breakout signals.
78
+ - name: momentum_entry
79
+ action_type: OPEN_POSITION
80
+ decision_mode: llm
81
+ decision_model: claude-sonnet-4-20250514
82
+ scanners: [external_momentum]
83
+ min_confidence: 7
84
+ params:
85
+ order_type: FEE_OPTIMIZED_LIMIT
86
+ fee_optimized_limit_options:
87
+ ensure_execution_as_taker: true
88
+ execution_timeout_seconds: 15
89
+ context:
90
+ - type: signal
91
+ scanner: external_momentum
92
+ decision_prompt: |
93
+ You are a trade-decisioning evaluator. Given a MOMENTUM_BREAKOUT
94
+ signal pushed by the external momentum producer, decide whether to
95
+ open a position on it or skip.
96
+
97
+ A MOMENTUM_BREAKOUT fires when an asset's latest closed candle moves
98
+ by at least the producer's threshold vs. the previous close on the
99
+ signal's timeframe — i.e. a short-term directional breakout in price.
100
+ `meta.movePct` carries the signed % change (positive = LONG bias,
101
+ negative = SHORT bias); `score` (0..1) scales with the move's
102
+ magnitude; `meta.dayNtlVlm` and `meta.maxLeverage` describe the
103
+ instrument's liquidity and leverage headroom.
104
+
105
+ SIGNAL DATA:
106
+ {{signal_external_momentum}}
107
+
108
+ ═══ GAUNTLET ═══
109
+ 1. movePct magnitude — require |movePct| >= 1.5; reject sub-threshold noise.
110
+ 2. Direction sanity — LONG only if movePct > 0, SHORT only if movePct < 0.
111
+ 3. Liquidity — meta.dayNtlVlm must be >= 1_000_000.
112
+ 4. Leverage — meta.maxLeverage must be >= 5; skip otherwise.
113
+ 5. Score — use the producer score (0..1) as a proxy for strength; require >= 0.4.
114
+ 6. One signal at a time — pick the highest-score eligible signal; skip the rest.
115
+
116
+ Respond with a single JSON object:
117
+ {
118
+ "execute": true|false,
119
+ "actionType": "OPEN_POSITION",
120
+ "confidence": 1-10,
121
+ "reasoning": "one sentence",
122
+ "payload": {
123
+ "signals": [
124
+ { "asset": "<ticker>", "direction": "LONG"|"SHORT", "reason": "one sentence" }
125
+ ]
126
+ }
127
+ }
128
+
129
+ # ── EXIT (DSL) ──
130
+ # Trailing stop-loss tuned for short-horizon momentum entries.
131
+ # Time-based cuts catch stalled trades that never deliver follow-through.
132
+ exit:
133
+ engine: dsl
134
+ interval_seconds: 30
135
+ order_type: FEE_OPTIMIZED_LIMIT
136
+ fee_optimized_limit_options:
137
+ ensure_execution_as_taker: true
138
+ execution_timeout_seconds: 15
139
+ dsl_preset:
140
+ hard_timeout:
141
+ enabled: true
142
+ interval_in_minutes: 120
143
+ weak_peak_cut:
144
+ enabled: true
145
+ interval_in_minutes: 45
146
+ min_value: 2
147
+ dead_weight_cut:
148
+ enabled: true
149
+ interval_in_minutes: 30
150
+ phase1:
151
+ enabled: true
152
+ max_loss_pct: 2.5
153
+ retrace_threshold: 7
154
+ consecutive_breaches_required: 3
155
+ phase2:
156
+ enabled: true
157
+ tiers:
158
+ - { trigger_pct: 6, lock_hw_pct: 35 }
159
+ - { trigger_pct: 10, lock_hw_pct: 55 }
160
+ - { trigger_pct: 15, lock_hw_pct: 70 }
161
+ - { trigger_pct: 20, lock_hw_pct: 85 }
@@ -0,0 +1,93 @@
1
+ # Risk showcase — every risk guardrail field annotated for reference.
2
+ # Use as a copy-paste reference when configuring risk management.
3
+ name: risk-showcase
4
+ version: 1.0.0
5
+ description: >
6
+ Annotated risk guardrails config reference.
7
+ Uses position_tracker scanner with DSL exit engine.
8
+ Lists explicit example values for each field (not implicit runtime defaults).
9
+
10
+ notifications:
11
+ telegram_chat_id: "${TELEGRAM_CHAT_ID}"
12
+
13
+ strategy:
14
+ wallet: "${WALLET_ADDRESS}"
15
+ budget: 10000
16
+ slots: 3
17
+ margin_per_slot: 250
18
+ trading_risk: moderate
19
+ enabled: true
20
+
21
+ # ── RISK ──
22
+ # Optional. Without this block, all gates are OPEN (no risk management).
23
+ risk:
24
+ # How long to keep audit log files (JSONL + daily snapshots), in hours.
25
+ # Range: 1–168 (1 hour to 7 days). Default: 48.
26
+ data_retention_hours: 48
27
+
28
+ guard_rails:
29
+ # ── Daily Loss Halt ──
30
+ # Gate CLOSED when daily trading PnL drop exceeds this % of account value at day open.
31
+ # Uses Hyperliquid portfolio PnL (realized + unrealized + funding, excludes deposits/withdrawals).
32
+ # Resets at UTC midnight.
33
+ daily_loss_limit_pct: 5 # 5% of account value at day open
34
+
35
+ # ── Max Entries Per Day ──
36
+ # Gate CLOSED when position entries today >= max_entries_per_day.
37
+ # Counts open positions opened today (startTime) + closed trades opened today (openTime).
38
+ # Resets at UTC midnight.
39
+ max_entries_per_day: 8
40
+ # When true, at the entry cap gate 5 stays OPEN if today_snapshot.pnl.delta_since_open > 0
41
+ # (intraday PnL delta vs UTC day open; same MCP snapshot as daily loss when gates 1–2 run).
42
+ # Default: false.
43
+ bypass_max_entries_per_day_on_profit: false
44
+
45
+ # ── Consecutive Loss Cooldown ──
46
+ # Gate COOLDOWN when the last N closed trades all have negative realizedPnl.
47
+ # Stateless: derived from trade history API on every tick, no persisted streak.
48
+ # Streak carries across days. Cooldown window starts from the most recent
49
+ # loss's close time and expires cooldown_minutes later.
50
+ max_consecutive_losses: 3
51
+ cooldown_minutes: 60
52
+
53
+ # ── Drawdown Halt ──
54
+ # Gate CLOSED when PnL drawdown from peak >= drawdown_halt_pct %.
55
+ # PnL-based: immune to deposits and withdrawals.
56
+ # Drawdown = (peak_pnl - current_pnl) / account_value_at_day_open * 100.
57
+ drawdown_halt_pct: 30 # 30% PnL drawdown from peak triggers halt
58
+ # When true, PnL peak resets at UTC midnight (intraday drawdown only).
59
+ # When false (default), PnL peak carries from prior ~24h (perpDay window).
60
+ drawdown_reset_on_day_rollover: false
61
+
62
+ # ── Per-Asset Cooldown ──
63
+ # Gate COOLDOWN for a specific asset when it was closed within the last N minutes.
64
+ # Checked on each entry attempt. Only evaluated when all other gates are OPEN.
65
+ # Minimum: 5 minutes (backend latency floor).
66
+ per_asset_cooldown_minutes: 30 # 30 min cooldown after closing any asset
67
+
68
+ # ── SCANNERS ──
69
+ scanners:
70
+ - name: position_tracker
71
+ type: position_tracker
72
+ interval: 10s
73
+
74
+ # ── ACTIONS ──
75
+ actions:
76
+ - name: position_tracker_action
77
+ action_type: POSITION_TRACKER
78
+ decision_mode: rule
79
+ scanners: [position_tracker]
80
+
81
+ # ── EXIT ──
82
+ exit:
83
+ engine: dsl
84
+ interval_seconds: 30
85
+ dsl_preset:
86
+ phase1:
87
+ max_loss_pct: 5.0
88
+ retrace_threshold: 10
89
+ consecutive_breaches_required: 2
90
+ phase2:
91
+ tiers:
92
+ - { trigger_pct: 10, lock_hw_pct: 50 }
93
+ - { trigger_pct: 20, lock_hw_pct: 70 }
@@ -0,0 +1,67 @@
1
+ name: viper
2
+ version: 1.0.0
3
+ description: Moderate — candle-based breakouts via prescreener + momentum.
4
+
5
+ strategy:
6
+ wallet: "${WALLET_ADDRESS}"
7
+ slots: 4
8
+ margin_pct: 10
9
+ trading_risk: moderate
10
+ enabled: true
11
+
12
+ scanners:
13
+ - name: prescreener
14
+ type: prescreener
15
+ interval: 5m
16
+ config:
17
+ topN: 30
18
+ minDayVolume: 1000000
19
+ minLeverage: 2
20
+ minOpenInterest: 0
21
+ - name: momentum
22
+ type: momentum
23
+ interval: 1m
24
+ config:
25
+ timeframe: "1h"
26
+ minMovePct: 1.5
27
+ maxCandidates: 20
28
+ minDayVolume: 1000000
29
+ minSignalScore: 0.2
30
+ requirePrescreened: true
31
+
32
+ actions:
33
+ - name: open_breakout
34
+ action_type: OPEN_POSITION
35
+ decision_mode: llm
36
+ decision_model: claude-sonnet-4-20250514
37
+ scanners: [momentum]
38
+ min_confidence: 6
39
+ params:
40
+ order_type: FEE_OPTIMIZED_LIMIT
41
+ fee_optimized_limit_options:
42
+ ensure_execution_as_taker: true
43
+ execution_timeout_seconds: 15
44
+ context: [signal]
45
+ decision_prompt: |
46
+ Evaluate the momentum breakout signal. Reply with JSON: {"execute": true|false, "actionType": "OPEN_POSITION", "confidence": 1-10, "reasoning": "...", "payload": {"signals": [{"asset": "SYMBOL", "direction": "LONG"|"SHORT", "reason": "...", "leverage": <optional number>, "margin": <optional $ amount>}]}}.
47
+
48
+ exit:
49
+ engine: dsl
50
+ interval_seconds: 30
51
+ order_type: FEE_OPTIMIZED_LIMIT
52
+ fee_optimized_limit_options:
53
+ ensure_execution_as_taker: true
54
+ execution_timeout_seconds: 15
55
+ dsl_preset:
56
+ phase1:
57
+ enabled: true
58
+ max_loss_pct: 4.0
59
+ retrace_threshold: 10
60
+ consecutive_breaches_required: 3
61
+ phase2:
62
+ enabled: true
63
+ tiers:
64
+ - { trigger_pct: 10, lock_hw_pct: 50 }
65
+ - { trigger_pct: 20, lock_hw_pct: 60 }
66
+ - { trigger_pct: 35, lock_hw_pct: 63 }
67
+ - { trigger_pct: 50, lock_hw_pct: 70 }