@senpi/trading-recipe 1.0.21

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 (553) hide show
  1. package/README.md +117 -0
  2. package/dist/actions/close-position/close-position.action.d.ts +16 -0
  3. package/dist/actions/close-position/close-position.action.d.ts.map +1 -0
  4. package/dist/actions/close-position/close-position.action.js +215 -0
  5. package/dist/actions/close-position/close-position.action.js.map +1 -0
  6. package/dist/actions/decision-engine.d.ts +32 -0
  7. package/dist/actions/decision-engine.d.ts.map +1 -0
  8. package/dist/actions/decision-engine.js +103 -0
  9. package/dist/actions/decision-engine.js.map +1 -0
  10. package/dist/actions/llm-decision/anthropic-llm-decision.d.ts +12 -0
  11. package/dist/actions/llm-decision/anthropic-llm-decision.d.ts.map +1 -0
  12. package/dist/actions/llm-decision/anthropic-llm-decision.js +74 -0
  13. package/dist/actions/llm-decision/anthropic-llm-decision.js.map +1 -0
  14. package/dist/actions/llm-decision/factory.d.ts +17 -0
  15. package/dist/actions/llm-decision/factory.d.ts.map +1 -0
  16. package/dist/actions/llm-decision/factory.js +29 -0
  17. package/dist/actions/llm-decision/factory.js.map +1 -0
  18. package/dist/actions/llm-decision/index.d.ts +8 -0
  19. package/dist/actions/llm-decision/index.d.ts.map +1 -0
  20. package/dist/actions/llm-decision/index.js +5 -0
  21. package/dist/actions/llm-decision/index.js.map +1 -0
  22. package/dist/actions/llm-decision/openclaw-llm-decision.d.ts +14 -0
  23. package/dist/actions/llm-decision/openclaw-llm-decision.d.ts.map +1 -0
  24. package/dist/actions/llm-decision/openclaw-llm-decision.js +58 -0
  25. package/dist/actions/llm-decision/openclaw-llm-decision.js.map +1 -0
  26. package/dist/actions/llm-decision/shared.d.ts +41 -0
  27. package/dist/actions/llm-decision/shared.d.ts.map +1 -0
  28. package/dist/actions/llm-decision/shared.js +117 -0
  29. package/dist/actions/llm-decision/shared.js.map +1 -0
  30. package/dist/actions/open-position/open-position.action.d.ts +16 -0
  31. package/dist/actions/open-position/open-position.action.d.ts.map +1 -0
  32. package/dist/actions/open-position/open-position.action.js +275 -0
  33. package/dist/actions/open-position/open-position.action.js.map +1 -0
  34. package/dist/actions/types.d.ts +123 -0
  35. package/dist/actions/types.d.ts.map +1 -0
  36. package/dist/actions/types.js +3 -0
  37. package/dist/actions/types.js.map +1 -0
  38. package/dist/cli/guide-commands.d.ts +26 -0
  39. package/dist/cli/guide-commands.d.ts.map +1 -0
  40. package/dist/cli/guide-commands.js +345 -0
  41. package/dist/cli/guide-commands.js.map +1 -0
  42. package/dist/cli/senpi-commands.d.ts +20 -0
  43. package/dist/cli/senpi-commands.d.ts.map +1 -0
  44. package/dist/cli/senpi-commands.js +115 -0
  45. package/dist/cli/senpi-commands.js.map +1 -0
  46. package/dist/constants/dsl/index.d.ts +45 -0
  47. package/dist/constants/dsl/index.d.ts.map +1 -0
  48. package/dist/constants/dsl/index.js +45 -0
  49. package/dist/constants/dsl/index.js.map +1 -0
  50. package/dist/context/context-builder.d.ts +14 -0
  51. package/dist/context/context-builder.d.ts.map +1 -0
  52. package/dist/context/context-builder.js +36 -0
  53. package/dist/context/context-builder.js.map +1 -0
  54. package/dist/context/index.d.ts +5 -0
  55. package/dist/context/index.d.ts.map +1 -0
  56. package/dist/context/index.js +5 -0
  57. package/dist/context/index.js.map +1 -0
  58. package/dist/context/interpolate.d.ts +6 -0
  59. package/dist/context/interpolate.d.ts.map +1 -0
  60. package/dist/context/interpolate.js +15 -0
  61. package/dist/context/interpolate.js.map +1 -0
  62. package/dist/context/providers/asset-trend.provider.d.ts +42 -0
  63. package/dist/context/providers/asset-trend.provider.d.ts.map +1 -0
  64. package/dist/context/providers/asset-trend.provider.js +94 -0
  65. package/dist/context/providers/asset-trend.provider.js.map +1 -0
  66. package/dist/context/providers/index.d.ts +5 -0
  67. package/dist/context/providers/index.d.ts.map +1 -0
  68. package/dist/context/providers/index.js +5 -0
  69. package/dist/context/providers/index.js.map +1 -0
  70. package/dist/context/providers/regime.provider.d.ts +14 -0
  71. package/dist/context/providers/regime.provider.d.ts.map +1 -0
  72. package/dist/context/providers/regime.provider.js +29 -0
  73. package/dist/context/providers/regime.provider.js.map +1 -0
  74. package/dist/context/providers/signal.provider.d.ts +11 -0
  75. package/dist/context/providers/signal.provider.d.ts.map +1 -0
  76. package/dist/context/providers/signal.provider.js +27 -0
  77. package/dist/context/providers/signal.provider.js.map +1 -0
  78. package/dist/context/providers/strategy.provider.d.ts +14 -0
  79. package/dist/context/providers/strategy.provider.d.ts.map +1 -0
  80. package/dist/context/providers/strategy.provider.js +68 -0
  81. package/dist/context/providers/strategy.provider.js.map +1 -0
  82. package/dist/context/types.d.ts +30 -0
  83. package/dist/context/types.d.ts.map +1 -0
  84. package/dist/context/types.js +2 -0
  85. package/dist/context/types.js.map +1 -0
  86. package/dist/dsl/config/index.d.ts +59 -0
  87. package/dist/dsl/config/index.d.ts.map +1 -0
  88. package/dist/dsl/config/index.js +171 -0
  89. package/dist/dsl/config/index.js.map +1 -0
  90. package/dist/dsl/constants/index.d.ts +3 -0
  91. package/dist/dsl/constants/index.d.ts.map +1 -0
  92. package/dist/dsl/constants/index.js +3 -0
  93. package/dist/dsl/constants/index.js.map +1 -0
  94. package/dist/dsl/engine/index.d.ts +7 -0
  95. package/dist/dsl/engine/index.d.ts.map +1 -0
  96. package/dist/dsl/engine/index.js +310 -0
  97. package/dist/dsl/engine/index.js.map +1 -0
  98. package/dist/dsl/events/bus-types.d.ts +7 -0
  99. package/dist/dsl/events/bus-types.d.ts.map +1 -0
  100. package/dist/dsl/events/bus-types.js +6 -0
  101. package/dist/dsl/events/bus-types.js.map +1 -0
  102. package/dist/dsl/events/guards.d.ts +17 -0
  103. package/dist/dsl/events/guards.d.ts.map +1 -0
  104. package/dist/dsl/events/guards.js +94 -0
  105. package/dist/dsl/events/guards.js.map +1 -0
  106. package/dist/dsl/events/handlers.d.ts +15 -0
  107. package/dist/dsl/events/handlers.d.ts.map +1 -0
  108. package/dist/dsl/events/handlers.js +252 -0
  109. package/dist/dsl/events/handlers.js.map +1 -0
  110. package/dist/dsl/events/index.d.ts +4 -0
  111. package/dist/dsl/events/index.d.ts.map +1 -0
  112. package/dist/dsl/events/index.js +4 -0
  113. package/dist/dsl/events/index.js.map +1 -0
  114. package/dist/dsl/index.d.ts +13 -0
  115. package/dist/dsl/index.d.ts.map +1 -0
  116. package/dist/dsl/index.js +35 -0
  117. package/dist/dsl/index.js.map +1 -0
  118. package/dist/dsl/monitor/index.d.ts +18 -0
  119. package/dist/dsl/monitor/index.d.ts.map +1 -0
  120. package/dist/dsl/monitor/index.js +310 -0
  121. package/dist/dsl/monitor/index.js.map +1 -0
  122. package/dist/dsl/plugin/index.d.ts +29 -0
  123. package/dist/dsl/plugin/index.d.ts.map +1 -0
  124. package/dist/dsl/plugin/index.js +85 -0
  125. package/dist/dsl/plugin/index.js.map +1 -0
  126. package/dist/dsl/types/index.d.ts +3 -0
  127. package/dist/dsl/types/index.d.ts.map +1 -0
  128. package/dist/dsl/types/index.js +3 -0
  129. package/dist/dsl/types/index.js.map +1 -0
  130. package/dist/health/index.d.ts +9 -0
  131. package/dist/health/index.d.ts.map +1 -0
  132. package/dist/health/index.js +9 -0
  133. package/dist/health/index.js.map +1 -0
  134. package/dist/index.d.ts +95 -0
  135. package/dist/index.d.ts.map +1 -0
  136. package/dist/index.js +235 -0
  137. package/dist/index.js.map +1 -0
  138. package/dist/leverage/max-leverage-cache.d.ts +10 -0
  139. package/dist/leverage/max-leverage-cache.d.ts.map +1 -0
  140. package/dist/leverage/max-leverage-cache.js +51 -0
  141. package/dist/leverage/max-leverage-cache.js.map +1 -0
  142. package/dist/leverage/resolve-leverage.d.ts +9 -0
  143. package/dist/leverage/resolve-leverage.d.ts.map +1 -0
  144. package/dist/leverage/resolve-leverage.js +15 -0
  145. package/dist/leverage/resolve-leverage.js.map +1 -0
  146. package/dist/risk/index.d.ts +9 -0
  147. package/dist/risk/index.d.ts.map +1 -0
  148. package/dist/risk/index.js +9 -0
  149. package/dist/risk/index.js.map +1 -0
  150. package/dist/runtime/action-registry.d.ts +12 -0
  151. package/dist/runtime/action-registry.d.ts.map +1 -0
  152. package/dist/runtime/action-registry.js +20 -0
  153. package/dist/runtime/action-registry.js.map +1 -0
  154. package/dist/runtime/build-action-scan-payload.d.ts +20 -0
  155. package/dist/runtime/build-action-scan-payload.d.ts.map +1 -0
  156. package/dist/runtime/build-action-scan-payload.js +40 -0
  157. package/dist/runtime/build-action-scan-payload.js.map +1 -0
  158. package/dist/runtime/bus.d.ts +6 -0
  159. package/dist/runtime/bus.d.ts.map +1 -0
  160. package/dist/runtime/bus.js +19 -0
  161. package/dist/runtime/bus.js.map +1 -0
  162. package/dist/runtime/create-action-context.d.ts +34 -0
  163. package/dist/runtime/create-action-context.d.ts.map +1 -0
  164. package/dist/runtime/create-action-context.js +22 -0
  165. package/dist/runtime/create-action-context.js.map +1 -0
  166. package/dist/runtime/create-actions.d.ts +30 -0
  167. package/dist/runtime/create-actions.d.ts.map +1 -0
  168. package/dist/runtime/create-actions.js +71 -0
  169. package/dist/runtime/create-actions.js.map +1 -0
  170. package/dist/runtime/create-runtime-context.d.ts +35 -0
  171. package/dist/runtime/create-runtime-context.d.ts.map +1 -0
  172. package/dist/runtime/create-runtime-context.js +33 -0
  173. package/dist/runtime/create-runtime-context.js.map +1 -0
  174. package/dist/runtime/create-scanner-module.d.ts +14 -0
  175. package/dist/runtime/create-scanner-module.d.ts.map +1 -0
  176. package/dist/runtime/create-scanner-module.js +26 -0
  177. package/dist/runtime/create-scanner-module.js.map +1 -0
  178. package/dist/runtime/create-scanner-providers-for-run.d.ts +20 -0
  179. package/dist/runtime/create-scanner-providers-for-run.d.ts.map +1 -0
  180. package/dist/runtime/create-scanner-providers-for-run.js +34 -0
  181. package/dist/runtime/create-scanner-providers-for-run.js.map +1 -0
  182. package/dist/runtime/default-state-dir.d.ts +10 -0
  183. package/dist/runtime/default-state-dir.d.ts.map +1 -0
  184. package/dist/runtime/default-state-dir.js +22 -0
  185. package/dist/runtime/default-state-dir.js.map +1 -0
  186. package/dist/runtime/env-resolve.d.ts +17 -0
  187. package/dist/runtime/env-resolve.d.ts.map +1 -0
  188. package/dist/runtime/env-resolve.js +45 -0
  189. package/dist/runtime/env-resolve.js.map +1 -0
  190. package/dist/runtime/hook-system.d.ts +7 -0
  191. package/dist/runtime/hook-system.d.ts.map +1 -0
  192. package/dist/runtime/hook-system.js +16 -0
  193. package/dist/runtime/hook-system.js.map +1 -0
  194. package/dist/runtime/index.d.ts +37 -0
  195. package/dist/runtime/index.d.ts.map +1 -0
  196. package/dist/runtime/index.js +26 -0
  197. package/dist/runtime/index.js.map +1 -0
  198. package/dist/runtime/load-trading-strategy.d.ts +23 -0
  199. package/dist/runtime/load-trading-strategy.d.ts.map +1 -0
  200. package/dist/runtime/load-trading-strategy.js +130 -0
  201. package/dist/runtime/load-trading-strategy.js.map +1 -0
  202. package/dist/runtime/map-exit-config.d.ts +12 -0
  203. package/dist/runtime/map-exit-config.d.ts.map +1 -0
  204. package/dist/runtime/map-exit-config.js +91 -0
  205. package/dist/runtime/map-exit-config.js.map +1 -0
  206. package/dist/runtime/map-strategies-registration.d.ts +12 -0
  207. package/dist/runtime/map-strategies-registration.d.ts.map +1 -0
  208. package/dist/runtime/map-strategies-registration.js +52 -0
  209. package/dist/runtime/map-strategies-registration.js.map +1 -0
  210. package/dist/runtime/map-strategies.d.ts +12 -0
  211. package/dist/runtime/map-strategies.d.ts.map +1 -0
  212. package/dist/runtime/map-strategies.js +66 -0
  213. package/dist/runtime/map-strategies.js.map +1 -0
  214. package/dist/runtime/notifications.d.ts +12 -0
  215. package/dist/runtime/notifications.d.ts.map +1 -0
  216. package/dist/runtime/notifications.js +83 -0
  217. package/dist/runtime/notifications.js.map +1 -0
  218. package/dist/runtime/parse-interval.d.ts +11 -0
  219. package/dist/runtime/parse-interval.d.ts.map +1 -0
  220. package/dist/runtime/parse-interval.js +35 -0
  221. package/dist/runtime/parse-interval.js.map +1 -0
  222. package/dist/runtime/reconcile-state.d.ts +25 -0
  223. package/dist/runtime/reconcile-state.d.ts.map +1 -0
  224. package/dist/runtime/reconcile-state.js +112 -0
  225. package/dist/runtime/reconcile-state.js.map +1 -0
  226. package/dist/runtime/risk-guard.d.ts +6 -0
  227. package/dist/runtime/risk-guard.d.ts.map +1 -0
  228. package/dist/runtime/risk-guard.js +14 -0
  229. package/dist/runtime/risk-guard.js.map +1 -0
  230. package/dist/runtime/run.d.ts +21 -0
  231. package/dist/runtime/run.d.ts.map +1 -0
  232. package/dist/runtime/run.js +35 -0
  233. package/dist/runtime/run.js.map +1 -0
  234. package/dist/runtime/runtime.d.ts +40 -0
  235. package/dist/runtime/runtime.d.ts.map +1 -0
  236. package/dist/runtime/runtime.js +251 -0
  237. package/dist/runtime/runtime.js.map +1 -0
  238. package/dist/runtime/scanner-registry.d.ts +22 -0
  239. package/dist/runtime/scanner-registry.d.ts.map +1 -0
  240. package/dist/runtime/scanner-registry.js +83 -0
  241. package/dist/runtime/scanner-registry.js.map +1 -0
  242. package/dist/runtime/strategy-registry.d.ts +49 -0
  243. package/dist/runtime/strategy-registry.d.ts.map +1 -0
  244. package/dist/runtime/strategy-registry.js +156 -0
  245. package/dist/runtime/strategy-registry.js.map +1 -0
  246. package/dist/runtime/trading-strategy-config.d.ts +6 -0
  247. package/dist/runtime/trading-strategy-config.d.ts.map +1 -0
  248. package/dist/runtime/trading-strategy-config.js +5 -0
  249. package/dist/runtime/trading-strategy-config.js.map +1 -0
  250. package/dist/runtime/trading-strategy-schema.d.ts +20093 -0
  251. package/dist/runtime/trading-strategy-schema.d.ts.map +1 -0
  252. package/dist/runtime/trading-strategy-schema.js +115 -0
  253. package/dist/runtime/trading-strategy-schema.js.map +1 -0
  254. package/dist/scanners/__tests__/fixtures/index.d.ts +3 -0
  255. package/dist/scanners/__tests__/fixtures/index.d.ts.map +1 -0
  256. package/dist/scanners/__tests__/fixtures/index.js +3 -0
  257. package/dist/scanners/__tests__/fixtures/index.js.map +1 -0
  258. package/dist/scanners/__tests__/fixtures/scan-results.d.ts +23 -0
  259. package/dist/scanners/__tests__/fixtures/scan-results.d.ts.map +1 -0
  260. package/dist/scanners/__tests__/fixtures/scan-results.js +128 -0
  261. package/dist/scanners/__tests__/fixtures/scan-results.js.map +1 -0
  262. package/dist/scanners/__tests__/fixtures/signals.d.ts +18 -0
  263. package/dist/scanners/__tests__/fixtures/signals.d.ts.map +1 -0
  264. package/dist/scanners/__tests__/fixtures/signals.js +84 -0
  265. package/dist/scanners/__tests__/fixtures/signals.js.map +1 -0
  266. package/dist/scanners/__tests__/test-helpers.d.ts +4 -0
  267. package/dist/scanners/__tests__/test-helpers.d.ts.map +1 -0
  268. package/dist/scanners/__tests__/test-helpers.js +23 -0
  269. package/dist/scanners/__tests__/test-helpers.js.map +1 -0
  270. package/dist/scanners/artifacts.d.ts +119 -0
  271. package/dist/scanners/artifacts.d.ts.map +1 -0
  272. package/dist/scanners/artifacts.js +72 -0
  273. package/dist/scanners/artifacts.js.map +1 -0
  274. package/dist/scanners/create-scanner.d.ts +13 -0
  275. package/dist/scanners/create-scanner.d.ts.map +1 -0
  276. package/dist/scanners/create-scanner.js +11 -0
  277. package/dist/scanners/create-scanner.js.map +1 -0
  278. package/dist/scanners/engine/config-validator.d.ts +7 -0
  279. package/dist/scanners/engine/config-validator.d.ts.map +1 -0
  280. package/dist/scanners/engine/config-validator.js +16 -0
  281. package/dist/scanners/engine/config-validator.js.map +1 -0
  282. package/dist/scanners/engine/data-providers.d.ts +47 -0
  283. package/dist/scanners/engine/data-providers.d.ts.map +1 -0
  284. package/dist/scanners/engine/data-providers.js +8 -0
  285. package/dist/scanners/engine/data-providers.js.map +1 -0
  286. package/dist/scanners/engine/engine.d.ts +76 -0
  287. package/dist/scanners/engine/engine.d.ts.map +1 -0
  288. package/dist/scanners/engine/engine.js +399 -0
  289. package/dist/scanners/engine/engine.js.map +1 -0
  290. package/dist/scanners/engine/index.d.ts +9 -0
  291. package/dist/scanners/engine/index.d.ts.map +1 -0
  292. package/dist/scanners/engine/index.js +7 -0
  293. package/dist/scanners/engine/index.js.map +1 -0
  294. package/dist/scanners/engine/input-resolver.d.ts +21 -0
  295. package/dist/scanners/engine/input-resolver.d.ts.map +1 -0
  296. package/dist/scanners/engine/input-resolver.js +149 -0
  297. package/dist/scanners/engine/input-resolver.js.map +1 -0
  298. package/dist/scanners/engine/lifecycle.d.ts +21 -0
  299. package/dist/scanners/engine/lifecycle.d.ts.map +1 -0
  300. package/dist/scanners/engine/lifecycle.js +2 -0
  301. package/dist/scanners/engine/lifecycle.js.map +1 -0
  302. package/dist/scanners/engine/result-builder.d.ts +30 -0
  303. package/dist/scanners/engine/result-builder.d.ts.map +1 -0
  304. package/dist/scanners/engine/result-builder.js +129 -0
  305. package/dist/scanners/engine/result-builder.js.map +1 -0
  306. package/dist/scanners/engine/strategy-registry.d.ts +45 -0
  307. package/dist/scanners/engine/strategy-registry.d.ts.map +1 -0
  308. package/dist/scanners/engine/strategy-registry.js +93 -0
  309. package/dist/scanners/engine/strategy-registry.js.map +1 -0
  310. package/dist/scanners/events.d.ts +41 -0
  311. package/dist/scanners/events.d.ts.map +1 -0
  312. package/dist/scanners/events.js +33 -0
  313. package/dist/scanners/events.js.map +1 -0
  314. package/dist/scanners/implementations/emerging-movers.d.ts +215 -0
  315. package/dist/scanners/implementations/emerging-movers.d.ts.map +1 -0
  316. package/dist/scanners/implementations/emerging-movers.js +709 -0
  317. package/dist/scanners/implementations/emerging-movers.js.map +1 -0
  318. package/dist/scanners/implementations/index.d.ts +8 -0
  319. package/dist/scanners/implementations/index.d.ts.map +1 -0
  320. package/dist/scanners/implementations/index.js +8 -0
  321. package/dist/scanners/implementations/index.js.map +1 -0
  322. package/dist/scanners/implementations/indicators.d.ts +40 -0
  323. package/dist/scanners/implementations/indicators.d.ts.map +1 -0
  324. package/dist/scanners/implementations/indicators.js +114 -0
  325. package/dist/scanners/implementations/indicators.js.map +1 -0
  326. package/dist/scanners/implementations/liquidation-watchdog.d.ts +74 -0
  327. package/dist/scanners/implementations/liquidation-watchdog.d.ts.map +1 -0
  328. package/dist/scanners/implementations/liquidation-watchdog.js +268 -0
  329. package/dist/scanners/implementations/liquidation-watchdog.js.map +1 -0
  330. package/dist/scanners/implementations/market-regime.d.ts +52 -0
  331. package/dist/scanners/implementations/market-regime.d.ts.map +1 -0
  332. package/dist/scanners/implementations/market-regime.js +201 -0
  333. package/dist/scanners/implementations/market-regime.js.map +1 -0
  334. package/dist/scanners/implementations/momentum.d.ts +21 -0
  335. package/dist/scanners/implementations/momentum.d.ts.map +1 -0
  336. package/dist/scanners/implementations/momentum.js +128 -0
  337. package/dist/scanners/implementations/momentum.js.map +1 -0
  338. package/dist/scanners/implementations/oi-tracker.d.ts +13 -0
  339. package/dist/scanners/implementations/oi-tracker.d.ts.map +1 -0
  340. package/dist/scanners/implementations/oi-tracker.js +67 -0
  341. package/dist/scanners/implementations/oi-tracker.js.map +1 -0
  342. package/dist/scanners/implementations/opportunity.d.ts +104 -0
  343. package/dist/scanners/implementations/opportunity.d.ts.map +1 -0
  344. package/dist/scanners/implementations/opportunity.js +441 -0
  345. package/dist/scanners/implementations/opportunity.js.map +1 -0
  346. package/dist/scanners/implementations/prescreener.d.ts +20 -0
  347. package/dist/scanners/implementations/prescreener.d.ts.map +1 -0
  348. package/dist/scanners/implementations/prescreener.js +97 -0
  349. package/dist/scanners/implementations/prescreener.js.map +1 -0
  350. package/dist/scanners/implementations/sm-flip.d.ts +43 -0
  351. package/dist/scanners/implementations/sm-flip.d.ts.map +1 -0
  352. package/dist/scanners/implementations/sm-flip.js +200 -0
  353. package/dist/scanners/implementations/sm-flip.js.map +1 -0
  354. package/dist/scanners/index.d.ts +25 -0
  355. package/dist/scanners/index.d.ts.map +1 -0
  356. package/dist/scanners/index.js +18 -0
  357. package/dist/scanners/index.js.map +1 -0
  358. package/dist/scanners/input-descriptors.d.ts +61 -0
  359. package/dist/scanners/input-descriptors.d.ts.map +1 -0
  360. package/dist/scanners/input-descriptors.js +43 -0
  361. package/dist/scanners/input-descriptors.js.map +1 -0
  362. package/dist/scanners/protocol/context.d.ts +75 -0
  363. package/dist/scanners/protocol/context.d.ts.map +1 -0
  364. package/dist/scanners/protocol/context.js +2 -0
  365. package/dist/scanners/protocol/context.js.map +1 -0
  366. package/dist/scanners/protocol/hooks.d.ts +18 -0
  367. package/dist/scanners/protocol/hooks.d.ts.map +1 -0
  368. package/dist/scanners/protocol/hooks.js +12 -0
  369. package/dist/scanners/protocol/hooks.js.map +1 -0
  370. package/dist/scanners/protocol/index.d.ts +5 -0
  371. package/dist/scanners/protocol/index.d.ts.map +1 -0
  372. package/dist/scanners/protocol/index.js +2 -0
  373. package/dist/scanners/protocol/index.js.map +1 -0
  374. package/dist/scanners/protocol/scanner.d.ts +47 -0
  375. package/dist/scanners/protocol/scanner.d.ts.map +1 -0
  376. package/dist/scanners/protocol/scanner.js +2 -0
  377. package/dist/scanners/protocol/scanner.js.map +1 -0
  378. package/dist/scanners/providers/adapter.d.ts +23 -0
  379. package/dist/scanners/providers/adapter.d.ts.map +1 -0
  380. package/dist/scanners/providers/adapter.js +227 -0
  381. package/dist/scanners/providers/adapter.js.map +1 -0
  382. package/dist/scanners/providers/cache.d.ts +20 -0
  383. package/dist/scanners/providers/cache.d.ts.map +1 -0
  384. package/dist/scanners/providers/cache.js +61 -0
  385. package/dist/scanners/providers/cache.js.map +1 -0
  386. package/dist/scanners/providers/client.d.ts +53 -0
  387. package/dist/scanners/providers/client.d.ts.map +1 -0
  388. package/dist/scanners/providers/client.js +174 -0
  389. package/dist/scanners/providers/client.js.map +1 -0
  390. package/dist/scanners/providers/factory.d.ts +43 -0
  391. package/dist/scanners/providers/factory.d.ts.map +1 -0
  392. package/dist/scanners/providers/factory.js +192 -0
  393. package/dist/scanners/providers/factory.js.map +1 -0
  394. package/dist/scanners/providers/types.d.ts +61 -0
  395. package/dist/scanners/providers/types.d.ts.map +1 -0
  396. package/dist/scanners/providers/types.js +6 -0
  397. package/dist/scanners/providers/types.js.map +1 -0
  398. package/dist/scanners/runtime-module.d.ts +54 -0
  399. package/dist/scanners/runtime-module.d.ts.map +1 -0
  400. package/dist/scanners/runtime-module.js +90 -0
  401. package/dist/scanners/runtime-module.js.map +1 -0
  402. package/dist/scanners/scanner-definition.d.ts +58 -0
  403. package/dist/scanners/scanner-definition.d.ts.map +1 -0
  404. package/dist/scanners/scanner-definition.js +19 -0
  405. package/dist/scanners/scanner-definition.js.map +1 -0
  406. package/dist/scanners/schema-utils.d.ts +6 -0
  407. package/dist/scanners/schema-utils.d.ts.map +1 -0
  408. package/dist/scanners/schema-utils.js +14 -0
  409. package/dist/scanners/schema-utils.js.map +1 -0
  410. package/dist/scanners/score-utils.d.ts +19 -0
  411. package/dist/scanners/score-utils.d.ts.map +1 -0
  412. package/dist/scanners/score-utils.js +47 -0
  413. package/dist/scanners/score-utils.js.map +1 -0
  414. package/dist/scanners/store/fs-utils.d.ts +12 -0
  415. package/dist/scanners/store/fs-utils.d.ts.map +1 -0
  416. package/dist/scanners/store/fs-utils.js +47 -0
  417. package/dist/scanners/store/fs-utils.js.map +1 -0
  418. package/dist/scanners/store/index.d.ts +5 -0
  419. package/dist/scanners/store/index.d.ts.map +1 -0
  420. package/dist/scanners/store/index.js +5 -0
  421. package/dist/scanners/store/index.js.map +1 -0
  422. package/dist/scanners/store/runtime-store.d.ts +50 -0
  423. package/dist/scanners/store/runtime-store.d.ts.map +1 -0
  424. package/dist/scanners/store/runtime-store.js +91 -0
  425. package/dist/scanners/store/runtime-store.js.map +1 -0
  426. package/dist/scanners/store/shared-artifact-store.d.ts +31 -0
  427. package/dist/scanners/store/shared-artifact-store.d.ts.map +1 -0
  428. package/dist/scanners/store/shared-artifact-store.js +89 -0
  429. package/dist/scanners/store/shared-artifact-store.js.map +1 -0
  430. package/dist/scanners/store/signal-store.d.ts +36 -0
  431. package/dist/scanners/store/signal-store.d.ts.map +1 -0
  432. package/dist/scanners/store/signal-store.js +135 -0
  433. package/dist/scanners/store/signal-store.js.map +1 -0
  434. package/dist/scanners/types.d.ts +115 -0
  435. package/dist/scanners/types.d.ts.map +1 -0
  436. package/dist/scanners/types.js +3 -0
  437. package/dist/scanners/types.js.map +1 -0
  438. package/dist/scripts/run-dsl-standalone-live.d.ts +27 -0
  439. package/dist/scripts/run-dsl-standalone-live.d.ts.map +1 -0
  440. package/dist/scripts/run-dsl-standalone-live.js +207 -0
  441. package/dist/scripts/run-dsl-standalone-live.js.map +1 -0
  442. package/dist/scripts/run-dsl-standalone-mock.d.ts +13 -0
  443. package/dist/scripts/run-dsl-standalone-mock.d.ts.map +1 -0
  444. package/dist/scripts/run-dsl-standalone-mock.js +255 -0
  445. package/dist/scripts/run-dsl-standalone-mock.js.map +1 -0
  446. package/dist/senpi/client.d.ts +77 -0
  447. package/dist/senpi/client.d.ts.map +1 -0
  448. package/dist/senpi/client.js +523 -0
  449. package/dist/senpi/client.js.map +1 -0
  450. package/dist/senpi/constants.d.ts +7 -0
  451. package/dist/senpi/constants.d.ts.map +1 -0
  452. package/dist/senpi/constants.js +7 -0
  453. package/dist/senpi/constants.js.map +1 -0
  454. package/dist/senpi/index.d.ts +3 -0
  455. package/dist/senpi/index.d.ts.map +1 -0
  456. package/dist/senpi/index.js +2 -0
  457. package/dist/senpi/index.js.map +1 -0
  458. package/dist/senpi/types.d.ts +132 -0
  459. package/dist/senpi/types.d.ts.map +1 -0
  460. package/dist/senpi/types.js +3 -0
  461. package/dist/senpi/types.js.map +1 -0
  462. package/dist/state/index.d.ts +3 -0
  463. package/dist/state/index.d.ts.map +1 -0
  464. package/dist/state/index.js +3 -0
  465. package/dist/state/index.js.map +1 -0
  466. package/dist/state/paths.d.ts +8 -0
  467. package/dist/state/paths.d.ts.map +1 -0
  468. package/dist/state/paths.js +19 -0
  469. package/dist/state/paths.js.map +1 -0
  470. package/dist/state/state-manager.d.ts +58 -0
  471. package/dist/state/state-manager.d.ts.map +1 -0
  472. package/dist/state/state-manager.js +221 -0
  473. package/dist/state/state-manager.js.map +1 -0
  474. package/dist/strategy/index.d.ts +2 -0
  475. package/dist/strategy/index.d.ts.map +1 -0
  476. package/dist/strategy/index.js +2 -0
  477. package/dist/strategy/index.js.map +1 -0
  478. package/dist/strategy/strategy-state.d.ts +48 -0
  479. package/dist/strategy/strategy-state.d.ts.map +1 -0
  480. package/dist/strategy/strategy-state.js +185 -0
  481. package/dist/strategy/strategy-state.js.map +1 -0
  482. package/dist/types/action.d.ts +15 -0
  483. package/dist/types/action.d.ts.map +1 -0
  484. package/dist/types/action.js +2 -0
  485. package/dist/types/action.js.map +1 -0
  486. package/dist/types/dsl/index.d.ts +215 -0
  487. package/dist/types/dsl/index.d.ts.map +1 -0
  488. package/dist/types/dsl/index.js +5 -0
  489. package/dist/types/dsl/index.js.map +1 -0
  490. package/dist/types/event-bus.d.ts +11 -0
  491. package/dist/types/event-bus.d.ts.map +1 -0
  492. package/dist/types/event-bus.js +6 -0
  493. package/dist/types/event-bus.js.map +1 -0
  494. package/dist/types/hooks.d.ts +27 -0
  495. package/dist/types/hooks.d.ts.map +1 -0
  496. package/dist/types/hooks.js +15 -0
  497. package/dist/types/hooks.js.map +1 -0
  498. package/dist/types/index.d.ts +6 -0
  499. package/dist/types/index.d.ts.map +1 -0
  500. package/dist/types/index.js +6 -0
  501. package/dist/types/index.js.map +1 -0
  502. package/dist/types/notification.d.ts +4 -0
  503. package/dist/types/notification.d.ts.map +1 -0
  504. package/dist/types/notification.js +3 -0
  505. package/dist/types/notification.js.map +1 -0
  506. package/dist/types/runtime.d.ts +18 -0
  507. package/dist/types/runtime.d.ts.map +1 -0
  508. package/dist/types/runtime.js +2 -0
  509. package/dist/types/runtime.js.map +1 -0
  510. package/dist/types/scanner.d.ts +59 -0
  511. package/dist/types/scanner.d.ts.map +1 -0
  512. package/dist/types/scanner.js +13 -0
  513. package/dist/types/scanner.js.map +1 -0
  514. package/dist/types/strategy.d.ts +100 -0
  515. package/dist/types/strategy.d.ts.map +1 -0
  516. package/dist/types/strategy.js +2 -0
  517. package/dist/types/strategy.js.map +1 -0
  518. package/dist/utils/logger/dsl.d.ts +8 -0
  519. package/dist/utils/logger/dsl.d.ts.map +1 -0
  520. package/dist/utils/logger/dsl.js +7 -0
  521. package/dist/utils/logger/dsl.js.map +1 -0
  522. package/dist/utils/logger.d.ts +13 -0
  523. package/dist/utils/logger.d.ts.map +1 -0
  524. package/dist/utils/logger.js +65 -0
  525. package/dist/utils/logger.js.map +1 -0
  526. package/dist/utils/response.d.ts +14 -0
  527. package/dist/utils/response.d.ts.map +1 -0
  528. package/dist/utils/response.js +44 -0
  529. package/dist/utils/response.js.map +1 -0
  530. package/dist/version.d.ts +2 -0
  531. package/dist/version.d.ts.map +1 -0
  532. package/dist/version.js +2 -0
  533. package/dist/version.js.map +1 -0
  534. package/examples/.env.example +15 -0
  535. package/examples/README.md +75 -0
  536. package/examples/scanners-consumer-quickstart.mjs +134 -0
  537. package/examples/scanners-emerging-movers-v4.mjs +285 -0
  538. package/examples/scanners-liquidation-watchdog.mjs +331 -0
  539. package/examples/scanners-live-mcp.mjs +208 -0
  540. package/examples/scanners-multi-strategy.mjs +165 -0
  541. package/examples/scanners-scheduled-events.mjs +95 -0
  542. package/examples/scanners-senpi-provider-client.mjs +182 -0
  543. package/examples/scanners-single-strategy.mjs +198 -0
  544. package/examples/strategies/README.md +45 -0
  545. package/examples/strategies/dsl-showcase.yaml +60 -0
  546. package/examples/strategies/fox-minimal-loosened.yaml +201 -0
  547. package/examples/strategies/fox-minimal.yaml +209 -0
  548. package/examples/strategies/minimal.yaml +49 -0
  549. package/examples/strategies/viper.yaml +64 -0
  550. package/examples/strategies/wolf.yaml +62 -0
  551. package/examples/yamls/sample-with-dsl-and-emerging-movers.yaml +116 -0
  552. package/openclaw.plugin.json +15 -0
  553. package/package.json +52 -0
@@ -0,0 +1,285 @@
1
+ /**
2
+ * Emerging-movers v4 — signal detection showcase
3
+ *
4
+ * Demonstrates the five signal types detected by the emerging-movers scanner
5
+ * using a simulated 50-token SM leaderboard that evolves over 4 scans:
6
+ *
7
+ * Scan 1: baseline (warm-up, no signals emitted)
8
+ * Scan 2: FIRST_JUMP (WIF rockets from #45 to #3),
9
+ * CONTRIB_EXPLOSION (ONDO goes 4x contribution),
10
+ * NEW_ENTRY_DEEP (PENDLE appears at #8)
11
+ * Scan 3: IMMEDIATE_MOVER (JUP jumps 15 ranks from #28),
12
+ * DEEP_CLIMBER (RENDER climbs 6 ranks from #32)
13
+ * Scan 4: climb streak + multi-scan climbing for tokens that kept improving
14
+ *
15
+ * Run:
16
+ * npm run build && node examples/scanners-emerging-movers-v4.mjs
17
+ */
18
+ import { mkdtemp, rm } from "node:fs/promises";
19
+ import { tmpdir } from "node:os";
20
+ import { join } from "node:path";
21
+ import {
22
+ createScannerRuntimeModule,
23
+ emergingMoversScanner,
24
+ } from "../dist/scanners/index.js";
25
+
26
+ // ─── Simulated SM leaderboard ───────────────────────────────────────────────
27
+ // 50 tokens with realistic contribution and trader distributions. Specific
28
+ // tokens are manipulated across scans to trigger each v4 signal type.
29
+
30
+ function makeBaseLeaderboard() {
31
+ const tokens = [
32
+ "BTC", "ETH", "SOL", "DOGE", "PEPE", "AVAX", "LINK", "MATIC",
33
+ "ARB", "OP", "SUI", "APT", "INJ", "TIA", "SEI", "NEAR",
34
+ "FTM", "ATOM", "DOT", "ADA", "XRP", "BNB", "UNI", "AAVE",
35
+ "MKR", "LDO", "CRV", "SNX", "COMP", "ONDO", "WIF", "JUP",
36
+ "RENDER", "FET", "RNDR", "PYTH", "JTO", "STRK", "MANTA", "DYM",
37
+ "PIXEL", "PORTAL", "ETHFI", "W", "ENA", "BOME", "SLERF", "MEW",
38
+ "MYRO", "BONK",
39
+ ];
40
+
41
+ return tokens.map((token, i) => ({
42
+ token,
43
+ direction: "up",
44
+ // Contribution decreases roughly linearly; top tokens dominate
45
+ pctOfTopTradersGain: Math.max(0.001, 0.50 - i * 0.009),
46
+ traderCount: Math.max(10, 500 - i * 8),
47
+ tokenPriceChangePct4h: Math.max(-2, 8 - i * 0.3),
48
+ }));
49
+ }
50
+
51
+ /** Scan 1: Baseline snapshot. Scanner warms up (no signals emitted). */
52
+ function scan1() {
53
+ return makeBaseLeaderboard();
54
+ }
55
+
56
+ /**
57
+ * Scan 2: Three dramatic events.
58
+ * - WIF (was #31, contrib 0.230) rockets to massive contribution → lands ~#3
59
+ * - ONDO (was #30, contrib 0.239) goes 4x contribution → CONTRIB_EXPLOSION
60
+ * - PENDLE (new token, wasn't in scan 1) appears with high contribution → NEW_ENTRY_DEEP
61
+ */
62
+ function scan2() {
63
+ const board = makeBaseLeaderboard();
64
+
65
+ // WIF: was at index 30 (rank ~31). Boost contribution so it sorts to ~rank 3.
66
+ // Also: WIF was ranked 31 (>= firstJumpMinPrevRank=30), triggering FIRST_JUMP.
67
+ const wif = board.find((m) => m.token === "WIF");
68
+ wif.pctOfTopTradersGain = 0.48;
69
+ wif.traderCount = 420;
70
+ wif.tokenPriceChangePct4h = 15.2;
71
+
72
+ // ONDO: was at index 29 (rank ~30). 4x its contribution for CONTRIB_EXPLOSION.
73
+ const ondo = board.find((m) => m.token === "ONDO");
74
+ ondo.pctOfTopTradersGain = ondo.pctOfTopTradersGain * 4.5;
75
+ ondo.traderCount = 310;
76
+ ondo.tokenPriceChangePct4h = 9.1;
77
+
78
+ // JUP: boost in scan 2 so it lands ~rank 26–29 (between deepClimbRankThreshold
79
+ // and firstJumpMinPrevRank). This sets up scan 3's IMMEDIATE_MOVER — prevRank
80
+ // will be >= 25 (qualifies as deep) but < 30 (not deep enough for FIRST_JUMP).
81
+ const jup = board.find((m) => m.token === "JUP");
82
+ jup.pctOfTopTradersGain = 0.28;
83
+ jup.traderCount = 260;
84
+
85
+ // PENDLE: replace a low-ranked filler token so PENDLE appears fresh.
86
+ const pendle = board.findIndex((m) => m.token === "BONK");
87
+ board[pendle] = {
88
+ token: "PENDLE",
89
+ direction: "up",
90
+ pctOfTopTradersGain: 0.42,
91
+ traderCount: 280,
92
+ tokenPriceChangePct4h: 7.8,
93
+ };
94
+
95
+ return board;
96
+ }
97
+
98
+ /**
99
+ * Scan 3: Rank-based signals.
100
+ * - JUP jumps 15+ ranks from ~#27 → IMMEDIATE_MOVER (not FIRST_JUMP because prevRank < 30)
101
+ * - RENDER climbs 6 ranks from deep → DEEP_CLIMBER
102
+ * - PENDLE continues climbing slightly (building streak history)
103
+ */
104
+ function scan3() {
105
+ const board = makeBaseLeaderboard();
106
+
107
+ // Keep WIF high (now a returning token, not a first jump)
108
+ const wif = board.find((m) => m.token === "WIF");
109
+ wif.pctOfTopTradersGain = 0.46;
110
+ wif.traderCount = 400;
111
+
112
+ // ONDO settles back a bit (no longer 4x, so no explosion this scan)
113
+ const ondo = board.find((m) => m.token === "ONDO");
114
+ ondo.pctOfTopTradersGain = 0.35;
115
+
116
+ // PENDLE still present, climbing a bit
117
+ const pendle = board.findIndex((m) => m.token === "BONK");
118
+ board[pendle] = {
119
+ token: "PENDLE",
120
+ direction: "up",
121
+ pctOfTopTradersGain: 0.43,
122
+ traderCount: 290,
123
+ tokenPriceChangePct4h: 6.5,
124
+ };
125
+
126
+ // In scan 2, JUP was at its default position (index 31, contrib ~0.221).
127
+ // After sorting in scan 2 (with WIF and ONDO boosted), JUP lands around rank ~27.
128
+ // Here we give JUP a contribution that sorts it to ~rank 10, a jump of 15+.
129
+ // prevRank ~27 is >= deepClimbRankThreshold (25) but < firstJumpMinPrevRank (30),
130
+ // so it qualifies as IMMEDIATE_MOVER, not FIRST_JUMP.
131
+ const jup = board.find((m) => m.token === "JUP");
132
+ jup.pctOfTopTradersGain = 0.44;
133
+ jup.traderCount = 350;
134
+ jup.tokenPriceChangePct4h = 11.0;
135
+
136
+ // RENDER: was at index 32 (rank ~33). Moderate boost for DEEP_CLIMBER.
137
+ const render = board.find((m) => m.token === "RENDER");
138
+ render.pctOfTopTradersGain = 0.30;
139
+ render.traderCount = 240;
140
+ render.tokenPriceChangePct4h = 5.3;
141
+
142
+ return board;
143
+ }
144
+
145
+ /**
146
+ * Scan 4: Sustained climbing.
147
+ * - RENDER continues climbing → STREAK signal
148
+ * - PENDLE continues climbing → multi-scan CLIMBING detection
149
+ */
150
+ function scan4() {
151
+ const board = makeBaseLeaderboard();
152
+
153
+ // WIF, ONDO, JUP remain high but stable
154
+ const wif = board.find((m) => m.token === "WIF");
155
+ wif.pctOfTopTradersGain = 0.45;
156
+ const ondo = board.find((m) => m.token === "ONDO");
157
+ ondo.pctOfTopTradersGain = 0.34;
158
+ const jup = board.find((m) => m.token === "JUP");
159
+ jup.pctOfTopTradersGain = 0.43;
160
+
161
+ // PENDLE keeps climbing
162
+ const pendle = board.findIndex((m) => m.token === "BONK");
163
+ board[pendle] = {
164
+ token: "PENDLE",
165
+ direction: "up",
166
+ pctOfTopTradersGain: 0.45,
167
+ traderCount: 310,
168
+ tokenPriceChangePct4h: 8.2,
169
+ };
170
+
171
+ // RENDER continues improving
172
+ const render = board.find((m) => m.token === "RENDER");
173
+ render.pctOfTopTradersGain = 0.36;
174
+ render.traderCount = 270;
175
+ render.tokenPriceChangePct4h = 6.8;
176
+
177
+ return board;
178
+ }
179
+
180
+ // ─── Main ───────────────────────────────────────────────────────────────────
181
+
182
+ const SCAN_DATA = [scan1, scan2, scan3, scan4];
183
+
184
+ async function main() {
185
+ const stateDir = await mkdtemp(join(tmpdir(), "emerging-movers-v4-"));
186
+ let scanIndex = 0;
187
+
188
+ const module = createScannerRuntimeModule({
189
+ stateDir,
190
+ scanners: [emergingMoversScanner],
191
+ strategies: [
192
+ {
193
+ id: "wolf",
194
+ name: "Wolf Strategy",
195
+ scannerOverrides: {
196
+ "emerging-movers": {
197
+ config: {
198
+ // Production-like v4 configuration
199
+ topN: 50,
200
+ minRankJump: 5,
201
+ minTopTradersGain: 0.01,
202
+ minScansBeforeSignals: 2,
203
+ historyLimit: 60,
204
+ immediateJumpThreshold: 10,
205
+ deepClimbRankThreshold: 25,
206
+ contribExplosionMultiplier: 3.0,
207
+ contribAccelThreshold: 0.003,
208
+ minVelocityForDeepClimber: 0.0003,
209
+ erraticReversalThreshold: 5,
210
+ climbStreakScans: 3,
211
+ rankClimbThreshold: 3,
212
+ newEntryDeepMaxRank: 20,
213
+ newEntryMaxRank: 35,
214
+ firstJumpMinPrevRank: 30,
215
+ },
216
+ },
217
+ },
218
+ },
219
+ ],
220
+ providers: {
221
+ getSmData: async () => {
222
+ const data = SCAN_DATA[scanIndex]();
223
+ scanIndex++;
224
+ return data;
225
+ },
226
+ },
227
+ });
228
+
229
+ try {
230
+ for (let i = 0; i < SCAN_DATA.length; i++) {
231
+ const result = await module.runOnce("wolf", "emerging-movers");
232
+ console.log(`\n── Scan ${i + 1} ──────────────────────────────────────`);
233
+ console.log(`Status: ${result.status} | Scanned: ${result.scannedCount} | Signals: ${result.signals.length}`);
234
+
235
+ if (result.signals.length === 0) {
236
+ console.log("(warm-up scan — no signals yet)");
237
+ continue;
238
+ }
239
+
240
+ for (const signal of result.signals) {
241
+ const m = signal.meta;
242
+ console.log(
243
+ ` [${signal.signalType}] ${signal.asset}`,
244
+ `| score=${signal.score}`,
245
+ `| rank=#${m.rank}`,
246
+ `| prev=#${m.prevRank ?? "new"}`,
247
+ `| jump=${m.jump}`,
248
+ `| vel=${m.contribVelocity}`,
249
+ );
250
+ console.log(` reasons: ${(m.reasons).join(", ")}`);
251
+
252
+ const activeFactors = Object.entries(signal.factors)
253
+ .filter(([, v]) => v)
254
+ .map(([k]) => k);
255
+ if (activeFactors.length > 0) {
256
+ console.log(` factors: ${activeFactors.join(", ")}`);
257
+ }
258
+ }
259
+
260
+ // Print summary breakdown
261
+ const bd = result.summary.signalBreakdown;
262
+ const counts = Object.entries(bd).filter(([, v]) => v > 0);
263
+ if (counts.length > 0) {
264
+ console.log(` summary: ${counts.map(([k, v]) => `${k}=${v}`).join(", ")}`);
265
+ }
266
+ }
267
+
268
+ // Query all persisted signals
269
+ const allSignals = await module.querySignals({ strategyId: "wolf", limit: 50 });
270
+ console.log(`\n── Total persisted signals: ${allSignals.length} ──`);
271
+ const byType = {};
272
+ for (const s of allSignals) {
273
+ byType[s.signalType] = (byType[s.signalType] || 0) + 1;
274
+ }
275
+ console.log("By type:", byType);
276
+ } finally {
277
+ await module.stop();
278
+ await rm(stateDir, { recursive: true, force: true });
279
+ }
280
+ }
281
+
282
+ main().catch((error) => {
283
+ console.error(error);
284
+ process.exit(1);
285
+ });
@@ -0,0 +1,331 @@
1
+ /**
2
+ * Liquidation-watchdog scanner e2e examples.
3
+ *
4
+ * Run: node examples/scanners-liquidation-watchdog.mjs
5
+ *
6
+ * Two scenarios:
7
+ * 1. Without DSL states — scanner operates with margin/liq checks only.
8
+ * 2. With DSL states — scanner enriches liq-distance alerts with DSL floor info.
9
+ */
10
+
11
+ import { mkdtemp, rm } from "node:fs/promises";
12
+ import { tmpdir } from "node:os";
13
+ import { join } from "node:path";
14
+ import {
15
+ createScannerRuntimeModule,
16
+ liquidationWatchdogScanner,
17
+ } from "../dist/scanners/index.js";
18
+ import { StateManager } from "../dist/state/index.js";
19
+
20
+ // ─── Shared fixtures ────────────────────────────────────────────────────────
21
+
22
+ function makeClearingHouseState({ bufferPct, positions }) {
23
+ // bufferPct controls how much margin room is left:
24
+ // buffer = (accountValue - crossMaintenanceMargin) / accountValue * 100
25
+ // → crossMaintenanceMargin = accountValue * (1 - bufferPct / 100)
26
+ const accountValue = 10_000;
27
+ const crossMaintenanceMargin = accountValue * (1 - bufferPct / 100);
28
+ return {
29
+ accountValue,
30
+ totalMarginUsed: crossMaintenanceMargin,
31
+ crossMaintenanceMargin,
32
+ availableBalance: accountValue - crossMaintenanceMargin,
33
+ positions: positions ?? [],
34
+ };
35
+ }
36
+
37
+ function makePosition({ asset, direction, markPrice, liqPrice, roe, marginType }) {
38
+ return {
39
+ asset,
40
+ direction: direction ?? "LONG",
41
+ size: 1,
42
+ entryPrice: markPrice * 0.95,
43
+ markPrice,
44
+ liquidationPrice: liqPrice ?? null,
45
+ unrealizedPnl: markPrice * 0.05,
46
+ roe: roe ?? 5,
47
+ leverage: 5,
48
+ marginType: marginType ?? "cross",
49
+ };
50
+ }
51
+
52
+ // ─── Scenario 1: Without DSL states ─────────────────────────────────────────
53
+
54
+ async function scenarioWithoutDslStates() {
55
+ console.log("\n=== Scenario 1: Without DSL states ===\n");
56
+
57
+ const stateDir = await mkdtemp(join(tmpdir(), "watchdog-no-dsl-"));
58
+
59
+ // Two runs: first healthy, second critical
60
+ let run = 0;
61
+ const clearingHouseRuns = [
62
+ // Run 1: healthy — 80% buffer, positions far from liq
63
+ makeClearingHouseState({
64
+ bufferPct: 80,
65
+ positions: [
66
+ makePosition({ asset: "BTC", markPrice: 60000, liqPrice: 20000, roe: 12 }),
67
+ makePosition({ asset: "ETH", markPrice: 3000, liqPrice: 1000, roe: 8 }),
68
+ ],
69
+ }),
70
+ // Run 2: critical — 20% buffer, one position with bad ROE and tight liq
71
+ makeClearingHouseState({
72
+ bufferPct: 20,
73
+ positions: [
74
+ makePosition({ asset: "BTC", markPrice: 60000, liqPrice: 20000, roe: 5 }),
75
+ makePosition({ asset: "ETH", markPrice: 3000, liqPrice: 2700, roe: -25, marginType: "cross" }),
76
+ ],
77
+ }),
78
+ ];
79
+
80
+ const module = createScannerRuntimeModule({
81
+ stateDir,
82
+ scanners: [liquidationWatchdogScanner],
83
+ strategies: [
84
+ {
85
+ id: "wallet-001",
86
+ name: "Trader-A",
87
+ scannerOverrides: {
88
+ "liquidation-watchdog": {
89
+ config: {
90
+ bufferWarningPct: 50,
91
+ bufferCriticalPct: 30,
92
+ liqDistanceWarningPct: 30,
93
+ liqDistanceIsolatedWarningPct: 15,
94
+ roeDangerPct: -15,
95
+ },
96
+ },
97
+ },
98
+ },
99
+ ],
100
+ providers: {
101
+ getClearingHouseState: async () => clearingHouseRuns[Math.min(run, clearingHouseRuns.length - 1)],
102
+ getActivePositions: async () => [],
103
+ getInstruments: async () => [],
104
+ // No getDslStatesForStrategy — scanner should handle gracefully
105
+ },
106
+ });
107
+
108
+ try {
109
+ // Run 1: healthy
110
+ run = 0;
111
+ const result1 = await module.runOnce("wallet-001", "liquidation-watchdog");
112
+ console.log("Run 1 (healthy):");
113
+ console.log(" scannedCount:", result1.scannedCount);
114
+ console.log(" signals:", result1.signals.length);
115
+ console.log(" summary.marginBuffer:", result1.summary.marginBuffer);
116
+ console.log(" summary.alertCount:", result1.summary.alertCount);
117
+ console.log(" summary.consecutiveCleanChecks:", result1.summary.consecutiveCleanChecks);
118
+ console.assert(result1.signals.length === 0, "Expected 0 signals for healthy state");
119
+ console.assert(result1.summary.consecutiveCleanChecks === 1, "Expected 1 clean check");
120
+
121
+ // Run 2: critical buffer + tight liq + bad ROE
122
+ run = 1;
123
+ const result2 = await module.runOnce("wallet-001", "liquidation-watchdog");
124
+ console.log("\nRun 2 (critical):");
125
+ console.log(" scannedCount:", result2.scannedCount);
126
+ console.log(" signals:", result2.signals.length);
127
+ console.log(" summary.marginBuffer:", result2.summary.marginBuffer);
128
+ console.log(" summary.alertCount:", result2.summary.alertCount);
129
+ console.log(" summary.consecutiveCleanChecks:", result2.summary.consecutiveCleanChecks);
130
+
131
+ const closeSignals = result2.signals.filter((s) => s.signalType === "WATCHDOG_CLOSE");
132
+ const alertSignals = result2.signals.filter((s) => s.signalType === "WATCHDOG_ALERT");
133
+ console.log(" WATCHDOG_CLOSE signals:", closeSignals.length);
134
+ console.log(" WATCHDOG_ALERT signals:", alertSignals.length);
135
+
136
+ if (closeSignals.length > 0) {
137
+ console.log(" Close target asset:", closeSignals[0].asset, "(lowest ROE)");
138
+ console.log(" Close meta:", JSON.stringify(closeSignals[0].meta, null, 2));
139
+ }
140
+
141
+ // Verify no alert message contains "DSL floor" since no DSL states were provided
142
+ const allMessages = alertSignals.map((s) => s.meta.message);
143
+ const hasDslFloorNote = allMessages.some((m) => typeof m === "string" && m.includes("DSL floor"));
144
+ console.assert(!hasDslFloorNote, "Expected no DSL floor notes without dslStates provider");
145
+ console.assert(closeSignals.length >= 1, "Expected at least 1 WATCHDOG_CLOSE signal");
146
+ console.assert(closeSignals[0]?.asset === "ETH", "Expected ETH (lowest ROE) as close target");
147
+ console.assert(result2.summary.consecutiveCleanChecks === 0, "Expected 0 clean checks after alert");
148
+
149
+ console.log("\n [PASS] Scenario 1 completed successfully");
150
+ } finally {
151
+ await module.stop();
152
+ await rm(stateDir, { recursive: true, force: true });
153
+ }
154
+ }
155
+
156
+ // ─── Scenario 2: With DSL states from StateManager ──────────────────────────
157
+
158
+ async function scenarioWithDslStates() {
159
+ console.log("\n=== Scenario 2: With DSL states from StateManager ===\n");
160
+
161
+ const stateDir = await mkdtemp(join(tmpdir(), "watchdog-with-dsl-"));
162
+
163
+ // Seed the StateManager with DSL state files (as the DSL plugin would)
164
+ const stateManager = new StateManager(stateDir);
165
+
166
+ const baseDslState = {
167
+ version: 1,
168
+ address: "wallet-002",
169
+ wallet: "wallet-002",
170
+ dex: "",
171
+ highWaterPrice: 0,
172
+ hwTimestamp: new Date().toISOString(),
173
+ currentBreachCount: 0,
174
+ currentTierIndex: null,
175
+ tierFloorPrice: 0,
176
+ tiers: [],
177
+ phase1: { retraceThreshold: 5, absoluteFloor: 0, consecutiveBreachesRequired: 3 },
178
+ phase2: { retraceFromHW: 4, consecutiveBreachesRequired: 2 },
179
+ phase2TriggerTier: 0,
180
+ slOrderId: null,
181
+ lastSyncedFloorPrice: null,
182
+ slOrderIdUpdatedAt: null,
183
+ lastSlSyncError: null,
184
+ pendingClose: false,
185
+ active: true,
186
+ createdAt: new Date().toISOString(),
187
+ lastCheck: new Date().toISOString(),
188
+ consecutiveFetchFailures: 0,
189
+ tickCount: 0,
190
+ peakROE: 0,
191
+ lastError: null,
192
+ lastErrorAt: null,
193
+ closedAt: null,
194
+ closeReason: null,
195
+ };
196
+
197
+ await stateManager.setDslState("wallet-002", "BTC", "", {
198
+ ...baseDslState,
199
+ asset: "BTC",
200
+ direction: "LONG",
201
+ entryPrice: 58000,
202
+ size: 1,
203
+ leverage: 5,
204
+ highWaterPrice: 62000,
205
+ phase: 2,
206
+ currentTierIndex: 1,
207
+ tierFloorPrice: 57000,
208
+ floorPrice: 56500, // DSL floor for BTC
209
+ lastPrice: 60000,
210
+ peakROE: 15,
211
+ tickCount: 100,
212
+ });
213
+
214
+ await stateManager.setDslState("wallet-002", "SOL", "", {
215
+ ...baseDslState,
216
+ asset: "SOL",
217
+ direction: "LONG",
218
+ entryPrice: 140,
219
+ size: 10,
220
+ leverage: 5,
221
+ highWaterPrice: 155,
222
+ phase: 1,
223
+ tierFloorPrice: 135,
224
+ floorPrice: 133, // DSL floor for SOL
225
+ lastPrice: 150,
226
+ peakROE: 10,
227
+ tickCount: 50,
228
+ });
229
+
230
+ // Verify StateManager has the states
231
+ const loaded = stateManager.listDslStates("wallet-002");
232
+ console.log(" StateManager DSL states loaded:", loaded.length);
233
+ console.assert(loaded.length === 2, "Expected 2 DSL states in StateManager");
234
+
235
+ // Critical clearinghouse scenario
236
+ const clearingHouse = makeClearingHouseState({
237
+ bufferPct: 25, // CRITICAL
238
+ positions: [
239
+ makePosition({ asset: "BTC", markPrice: 60000, liqPrice: 54000, roe: 3 }), // 10% liq dist
240
+ makePosition({ asset: "SOL", markPrice: 150, liqPrice: 130, roe: -18 }), // ~13.3% liq dist
241
+ ],
242
+ });
243
+
244
+ // Wire getDslStatesForStrategy to read from the StateManager — same as Runtime does
245
+ const module = createScannerRuntimeModule({
246
+ stateDir,
247
+ scanners: [liquidationWatchdogScanner],
248
+ strategies: [
249
+ {
250
+ id: "wallet-002",
251
+ name: "Trader-B",
252
+ scannerOverrides: {
253
+ "liquidation-watchdog": {
254
+ config: {
255
+ bufferWarningPct: 50,
256
+ bufferCriticalPct: 30,
257
+ liqDistanceWarningPct: 30,
258
+ roeDangerPct: -15,
259
+ },
260
+ },
261
+ },
262
+ },
263
+ ],
264
+ providers: {
265
+ getClearingHouseState: async () => clearingHouse,
266
+ getActivePositions: async () => [],
267
+ getInstruments: async () => [],
268
+ getDslStatesForStrategy: async (address) => stateManager.listDslStates(address),
269
+ },
270
+ });
271
+
272
+ try {
273
+ const result = await module.runOnce("wallet-002", "liquidation-watchdog");
274
+
275
+ console.log("Run (critical + DSL from StateManager):");
276
+ console.log(" scannedCount:", result.scannedCount);
277
+ console.log(" signals:", result.signals.length);
278
+ console.log(" summary.marginBuffer:", result.summary.marginBuffer);
279
+ console.log(" summary.alertCount:", result.summary.alertCount);
280
+
281
+ const closeSignals = result.signals.filter((s) => s.signalType === "WATCHDOG_CLOSE");
282
+ const alertSignals = result.signals.filter((s) => s.signalType === "WATCHDOG_ALERT");
283
+ console.log(" WATCHDOG_CLOSE signals:", closeSignals.length);
284
+ console.log(" WATCHDOG_ALERT signals:", alertSignals.length);
285
+
286
+ if (closeSignals.length > 0) {
287
+ console.log(" Close target:", closeSignals[0].asset, "ROE:", closeSignals[0].meta.roe);
288
+ }
289
+
290
+ // Check that liq-distance alerts include DSL floor notes from StateManager
291
+ const liqAlertMessages = alertSignals
292
+ .filter((s) => typeof s.meta.message === "string" && s.meta.message.includes("Liquidation distance"))
293
+ .map((s) => s.meta.message);
294
+
295
+ console.log("\n Liquidation distance alert messages:");
296
+ for (const msg of liqAlertMessages) {
297
+ console.log(" -", msg);
298
+ }
299
+
300
+ const hasDslFloorNote = liqAlertMessages.some((m) => m.includes("DSL floor"));
301
+ console.assert(hasDslFloorNote, "Expected at least one liq alert with DSL floor note");
302
+ console.assert(closeSignals.length >= 1, "Expected WATCHDOG_CLOSE on critical buffer");
303
+ console.assert(closeSignals[0]?.asset === "SOL", "Expected SOL (lowest ROE -18) as close target");
304
+
305
+ // Verify BTC alert includes DSL floor $56500.00 (from StateManager)
306
+ const btcAlert = liqAlertMessages.find((m) => m.includes("BTC"));
307
+ console.assert(btcAlert?.includes("DSL floor: $56500.00"), "Expected BTC alert to contain DSL floor $56500.00 from StateManager");
308
+
309
+ // Verify SOL alert includes DSL floor $133.00 (from StateManager)
310
+ const solAlert = liqAlertMessages.find((m) => m.includes("SOL"));
311
+ console.assert(solAlert?.includes("DSL floor: $133.00"), "Expected SOL alert to contain DSL floor $133.00 from StateManager");
312
+
313
+ console.log("\n [PASS] Scenario 2 completed successfully");
314
+ } finally {
315
+ await module.stop();
316
+ await rm(stateDir, { recursive: true, force: true });
317
+ }
318
+ }
319
+
320
+ // ─── Main ───────────────────────────────────────────────────────────────────
321
+
322
+ async function main() {
323
+ await scenarioWithoutDslStates();
324
+ await scenarioWithDslStates();
325
+ console.log("\nAll scenarios passed.\n");
326
+ }
327
+
328
+ main().catch((error) => {
329
+ console.error(error);
330
+ process.exit(1);
331
+ });