@reefclaw/connect 0.1.12 → 0.1.14

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 (391) hide show
  1. package/assets/plugin/audit/mode-transition-audit.d.ts +11 -0
  2. package/assets/plugin/audit/mode-transition-audit.js +29 -0
  3. package/assets/plugin/balance-utils.d.ts +36 -0
  4. package/assets/plugin/balance-utils.js +98 -0
  5. package/assets/plugin/ccxt/binance-ban-gate.d.ts +47 -0
  6. package/assets/plugin/ccxt/binance-ban-gate.js +420 -0
  7. package/assets/plugin/ccxt/binance-private.d.ts +346 -0
  8. package/assets/plugin/ccxt/binance-private.js +1525 -0
  9. package/assets/plugin/ccxt/binance-public.d.ts +34 -0
  10. package/assets/plugin/ccxt/binance-public.js +180 -0
  11. package/assets/plugin/ccxt/intel-public.d.ts +25 -0
  12. package/assets/plugin/ccxt/intel-public.js +80 -0
  13. package/assets/plugin/ccxt/public-market-data-api.d.ts +26 -0
  14. package/assets/plugin/ccxt/public-market-data-api.js +23 -0
  15. package/assets/plugin/config/agent-config-client.d.ts +77 -0
  16. package/assets/plugin/config/agent-config-client.js +188 -0
  17. package/assets/plugin/config/agent-config-poller.d.ts +32 -0
  18. package/assets/plugin/config/agent-config-poller.js +101 -0
  19. package/assets/plugin/config/brackets-config.d.ts +22 -0
  20. package/assets/plugin/config/brackets-config.js +58 -0
  21. package/assets/plugin/config/entitlement-gate.d.ts +51 -0
  22. package/assets/plugin/config/entitlement-gate.js +137 -0
  23. package/assets/plugin/config/gate-store.d.ts +18 -0
  24. package/assets/plugin/config/gate-store.js +61 -0
  25. package/assets/plugin/config/plugin-config-io.d.ts +222 -0
  26. package/assets/plugin/config/plugin-config-io.js +126 -0
  27. package/assets/plugin/config/position-review-config.d.ts +35 -0
  28. package/assets/plugin/config/position-review-config.js +105 -0
  29. package/assets/plugin/config/tool-gate.d.ts +53 -0
  30. package/assets/plugin/config/tool-gate.js +128 -0
  31. package/assets/plugin/config/user-data-stream-config.d.ts +89 -0
  32. package/assets/plugin/config/user-data-stream-config.js +239 -0
  33. package/assets/plugin/connector-supervisor.d.ts +36 -0
  34. package/assets/plugin/connector-supervisor.js +149 -0
  35. package/assets/plugin/exchange-adapter.d.ts +65 -0
  36. package/assets/plugin/exchange-adapter.js +4 -0
  37. package/assets/plugin/index.d.ts +30 -0
  38. package/assets/plugin/index.js +2763 -0
  39. package/assets/plugin/ingest/pending-entry-metadata.d.ts +74 -0
  40. package/assets/plugin/ingest/pending-entry-metadata.js +236 -0
  41. package/assets/plugin/ingest/position-auto-capture.d.ts +171 -0
  42. package/assets/plugin/ingest/position-auto-capture.js +709 -0
  43. package/assets/plugin/ingest/position-decisions-client.d.ts +327 -0
  44. package/assets/plugin/ingest/position-decisions-client.js +306 -0
  45. package/assets/plugin/ingest/readiness-reporter.d.ts +42 -0
  46. package/assets/plugin/ingest/readiness-reporter.js +163 -0
  47. package/assets/plugin/ingest/reconcile-db-vs-exchange.d.ts +51 -0
  48. package/assets/plugin/ingest/reconcile-db-vs-exchange.js +170 -0
  49. package/assets/plugin/ingest/reconciler-cleanup.d.ts +37 -0
  50. package/assets/plugin/ingest/reconciler-cleanup.js +147 -0
  51. package/assets/plugin/ingest/rest-gap-filler.d.ts +191 -0
  52. package/assets/plugin/ingest/rest-gap-filler.js +565 -0
  53. package/assets/plugin/ingest/touched-symbols-store.d.ts +25 -0
  54. package/assets/plugin/ingest/touched-symbols-store.js +96 -0
  55. package/assets/plugin/ingest/trade-store-client.d.ts +40 -0
  56. package/assets/plugin/ingest/trade-store-client.js +125 -0
  57. package/assets/plugin/ingest/ws-ingest.d.ts +43 -0
  58. package/assets/plugin/ingest/ws-ingest.js +126 -0
  59. package/assets/plugin/learning/setup-family.d.ts +21 -0
  60. package/assets/plugin/learning/setup-family.js +103 -0
  61. package/assets/plugin/lifecycle/install-signal-handlers.d.ts +33 -0
  62. package/assets/plugin/lifecycle/install-signal-handlers.js +112 -0
  63. package/assets/plugin/lifecycle/shutdown-coordinator.d.ts +43 -0
  64. package/assets/plugin/lifecycle/shutdown-coordinator.js +131 -0
  65. package/assets/plugin/lifecycle/trading-operation-lock.d.ts +17 -0
  66. package/assets/plugin/lifecycle/trading-operation-lock.js +14 -0
  67. package/assets/plugin/live/bracket-id.d.ts +26 -0
  68. package/assets/plugin/live/bracket-id.js +112 -0
  69. package/assets/plugin/live/bracket-ledger.d.ts +54 -0
  70. package/assets/plugin/live/bracket-ledger.js +267 -0
  71. package/assets/plugin/live/bracket-manager.d.ts +82 -0
  72. package/assets/plugin/live/bracket-manager.js +478 -0
  73. package/assets/plugin/live/bracket-params.d.ts +22 -0
  74. package/assets/plugin/live/bracket-params.js +124 -0
  75. package/assets/plugin/live/bracket-reconciler.d.ts +95 -0
  76. package/assets/plugin/live/bracket-reconciler.js +573 -0
  77. package/assets/plugin/live/bracket-types.d.ts +102 -0
  78. package/assets/plugin/live/bracket-types.js +8 -0
  79. package/assets/plugin/live/deposit-tracker.d.ts +62 -0
  80. package/assets/plugin/live/deposit-tracker.js +97 -0
  81. package/assets/plugin/live/emergency-controls.d.ts +32 -0
  82. package/assets/plugin/live/emergency-controls.js +226 -0
  83. package/assets/plugin/live/exchange-errors.d.ts +12 -0
  84. package/assets/plugin/live/exchange-errors.js +130 -0
  85. package/assets/plugin/live/exchange-info-cache.d.ts +37 -0
  86. package/assets/plugin/live/exchange-info-cache.js +134 -0
  87. package/assets/plugin/live/fact-subscriber.d.ts +78 -0
  88. package/assets/plugin/live/fact-subscriber.js +182 -0
  89. package/assets/plugin/live/fill-price.d.ts +13 -0
  90. package/assets/plugin/live/fill-price.js +37 -0
  91. package/assets/plugin/live/intent-journal.d.ts +42 -0
  92. package/assets/plugin/live/intent-journal.js +122 -0
  93. package/assets/plugin/live/listen-key-manager.d.ts +70 -0
  94. package/assets/plugin/live/listen-key-manager.js +169 -0
  95. package/assets/plugin/live/live-adapter.d.ts +319 -0
  96. package/assets/plugin/live/live-adapter.js +1906 -0
  97. package/assets/plugin/live/live-balance-enricher.d.ts +32 -0
  98. package/assets/plugin/live/live-balance-enricher.js +104 -0
  99. package/assets/plugin/live/live-bracket-api.d.ts +13 -0
  100. package/assets/plugin/live/live-bracket-api.js +20 -0
  101. package/assets/plugin/live/live-state-store.d.ts +194 -0
  102. package/assets/plugin/live/live-state-store.js +450 -0
  103. package/assets/plugin/live/local-signal-service.d.ts +57 -0
  104. package/assets/plugin/live/local-signal-service.js +151 -0
  105. package/assets/plugin/live/local-strategy-evaluator.d.ts +62 -0
  106. package/assets/plugin/live/local-strategy-evaluator.js +131 -0
  107. package/assets/plugin/live/microstructure-assembler.d.ts +54 -0
  108. package/assets/plugin/live/microstructure-assembler.js +148 -0
  109. package/assets/plugin/live/order-poller.d.ts +29 -0
  110. package/assets/plugin/live/order-poller.js +125 -0
  111. package/assets/plugin/live/position-state-store.d.ts +87 -0
  112. package/assets/plugin/live/position-state-store.js +237 -0
  113. package/assets/plugin/live/proposal-decision-listener.d.ts +70 -0
  114. package/assets/plugin/live/proposal-decision-listener.js +292 -0
  115. package/assets/plugin/live/proposal-manager.d.ts +76 -0
  116. package/assets/plugin/live/proposal-manager.js +140 -0
  117. package/assets/plugin/live/rate-limiter.d.ts +47 -0
  118. package/assets/plugin/live/rate-limiter.js +159 -0
  119. package/assets/plugin/live/reconciler.d.ts +39 -0
  120. package/assets/plugin/live/reconciler.js +175 -0
  121. package/assets/plugin/live/setup-buckets.d.ts +7 -0
  122. package/assets/plugin/live/setup-buckets.js +33 -0
  123. package/assets/plugin/live/slippage-tracker.d.ts +45 -0
  124. package/assets/plugin/live/slippage-tracker.js +78 -0
  125. package/assets/plugin/live/stop-watcher.d.ts +67 -0
  126. package/assets/plugin/live/stop-watcher.js +218 -0
  127. package/assets/plugin/live/user-data-active-probe.d.ts +54 -0
  128. package/assets/plugin/live/user-data-active-probe.js +180 -0
  129. package/assets/plugin/live/user-data-stream-controller.d.ts +200 -0
  130. package/assets/plugin/live/user-data-stream-controller.js +579 -0
  131. package/assets/plugin/live/user-data-stream-ws.d.ts +22 -0
  132. package/assets/plugin/live/user-data-stream-ws.js +63 -0
  133. package/assets/plugin/live/user-data-stream.d.ts +243 -0
  134. package/assets/plugin/live/user-data-stream.js +704 -0
  135. package/assets/plugin/logger.d.ts +2 -0
  136. package/assets/plugin/logger.js +2 -0
  137. package/assets/plugin/mfe.d.ts +21 -0
  138. package/assets/plugin/mfe.js +68 -0
  139. package/assets/plugin/onboarding/mode-ladder.d.ts +1 -0
  140. package/assets/plugin/onboarding/mode-ladder.js +3 -0
  141. package/assets/plugin/onboarding/runtime.d.ts +102 -0
  142. package/assets/plugin/onboarding/runtime.js +215 -0
  143. package/assets/plugin/openclaw.plugin.json +92 -0
  144. package/assets/plugin/paper-adapter.d.ts +24 -0
  145. package/assets/plugin/paper-adapter.js +91 -0
  146. package/assets/plugin/persistence/state-manager.d.ts +66 -0
  147. package/assets/plugin/persistence/state-manager.js +222 -0
  148. package/assets/plugin/pinned-plan.d.ts +9 -0
  149. package/assets/plugin/pinned-plan.js +23 -0
  150. package/assets/plugin/portfolio/reentry-tracker.d.ts +36 -0
  151. package/assets/plugin/portfolio/reentry-tracker.js +127 -0
  152. package/assets/plugin/portfolio/wave9-admission.d.ts +67 -0
  153. package/assets/plugin/portfolio/wave9-admission.js +262 -0
  154. package/assets/plugin/portfolio/wave9-policy.d.ts +36 -0
  155. package/assets/plugin/portfolio/wave9-policy.js +183 -0
  156. package/assets/plugin/risk/pre-trade-check.d.ts +38 -0
  157. package/assets/plugin/risk/pre-trade-check.js +345 -0
  158. package/assets/plugin/risk/pre-trade-types.d.ts +60 -0
  159. package/assets/plugin/risk/pre-trade-types.js +3 -0
  160. package/assets/plugin/shadow/shadow-tracker.d.ts +36 -0
  161. package/assets/plugin/shadow/shadow-tracker.js +151 -0
  162. package/assets/plugin/shadow/types.d.ts +42 -0
  163. package/assets/plugin/shadow/types.js +20 -0
  164. package/assets/plugin/shared/indicators-extended.d.ts +52 -0
  165. package/assets/plugin/shared/indicators-extended.js +291 -0
  166. package/assets/plugin/shared/indicators.d.ts +15 -0
  167. package/assets/plugin/shared/indicators.js +114 -0
  168. package/assets/plugin/signals/conditions/registry.d.ts +16 -0
  169. package/assets/plugin/signals/conditions/registry.js +1333 -0
  170. package/assets/plugin/signals/conditions/types.d.ts +1 -0
  171. package/assets/plugin/signals/conditions/types.js +4 -0
  172. package/assets/plugin/signals/direction-rules.d.ts +3 -0
  173. package/assets/plugin/signals/direction-rules.js +24 -0
  174. package/assets/plugin/signals/entry-rules.d.ts +6 -0
  175. package/assets/plugin/signals/entry-rules.js +33 -0
  176. package/assets/plugin/signals/serialize-context.d.ts +4 -0
  177. package/assets/plugin/signals/serialize-context.js +39 -0
  178. package/assets/plugin/signals/stop-rules.d.ts +3 -0
  179. package/assets/plugin/signals/stop-rules.js +48 -0
  180. package/assets/plugin/signals/strategy-adapter.d.ts +47 -0
  181. package/assets/plugin/signals/strategy-adapter.js +209 -0
  182. package/assets/plugin/signals/types.d.ts +1 -0
  183. package/assets/plugin/signals/types.js +8 -0
  184. package/assets/plugin/simulator/exchange-simulator.d.ts +105 -0
  185. package/assets/plugin/simulator/exchange-simulator.js +759 -0
  186. package/assets/plugin/simulator/fill-engine.d.ts +53 -0
  187. package/assets/plugin/simulator/fill-engine.js +280 -0
  188. package/assets/plugin/simulator/paper-market-feed.d.ts +26 -0
  189. package/assets/plugin/simulator/paper-market-feed.js +104 -0
  190. package/assets/plugin/simulator/realistic-fills.d.ts +59 -0
  191. package/assets/plugin/simulator/realistic-fills.js +175 -0
  192. package/assets/plugin/simulator/types.d.ts +228 -0
  193. package/assets/plugin/simulator/types.js +43 -0
  194. package/assets/plugin/strategy/builtin-strategies.d.ts +2 -0
  195. package/assets/plugin/strategy/builtin-strategies.js +113 -0
  196. package/assets/plugin/strategy/condition-registry.d.ts +3 -0
  197. package/assets/plugin/strategy/condition-registry.js +153 -0
  198. package/assets/plugin/strategy/evaluator.d.ts +70 -0
  199. package/assets/plugin/strategy/evaluator.js +98 -0
  200. package/assets/plugin/tools/assessment-validation.d.ts +141 -0
  201. package/assets/plugin/tools/assessment-validation.js +473 -0
  202. package/assets/plugin/tools/attach-brackets.d.ts +39 -0
  203. package/assets/plugin/tools/attach-brackets.js +564 -0
  204. package/assets/plugin/tools/audit-bracket-protection.d.ts +49 -0
  205. package/assets/plugin/tools/audit-bracket-protection.js +683 -0
  206. package/assets/plugin/tools/bracket-control.d.ts +12 -0
  207. package/assets/plugin/tools/bracket-control.js +35 -0
  208. package/assets/plugin/tools/cancel-all-orders.d.ts +9 -0
  209. package/assets/plugin/tools/cancel-all-orders.js +8 -0
  210. package/assets/plugin/tools/cancel-order.d.ts +14 -0
  211. package/assets/plugin/tools/cancel-order.js +60 -0
  212. package/assets/plugin/tools/check-position-health.d.ts +46 -0
  213. package/assets/plugin/tools/check-position-health.js +194 -0
  214. package/assets/plugin/tools/clear-exchange-credentials.d.ts +24 -0
  215. package/assets/plugin/tools/clear-exchange-credentials.js +70 -0
  216. package/assets/plugin/tools/close-position.d.ts +45 -0
  217. package/assets/plugin/tools/close-position.js +722 -0
  218. package/assets/plugin/tools/create-order.d.ts +89 -0
  219. package/assets/plugin/tools/create-order.js +1555 -0
  220. package/assets/plugin/tools/exit-gate.d.ts +58 -0
  221. package/assets/plugin/tools/exit-gate.js +162 -0
  222. package/assets/plugin/tools/fetch-balance.d.ts +5 -0
  223. package/assets/plugin/tools/fetch-balance.js +4 -0
  224. package/assets/plugin/tools/fetch-ohlcv.d.ts +11 -0
  225. package/assets/plugin/tools/fetch-ohlcv.js +8 -0
  226. package/assets/plugin/tools/fetch-open-orders.d.ts +7 -0
  227. package/assets/plugin/tools/fetch-open-orders.js +4 -0
  228. package/assets/plugin/tools/fetch-positions.d.ts +7 -0
  229. package/assets/plugin/tools/fetch-positions.js +4 -0
  230. package/assets/plugin/tools/fetch-ticker.d.ts +11 -0
  231. package/assets/plugin/tools/fetch-ticker.js +5 -0
  232. package/assets/plugin/tools/get-agent-profile.d.ts +4 -0
  233. package/assets/plugin/tools/get-agent-profile.js +6 -0
  234. package/assets/plugin/tools/get-analytics.d.ts +6 -0
  235. package/assets/plugin/tools/get-analytics.js +7 -0
  236. package/assets/plugin/tools/get-backtest.d.ts +12 -0
  237. package/assets/plugin/tools/get-backtest.js +91 -0
  238. package/assets/plugin/tools/get-basis.d.ts +7 -0
  239. package/assets/plugin/tools/get-basis.js +7 -0
  240. package/assets/plugin/tools/get-bracket-config.d.ts +11 -0
  241. package/assets/plugin/tools/get-bracket-config.js +24 -0
  242. package/assets/plugin/tools/get-cascade-risk.d.ts +7 -0
  243. package/assets/plugin/tools/get-cascade-risk.js +8 -0
  244. package/assets/plugin/tools/get-crypto-metrics.d.ts +18 -0
  245. package/assets/plugin/tools/get-crypto-metrics.js +62 -0
  246. package/assets/plugin/tools/get-cvd.d.ts +6 -0
  247. package/assets/plugin/tools/get-cvd.js +6 -0
  248. package/assets/plugin/tools/get-divergences.d.ts +6 -0
  249. package/assets/plugin/tools/get-divergences.js +6 -0
  250. package/assets/plugin/tools/get-funding-context.d.ts +6 -0
  251. package/assets/plugin/tools/get-funding-context.js +16 -0
  252. package/assets/plugin/tools/get-liquidation-levels.d.ts +7 -0
  253. package/assets/plugin/tools/get-liquidation-levels.js +7 -0
  254. package/assets/plugin/tools/get-liquidation-pulse.d.ts +9 -0
  255. package/assets/plugin/tools/get-liquidation-pulse.js +22 -0
  256. package/assets/plugin/tools/get-market-breadth.d.ts +6 -0
  257. package/assets/plugin/tools/get-market-breadth.js +8 -0
  258. package/assets/plugin/tools/get-market-intel.d.ts +19 -0
  259. package/assets/plugin/tools/get-market-intel.js +116 -0
  260. package/assets/plugin/tools/get-market-structure.d.ts +47 -0
  261. package/assets/plugin/tools/get-market-structure.js +198 -0
  262. package/assets/plugin/tools/get-my-mined-patterns.d.ts +20 -0
  263. package/assets/plugin/tools/get-my-mined-patterns.js +61 -0
  264. package/assets/plugin/tools/get-my-proposed-learnings.d.ts +20 -0
  265. package/assets/plugin/tools/get-my-proposed-learnings.js +55 -0
  266. package/assets/plugin/tools/get-my-recent-reviews.d.ts +22 -0
  267. package/assets/plugin/tools/get-my-recent-reviews.js +66 -0
  268. package/assets/plugin/tools/get-orderbook.d.ts +21 -0
  269. package/assets/plugin/tools/get-orderbook.js +32 -0
  270. package/assets/plugin/tools/get-pattern-scan.d.ts +7 -0
  271. package/assets/plugin/tools/get-pattern-scan.js +8 -0
  272. package/assets/plugin/tools/get-regime.d.ts +6 -0
  273. package/assets/plugin/tools/get-regime.js +7 -0
  274. package/assets/plugin/tools/get-relevant-learnings.d.ts +21 -0
  275. package/assets/plugin/tools/get-relevant-learnings.js +65 -0
  276. package/assets/plugin/tools/get-resting-liquidity.d.ts +6 -0
  277. package/assets/plugin/tools/get-resting-liquidity.js +11 -0
  278. package/assets/plugin/tools/get-risk-scenario.d.ts +29 -0
  279. package/assets/plugin/tools/get-risk-scenario.js +47 -0
  280. package/assets/plugin/tools/get-risk-summary.d.ts +51 -0
  281. package/assets/plugin/tools/get-risk-summary.js +118 -0
  282. package/assets/plugin/tools/get-sentiment.d.ts +4 -0
  283. package/assets/plugin/tools/get-sentiment.js +6 -0
  284. package/assets/plugin/tools/get-session-review.d.ts +7 -0
  285. package/assets/plugin/tools/get-session-review.js +8 -0
  286. package/assets/plugin/tools/get-setup-detail.d.ts +7 -0
  287. package/assets/plugin/tools/get-setup-detail.js +322 -0
  288. package/assets/plugin/tools/get-signals.d.ts +15 -0
  289. package/assets/plugin/tools/get-signals.js +54 -0
  290. package/assets/plugin/tools/get-sizing.d.ts +6 -0
  291. package/assets/plugin/tools/get-sizing.js +6 -0
  292. package/assets/plugin/tools/get-trade-feedback.d.ts +7 -0
  293. package/assets/plugin/tools/get-trade-feedback.js +8 -0
  294. package/assets/plugin/tools/get-trade-flow.d.ts +7 -0
  295. package/assets/plugin/tools/get-trade-flow.js +7 -0
  296. package/assets/plugin/tools/get-volume-analysis.d.ts +21 -0
  297. package/assets/plugin/tools/get-volume-analysis.js +74 -0
  298. package/assets/plugin/tools/get-volume-profile.d.ts +7 -0
  299. package/assets/plugin/tools/get-volume-profile.js +7 -0
  300. package/assets/plugin/tools/get-wave9-status.d.ts +127 -0
  301. package/assets/plugin/tools/get-wave9-status.js +796 -0
  302. package/assets/plugin/tools/helpers.d.ts +26 -0
  303. package/assets/plugin/tools/helpers.js +39 -0
  304. package/assets/plugin/tools/intel-api.d.ts +34 -0
  305. package/assets/plugin/tools/intel-api.js +119 -0
  306. package/assets/plugin/tools/intel-cache.d.ts +25 -0
  307. package/assets/plugin/tools/intel-cache.js +148 -0
  308. package/assets/plugin/tools/list-strategies.d.ts +17 -0
  309. package/assets/plugin/tools/list-strategies.js +23 -0
  310. package/assets/plugin/tools/modify-stop.d.ts +21 -0
  311. package/assets/plugin/tools/modify-stop.js +120 -0
  312. package/assets/plugin/tools/modify-target.d.ts +21 -0
  313. package/assets/plugin/tools/modify-target.js +110 -0
  314. package/assets/plugin/tools/propose-learning.d.ts +22 -0
  315. package/assets/plugin/tools/propose-learning.js +65 -0
  316. package/assets/plugin/tools/query-review-outcomes.d.ts +30 -0
  317. package/assets/plugin/tools/query-review-outcomes.js +64 -0
  318. package/assets/plugin/tools/query-trades.d.ts +21 -0
  319. package/assets/plugin/tools/query-trades.js +37 -0
  320. package/assets/plugin/tools/record-position-reviews.d.ts +38 -0
  321. package/assets/plugin/tools/record-position-reviews.js +147 -0
  322. package/assets/plugin/tools/save-strategy.d.ts +16 -0
  323. package/assets/plugin/tools/save-strategy.js +46 -0
  324. package/assets/plugin/tools/scan-pairs.d.ts +22 -0
  325. package/assets/plugin/tools/scan-pairs.js +234 -0
  326. package/assets/plugin/tools/score-setup.d.ts +31 -0
  327. package/assets/plugin/tools/score-setup.js +268 -0
  328. package/assets/plugin/tools/set-bracket-requirement.d.ts +18 -0
  329. package/assets/plugin/tools/set-bracket-requirement.js +81 -0
  330. package/assets/plugin/tools/set-exchange-credentials.d.ts +25 -0
  331. package/assets/plugin/tools/set-exchange-credentials.js +80 -0
  332. package/assets/plugin/tools/set-trading-mode.d.ts +26 -0
  333. package/assets/plugin/tools/set-trading-mode.js +152 -0
  334. package/assets/plugin/tools/test-exchange-credentials.d.ts +16 -0
  335. package/assets/plugin/tools/test-exchange-credentials.js +100 -0
  336. package/assets/plugin/tools/toggle-strategy.d.ts +8 -0
  337. package/assets/plugin/tools/toggle-strategy.js +15 -0
  338. package/assets/plugin/trading-params-cache.d.ts +26 -0
  339. package/assets/plugin/trading-params-cache.js +52 -0
  340. package/assets/plugin/types.d.ts +134 -0
  341. package/assets/plugin/types.js +7 -0
  342. package/assets/plugin/util/plugin-paths.d.ts +3 -0
  343. package/assets/plugin/util/plugin-paths.js +15 -0
  344. package/assets/plugin/venues/hyperliquid/hl-balance.d.ts +116 -0
  345. package/assets/plugin/venues/hyperliquid/hl-balance.js +145 -0
  346. package/assets/plugin/venues/hyperliquid/hl-bracket-coordinator.d.ts +123 -0
  347. package/assets/plugin/venues/hyperliquid/hl-bracket-coordinator.js +533 -0
  348. package/assets/plugin/venues/hyperliquid/hl-brackets.d.ts +102 -0
  349. package/assets/plugin/venues/hyperliquid/hl-brackets.js +172 -0
  350. package/assets/plugin/venues/hyperliquid/hl-cloid.d.ts +22 -0
  351. package/assets/plugin/venues/hyperliquid/hl-cloid.js +82 -0
  352. package/assets/plugin/venues/hyperliquid/hl-info-cache.d.ts +46 -0
  353. package/assets/plugin/venues/hyperliquid/hl-info-cache.js +125 -0
  354. package/assets/plugin/venues/hyperliquid/hl-live-adapter.d.ts +146 -0
  355. package/assets/plugin/venues/hyperliquid/hl-live-adapter.js +728 -0
  356. package/assets/plugin/venues/hyperliquid/hl-precision.d.ts +61 -0
  357. package/assets/plugin/venues/hyperliquid/hl-precision.js +176 -0
  358. package/assets/plugin/venues/hyperliquid/hl-private.d.ts +88 -0
  359. package/assets/plugin/venues/hyperliquid/hl-private.js +357 -0
  360. package/assets/plugin/venues/hyperliquid/hl-public.d.ts +79 -0
  361. package/assets/plugin/venues/hyperliquid/hl-public.js +436 -0
  362. package/assets/plugin/venues/hyperliquid/hl-rate-gate.d.ts +57 -0
  363. package/assets/plugin/venues/hyperliquid/hl-rate-gate.js +220 -0
  364. package/assets/plugin/venues/hyperliquid/hl-user-stream.d.ts +90 -0
  365. package/assets/plugin/venues/hyperliquid/hl-user-stream.js +220 -0
  366. package/assets/plugin/venues/registry.d.ts +38 -0
  367. package/assets/plugin/venues/registry.js +46 -0
  368. package/assets/plugin/venues/symbols.d.ts +43 -0
  369. package/assets/plugin/venues/symbols.js +107 -0
  370. package/assets/plugin/wave9/live-account-capture.d.ts +67 -0
  371. package/assets/plugin/wave9/live-account-capture.js +435 -0
  372. package/assets/plugin/wave9/live-autonomous-protection.d.ts +39 -0
  373. package/assets/plugin/wave9/live-autonomous-protection.js +112 -0
  374. package/assets/plugin/wave9/live-durable-reconciliation-scheduler.d.ts +33 -0
  375. package/assets/plugin/wave9/live-durable-reconciliation-scheduler.js +115 -0
  376. package/assets/plugin/wave9/live-execution-ledger.d.ts +107 -0
  377. package/assets/plugin/wave9/live-execution-ledger.js +498 -0
  378. package/assets/plugin/wave9/live-position-confirmation.d.ts +18 -0
  379. package/assets/plugin/wave9/live-position-confirmation.js +111 -0
  380. package/assets/plugin/wave9/live-residual-protection.d.ts +18 -0
  381. package/assets/plugin/wave9/live-residual-protection.js +250 -0
  382. package/assets/plugin/wave9/live-startup-reconciliation.d.ts +38 -0
  383. package/assets/plugin/wave9/live-startup-reconciliation.js +454 -0
  384. package/assets/plugin/wave9/live-symbol-ownership.d.ts +20 -0
  385. package/assets/plugin/wave9/live-symbol-ownership.js +132 -0
  386. package/assets/plugin/wave9/paper-admission-guard.d.ts +199 -0
  387. package/assets/plugin/wave9/paper-admission-guard.js +650 -0
  388. package/assets/plugin/wave9/usdm-evidence-provider.d.ts +42 -0
  389. package/assets/plugin/wave9/usdm-evidence-provider.js +133 -0
  390. package/dist/plugin.js +24 -15
  391. package/package.json +1 -1
@@ -0,0 +1,66 @@
1
+ import type { SimulatorState } from '../simulator/types.js';
2
+ export declare class StateManager {
3
+ private readonly statePath;
4
+ private saveTimer;
5
+ private pendingState;
6
+ constructor(pluginId: string, baseDir?: string);
7
+ getStatePath(): string;
8
+ /** Quarantine a state file that exists but won't parse, instead of letting
9
+ * the caller silently overwrite it with a fresh default (which would wipe
10
+ * the positions/orders/realized-PnL ledger). The corrupt bytes are renamed
11
+ * to `<state>.corrupt-<ts>` so an operator can recover them. Returns true if
12
+ * a corrupt file was quarantined. */
13
+ private quarantineCorruptSync;
14
+ /** Load state from disk. Returns null when the file is MISSING (fresh start)
15
+ * OR when it exists-but-is-unreadable (in which case the corrupt bytes are
16
+ * quarantined first — never silently discarded). The two cases are
17
+ * distinguished in the log; both yield null so the caller seeds a default,
18
+ * but a corrupt file is preserved as `<state>.corrupt-<ts>`. */
19
+ load(): Promise<SimulatorState | null>;
20
+ /** Save state atomically (write to a UNIQUE temp, rename to final). A unique
21
+ * temp name (pid + uuid) is essential under the two-process model: both the
22
+ * agent and gateway processes wire stateChanged→save, and a shared
23
+ * `<state>.tmp` let their concurrent writes interleave into a torn file that
24
+ * then parses as garbage on next boot. With a per-write temp, the worst case
25
+ * degrades to a harmless last-writer-wins rename of two COMPLETE files. */
26
+ save(state: SimulatorState): Promise<void>;
27
+ /**
28
+ * Debounced save — coalesces rapid mutations into one write per second.
29
+ * Call this on every state change; it will save at most once per second.
30
+ */
31
+ debouncedSave(state: SimulatorState): void;
32
+ /** Flush any pending debounced save immediately. */
33
+ flush(): Promise<void>;
34
+ /** Load state or create default if not found. */
35
+ loadOrDefault(startingBalance: number, quoteCurrency: string): Promise<SimulatorState>;
36
+ /** Synchronous load — for use in synchronous plugin register(). Same
37
+ * missing-vs-corrupt distinction as load(): a corrupt file is quarantined
38
+ * (preserved), never silently overwritten by the default the caller seeds. */
39
+ loadSync(): SimulatorState | null;
40
+ /** Synchronous load-or-create-default — for use in synchronous plugin register(). */
41
+ loadOrDefaultSync(startingBalance: number, quoteCurrency: string): SimulatorState;
42
+ private saveSyncSafe;
43
+ }
44
+ export interface PaperQuoteMigrationResult {
45
+ state: SimulatorState;
46
+ migrated: boolean;
47
+ fromQuote: string;
48
+ releasedPositions: number;
49
+ droppedOrders: number;
50
+ }
51
+ /** Migrate a persisted paper state whose quote currency no longer matches the
52
+ * configured venue's (issue #174 — e.g. a USDT wallet after switching to the
53
+ * USDC-quoted hyperliquid venue). Pure; returns the input untouched when the
54
+ * quotes already match.
55
+ *
56
+ * Semantics (equity-preserving):
57
+ * - Open positions are released at their entry price: opening deducted the
58
+ * full entry notional from the wallet (spot-collateral model), so that
59
+ * notional is credited back before the position rows — which reference the
60
+ * OLD venue's symbols and are unpriceable on the new one — are dropped.
61
+ * - Unfilled open orders never debited the wallet (fills do) — just dropped.
62
+ * - Balances carry 1:1 (USDT↔USDC are both dollar stables; paper precision),
63
+ * merging into any existing balance under the new quote.
64
+ * - Trade history is kept (display-only). savedAt is bumped so the other
65
+ * process's replaceState() staleness guard accepts the migrated snapshot. */
66
+ export declare function migratePaperQuoteCurrency(state: SimulatorState, expectedQuote: string): PaperQuoteMigrationResult;
@@ -0,0 +1,222 @@
1
+ // State persistence manager for the paper trading simulator.
2
+ // Saves/loads state to ~/.openclaw/plugins/reefclaw-paper-trading/state.json
3
+ // Uses atomic writes (temp file + rename) to prevent corruption.
4
+ import { readFile, writeFile, rename, mkdir, unlink } from 'node:fs/promises';
5
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, renameSync } from 'node:fs';
6
+ import { homedir } from 'node:os';
7
+ import { join, dirname } from 'node:path';
8
+ import { randomUUID } from 'node:crypto';
9
+ import { logger } from '../logger.js';
10
+ import { createDefaultState } from '../simulator/types.js';
11
+ const TAG = 'state-manager';
12
+ export class StateManager {
13
+ statePath;
14
+ saveTimer = null;
15
+ pendingState = null;
16
+ constructor(pluginId, baseDir) {
17
+ const base = baseDir ?? join(homedir(), '.openclaw', 'plugins', pluginId);
18
+ this.statePath = join(base, 'state.json');
19
+ }
20
+ getStatePath() {
21
+ return this.statePath;
22
+ }
23
+ /** Quarantine a state file that exists but won't parse, instead of letting
24
+ * the caller silently overwrite it with a fresh default (which would wipe
25
+ * the positions/orders/realized-PnL ledger). The corrupt bytes are renamed
26
+ * to `<state>.corrupt-<ts>` so an operator can recover them. Returns true if
27
+ * a corrupt file was quarantined. */
28
+ quarantineCorruptSync() {
29
+ if (!existsSync(this.statePath))
30
+ return false;
31
+ const dest = `${this.statePath}.corrupt-${Date.now()}`;
32
+ try {
33
+ renameSync(this.statePath, dest);
34
+ logger.error(TAG, `State file at ${this.statePath} is unreadable/corrupt — quarantined to ${dest}. NOT resetting silently; a fresh default will be used. Investigate before trading.`);
35
+ }
36
+ catch (err) {
37
+ logger.error(TAG, `State file at ${this.statePath} is corrupt AND could not be quarantined: ${err instanceof Error ? err.message : String(err)}`);
38
+ }
39
+ return true;
40
+ }
41
+ /** Load state from disk. Returns null when the file is MISSING (fresh start)
42
+ * OR when it exists-but-is-unreadable (in which case the corrupt bytes are
43
+ * quarantined first — never silently discarded). The two cases are
44
+ * distinguished in the log; both yield null so the caller seeds a default,
45
+ * but a corrupt file is preserved as `<state>.corrupt-<ts>`. */
46
+ async load() {
47
+ if (!existsSync(this.statePath)) {
48
+ logger.info(TAG, `No state file found at ${this.statePath}`);
49
+ return null;
50
+ }
51
+ try {
52
+ const raw = await readFile(this.statePath, 'utf-8');
53
+ const state = JSON.parse(raw);
54
+ logger.info(TAG, `Loaded state: ${state.positions.length} positions, ${state.openOrders.length} orders, ${state.tradeHistory.length} trades`);
55
+ return state;
56
+ }
57
+ catch {
58
+ // Exists but unreadable/corrupt — preserve, don't silently reset.
59
+ this.quarantineCorruptSync();
60
+ return null;
61
+ }
62
+ }
63
+ /** Save state atomically (write to a UNIQUE temp, rename to final). A unique
64
+ * temp name (pid + uuid) is essential under the two-process model: both the
65
+ * agent and gateway processes wire stateChanged→save, and a shared
66
+ * `<state>.tmp` let their concurrent writes interleave into a torn file that
67
+ * then parses as garbage on next boot. With a per-write temp, the worst case
68
+ * degrades to a harmless last-writer-wins rename of two COMPLETE files. */
69
+ async save(state) {
70
+ const tmpPath = `${this.statePath}.${process.pid}.${randomUUID()}.tmp`;
71
+ try {
72
+ const dir = dirname(this.statePath);
73
+ if (!existsSync(dir)) {
74
+ await mkdir(dir, { recursive: true });
75
+ }
76
+ await writeFile(tmpPath, JSON.stringify(state, null, 2), 'utf-8');
77
+ await rename(tmpPath, this.statePath);
78
+ logger.debug(TAG, 'State saved');
79
+ }
80
+ catch (err) {
81
+ logger.error(TAG, `Failed to save state: ${err instanceof Error ? err.message : String(err)}`);
82
+ // Best-effort cleanup of the orphaned temp so they don't accumulate.
83
+ await unlink(tmpPath).catch(() => { });
84
+ }
85
+ }
86
+ /**
87
+ * Debounced save — coalesces rapid mutations into one write per second.
88
+ * Call this on every state change; it will save at most once per second.
89
+ */
90
+ debouncedSave(state) {
91
+ this.pendingState = state;
92
+ if (this.saveTimer)
93
+ return; // Already scheduled
94
+ this.saveTimer = setTimeout(() => {
95
+ this.saveTimer = null;
96
+ if (this.pendingState) {
97
+ const s = this.pendingState;
98
+ this.pendingState = null;
99
+ this.save(s).catch(() => { });
100
+ }
101
+ }, 1000);
102
+ }
103
+ /** Flush any pending debounced save immediately. */
104
+ async flush() {
105
+ if (this.saveTimer) {
106
+ clearTimeout(this.saveTimer);
107
+ this.saveTimer = null;
108
+ }
109
+ if (this.pendingState) {
110
+ const s = this.pendingState;
111
+ this.pendingState = null;
112
+ await this.save(s);
113
+ }
114
+ }
115
+ /** Load state or create default if not found. */
116
+ async loadOrDefault(startingBalance, quoteCurrency) {
117
+ const loaded = await this.load();
118
+ if (loaded)
119
+ return loaded;
120
+ const state = createDefaultState(startingBalance, quoteCurrency);
121
+ logger.info(TAG, `Initialized default state: ${startingBalance} ${quoteCurrency}`);
122
+ await this.save(state);
123
+ return state;
124
+ }
125
+ /** Synchronous load — for use in synchronous plugin register(). Same
126
+ * missing-vs-corrupt distinction as load(): a corrupt file is quarantined
127
+ * (preserved), never silently overwritten by the default the caller seeds. */
128
+ loadSync() {
129
+ if (!existsSync(this.statePath)) {
130
+ logger.info(TAG, `No state file found at ${this.statePath}`);
131
+ return null;
132
+ }
133
+ try {
134
+ const raw = readFileSync(this.statePath, 'utf-8');
135
+ const state = JSON.parse(raw);
136
+ logger.info(TAG, `Loaded state: ${state.positions.length} positions, ${state.openOrders.length} orders, ${state.tradeHistory.length} trades`);
137
+ return state;
138
+ }
139
+ catch {
140
+ this.quarantineCorruptSync();
141
+ return null;
142
+ }
143
+ }
144
+ /** Synchronous load-or-create-default — for use in synchronous plugin register(). */
145
+ loadOrDefaultSync(startingBalance, quoteCurrency) {
146
+ const loaded = this.loadSync();
147
+ if (loaded) {
148
+ // Venue switch heal (issue #174): a persisted wallet quoted in the OLD
149
+ // venue's currency reads as $0 equity on the new venue. Migrate 1:1
150
+ // (USDT↔USDC), preserving total equity exactly.
151
+ const mig = migratePaperQuoteCurrency(loaded, quoteCurrency);
152
+ if (mig.migrated) {
153
+ logger.info(TAG, `Paper wallet quote migrated ${mig.fromQuote} → ${quoteCurrency} (venue switch): ` +
154
+ `released ${mig.releasedPositions} open position(s) at entry price, ` +
155
+ `dropped ${mig.droppedOrders} unfilled order(s), balances carried 1:1`);
156
+ this.saveSyncSafe(mig.state, 'migrated');
157
+ }
158
+ return mig.state;
159
+ }
160
+ const state = createDefaultState(startingBalance, quoteCurrency);
161
+ logger.info(TAG, `Initialized default state: ${startingBalance} ${quoteCurrency}`);
162
+ // Save synchronously so state persists immediately
163
+ this.saveSyncSafe(state, 'initial');
164
+ return state;
165
+ }
166
+ saveSyncSafe(state, label) {
167
+ try {
168
+ const dir = dirname(this.statePath);
169
+ if (!existsSync(dir)) {
170
+ mkdirSync(dir, { recursive: true });
171
+ }
172
+ writeFileSync(this.statePath, JSON.stringify(state, null, 2), 'utf-8');
173
+ }
174
+ catch (err) {
175
+ logger.error(TAG, `Failed to save ${label} state: ${err instanceof Error ? err.message : String(err)}`);
176
+ }
177
+ }
178
+ }
179
+ /** Migrate a persisted paper state whose quote currency no longer matches the
180
+ * configured venue's (issue #174 — e.g. a USDT wallet after switching to the
181
+ * USDC-quoted hyperliquid venue). Pure; returns the input untouched when the
182
+ * quotes already match.
183
+ *
184
+ * Semantics (equity-preserving):
185
+ * - Open positions are released at their entry price: opening deducted the
186
+ * full entry notional from the wallet (spot-collateral model), so that
187
+ * notional is credited back before the position rows — which reference the
188
+ * OLD venue's symbols and are unpriceable on the new one — are dropped.
189
+ * - Unfilled open orders never debited the wallet (fills do) — just dropped.
190
+ * - Balances carry 1:1 (USDT↔USDC are both dollar stables; paper precision),
191
+ * merging into any existing balance under the new quote.
192
+ * - Trade history is kept (display-only). savedAt is bumped so the other
193
+ * process's replaceState() staleness guard accepts the migrated snapshot. */
194
+ export function migratePaperQuoteCurrency(state, expectedQuote) {
195
+ const fromQuote = state.config?.quoteCurrency ?? 'USDT';
196
+ if (fromQuote === expectedQuote) {
197
+ return { state, migrated: false, fromQuote, releasedPositions: 0, droppedOrders: 0 };
198
+ }
199
+ const next = JSON.parse(JSON.stringify(state));
200
+ next.config = { ...next.config, quoteCurrency: expectedQuote };
201
+ const old = next.wallet[fromQuote] ?? { total: 0, available: 0, locked: 0 };
202
+ let releasedPositions = 0;
203
+ for (const pos of next.positions ?? []) {
204
+ const notional = pos.entryPrice * pos.quantity;
205
+ if (Number.isFinite(notional) && notional > 0) {
206
+ old.total += notional;
207
+ old.available += notional;
208
+ }
209
+ releasedPositions++;
210
+ }
211
+ const droppedOrders = (next.openOrders ?? []).length;
212
+ next.positions = [];
213
+ next.openOrders = [];
214
+ const target = next.wallet[expectedQuote] ?? { total: 0, available: 0, locked: 0 };
215
+ target.total += old.total;
216
+ target.available += old.available;
217
+ target.locked += old.locked;
218
+ next.wallet[expectedQuote] = target;
219
+ delete next.wallet[fromQuote];
220
+ next.savedAt = Date.now();
221
+ return { state: next, migrated: true, fromQuote, releasedPositions, droppedOrders };
222
+ }
@@ -0,0 +1,9 @@
1
+ /** Has the agent's pinned invalidation price been reached at the current mark?
2
+ *
3
+ * Long: invalidated when mark <= invalidationPrice.
4
+ * Short: invalidated when mark >= invalidationPrice.
5
+ *
6
+ * Returns undefined when there is nothing to check — no pinned invalidation,
7
+ * or no usable mark — so a missing plan reads as "unknown", never a false
8
+ * "not hit". Pure. */
9
+ export declare function computeInvalidationHit(side: 'long' | 'short', markPrice: number | undefined, invalidationPrice: number | undefined): boolean | undefined;
@@ -0,0 +1,23 @@
1
+ // Pinned trade plan — derived indication helpers (Slice 1, Task 5).
2
+ //
3
+ // Pure functions surfaced to the agent at heartbeat (via fetch_positions →
4
+ // CcxtPosition) so it can hold to its OWN plan instead of re-litigating the
5
+ // entry every cycle. Indication only — nothing here enforces anything; the
6
+ // only forced thing on the position is that a protective stop exists.
7
+ /** Has the agent's pinned invalidation price been reached at the current mark?
8
+ *
9
+ * Long: invalidated when mark <= invalidationPrice.
10
+ * Short: invalidated when mark >= invalidationPrice.
11
+ *
12
+ * Returns undefined when there is nothing to check — no pinned invalidation,
13
+ * or no usable mark — so a missing plan reads as "unknown", never a false
14
+ * "not hit". Pure. */
15
+ export function computeInvalidationHit(side, markPrice, invalidationPrice) {
16
+ if (invalidationPrice == null ||
17
+ !Number.isFinite(invalidationPrice) ||
18
+ markPrice == null ||
19
+ !Number.isFinite(markPrice)) {
20
+ return undefined;
21
+ }
22
+ return side === 'long' ? markPrice <= invalidationPrice : markPrice >= invalidationPrice;
23
+ }
@@ -0,0 +1,36 @@
1
+ export interface ReentryExitRecord {
2
+ /** Canonical symbol (no settle suffix). */
3
+ symbol: string;
4
+ /** setup_type / strategy name from the entry metadata, when known. */
5
+ setupType?: string;
6
+ side: 'long' | 'short';
7
+ /** Whether the closed trade realized a loss (drives the stronger caution). */
8
+ wasLoss?: boolean;
9
+ closedAtMs: number;
10
+ }
11
+ /** Signal-bar duration for a strategy/setup name. Name-suffix inference:
12
+ * `..._4h` → 240min, `..._1d` / daily → 1440min, `..._Nh` → N×60. Unknown
13
+ * shapes default to 60min so short-TF strategies are never over-warned. */
14
+ export declare function strategyBarMinutes(name: string | undefined): number;
15
+ export declare class ReentryTracker {
16
+ private records;
17
+ private readonly filePath;
18
+ private readonly dir;
19
+ constructor(pluginId?: string, opts?: {
20
+ basePath?: string;
21
+ });
22
+ /** Record a position exit. Never throws (best-effort persistence). */
23
+ recordExit(record: Omit<ReentryExitRecord, 'symbol'> & {
24
+ symbol: string;
25
+ }): void;
26
+ /** Most recent exit for (symbol[, setup]). A setup-specific record wins over
27
+ * a symbol-only match so multi-strategy books get precise cautions. */
28
+ lastExit(symbol: string, setupType?: string): ReentryExitRecord | undefined;
29
+ /** Structured caution when (symbol, strategy) was already traded within the
30
+ * current signal bar. Undefined = no caution. Pure indication (issue #204):
31
+ * the agent decides; nothing here blocks an order. */
32
+ cautionFor(symbol: string, strategy: string | undefined, nowMs?: number): string | undefined;
33
+ /** Test seam. */
34
+ getRecords(): readonly ReentryExitRecord[];
35
+ private persist;
36
+ }
@@ -0,0 +1,127 @@
1
+ // Re-entry tracker — records recent position exits per (symbol, setup) so the
2
+ // entry funnel (scan_pairs / get_signals) can flag setups the agent already
3
+ // traded within the current signal bar (issue #204).
4
+ //
5
+ // WHY: the validated backtests for the 4h/1d templates have one-trade-per-
6
+ // signal semantics — a signal bar produces at most one trade. Live, the 4h
7
+ // condition stays true for hours, so after every exit the next heartbeat
8
+ // re-entered the same setup: measured 19× the backtest cadence with 79-minute
9
+ // median holds, including 22 same-direction re-entries within one bar of a
10
+ // LOSING close (2026-07-14 → 07-20 HL soak). Per the tools-not-mandates
11
+ // doctrine this ships as STRUCTURED INDICATION — the annotation tells the
12
+ // agent the setup was already traded this bar; it never blocks the order.
13
+ //
14
+ // Persistence: small JSON in the plugins base dir (same pattern as
15
+ // position-state-store) so restarts don't blind the indication. Best-effort —
16
+ // a persistence failure degrades to in-memory-only, never throws into the
17
+ // trading path.
18
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
19
+ import { join } from 'node:path';
20
+ import { logger, formatError } from '../logger.js';
21
+ import { normalizeBracketSymbol } from '../live/bracket-ledger.js';
22
+ import { resolvePluginsBaseDir } from '../util/plugin-paths.js';
23
+ const TAG = 'reentry-tracker';
24
+ const DEFAULT_PLUGIN_ID = 'reefclaw-paper-trading';
25
+ const STATE_FILENAME = 'reentry-log.json';
26
+ const MAX_RECORDS = 300;
27
+ /** Signal-bar duration for a strategy/setup name. Name-suffix inference:
28
+ * `..._4h` → 240min, `..._1d` / daily → 1440min, `..._Nh` → N×60. Unknown
29
+ * shapes default to 60min so short-TF strategies are never over-warned. */
30
+ export function strategyBarMinutes(name) {
31
+ if (!name)
32
+ return 60;
33
+ const lower = name.toLowerCase();
34
+ const hourMatch = lower.match(/_(\d{1,2})h\b|_(\d{1,2})h_|_(\d{1,2})h$/);
35
+ if (hourMatch) {
36
+ const h = Number(hourMatch[1] ?? hourMatch[2] ?? hourMatch[3]);
37
+ if (Number.isFinite(h) && h > 0)
38
+ return h * 60;
39
+ }
40
+ if (/_1d\b|_1d_|_1d$|daily/.test(lower))
41
+ return 1440;
42
+ return 60;
43
+ }
44
+ export class ReentryTracker {
45
+ records = [];
46
+ filePath;
47
+ dir;
48
+ constructor(pluginId, opts) {
49
+ const base = resolvePluginsBaseDir(opts?.basePath);
50
+ this.dir = join(base, pluginId ?? DEFAULT_PLUGIN_ID);
51
+ this.filePath = join(this.dir, STATE_FILENAME);
52
+ try {
53
+ if (!existsSync(this.dir))
54
+ mkdirSync(this.dir, { recursive: true });
55
+ if (existsSync(this.filePath)) {
56
+ const parsed = JSON.parse(readFileSync(this.filePath, 'utf-8'));
57
+ if (Array.isArray(parsed?.records)) {
58
+ this.records = parsed.records.filter((r) => typeof r?.symbol === 'string' && Number.isFinite(r?.closedAtMs));
59
+ }
60
+ }
61
+ }
62
+ catch (err) {
63
+ logger.warn(TAG, `load failed (${formatError(err)}) — starting empty`);
64
+ this.records = [];
65
+ }
66
+ }
67
+ /** Record a position exit. Never throws (best-effort persistence). */
68
+ recordExit(record) {
69
+ try {
70
+ this.records.push({ ...record, symbol: normalizeBracketSymbol(record.symbol) });
71
+ if (this.records.length > MAX_RECORDS) {
72
+ this.records = this.records.slice(-MAX_RECORDS);
73
+ }
74
+ this.persist();
75
+ }
76
+ catch (err) {
77
+ logger.warn(TAG, `recordExit failed: ${formatError(err)}`);
78
+ }
79
+ }
80
+ /** Most recent exit for (symbol[, setup]). A setup-specific record wins over
81
+ * a symbol-only match so multi-strategy books get precise cautions. */
82
+ lastExit(symbol, setupType) {
83
+ const key = normalizeBracketSymbol(symbol);
84
+ let bySetup;
85
+ let bySymbol;
86
+ for (let i = this.records.length - 1; i >= 0; i--) {
87
+ const r = this.records[i];
88
+ if (r.symbol !== key)
89
+ continue;
90
+ if (!bySymbol)
91
+ bySymbol = r;
92
+ if (setupType && r.setupType === setupType) {
93
+ bySetup = r;
94
+ break;
95
+ }
96
+ if (!setupType)
97
+ break;
98
+ }
99
+ return bySetup ?? bySymbol;
100
+ }
101
+ /** Structured caution when (symbol, strategy) was already traded within the
102
+ * current signal bar. Undefined = no caution. Pure indication (issue #204):
103
+ * the agent decides; nothing here blocks an order. */
104
+ cautionFor(symbol, strategy, nowMs = Date.now()) {
105
+ const last = this.lastExit(symbol, strategy);
106
+ if (!last)
107
+ return undefined;
108
+ const barMin = strategyBarMinutes(strategy ?? last.setupType);
109
+ const agoMin = Math.round((nowMs - last.closedAtMs) / 60_000);
110
+ if (agoMin < 0 || agoMin > barMin)
111
+ return undefined;
112
+ const lossNote = last.wasLoss ? ' at a LOSS' : '';
113
+ return (`already traded this signal bar: exited a ${last.side} on this setup ${agoMin}m ago${lossNote} ` +
114
+ `(bar=${barMin}m). The validated backtest takes ONE trade per signal bar — re-enter only if ` +
115
+ `you can name what NEW information arrived since that exit.`);
116
+ }
117
+ /** Test seam. */
118
+ getRecords() {
119
+ return this.records;
120
+ }
121
+ persist() {
122
+ const payload = { schemaVersion: 1, records: this.records };
123
+ const tmp = `${this.filePath}.tmp`;
124
+ writeFileSync(tmp, JSON.stringify(payload), 'utf-8');
125
+ renameSync(tmp, this.filePath);
126
+ }
127
+ }
@@ -0,0 +1,67 @@
1
+ import type { Direction } from '../signals/types.js';
2
+ import { type Wave9StrategyName } from './wave9-policy.js';
3
+ export interface Wave9AdmissionPolicy {
4
+ riskPct: number;
5
+ maxPositions: number;
6
+ maxOpenRiskPct: number;
7
+ maxGrossExposureMultiple: number;
8
+ maxPositionUsd: number;
9
+ feeBps: number;
10
+ slippageBps: number;
11
+ capEnforcement: 'admission_only_no_forced_deleveraging';
12
+ riskMeasure: 'fixed_initial_stop_risk_usd';
13
+ }
14
+ export declare const WAVE9_ADMISSION_POLICY: Readonly<Wave9AdmissionPolicy>;
15
+ export interface Wave9AdmissionPosition {
16
+ candidateId: string;
17
+ symbol: string;
18
+ strategy: Wave9StrategyName;
19
+ direction: Direction;
20
+ entryPrice: number;
21
+ quantity: number;
22
+ markPrice: number;
23
+ initialStop: number;
24
+ dollarRiskUsd: number;
25
+ accruedFundingUsd: number;
26
+ }
27
+ export interface Wave9AdmissionState {
28
+ cashEquityUsd: number;
29
+ positions: Wave9AdmissionPosition[];
30
+ }
31
+ export interface Wave9AdmissionCandidate {
32
+ id: string;
33
+ eventTime: string;
34
+ symbol: string;
35
+ strategy: Wave9StrategyName;
36
+ direction: Direction;
37
+ referencePrice: number;
38
+ stopPrice: number;
39
+ }
40
+ export type Wave9AdmissionReason = 'accepted' | 'invalidGeometry' | 'symbolAlreadyOpen' | 'maxPositions' | 'maxGrossExposure' | 'maxOpenRisk' | 'invalidSizing';
41
+ export interface Wave9AdmissionLedgerRow extends Wave9AdmissionPosition {
42
+ estimatedExitCostUsd: number;
43
+ }
44
+ export interface Wave9AdmissionDecision extends Wave9AdmissionCandidate {
45
+ accepted: boolean;
46
+ reason: Wave9AdmissionReason;
47
+ entryPrice?: number;
48
+ quantity?: number;
49
+ notionalUsd?: number;
50
+ riskUsd?: number;
51
+ projectedCashEquityUsd?: number;
52
+ projectedLiquidationEquityUsd?: number;
53
+ projectedGrossExposureUsd?: number;
54
+ projectedOpenRiskUsd?: number;
55
+ projectedOpenPositions?: number;
56
+ projectedPositionLedger?: Wave9AdmissionLedgerRow[];
57
+ }
58
+ export interface Wave9AdmissionBatchResult {
59
+ decisions: Wave9AdmissionDecision[];
60
+ state: Wave9AdmissionState;
61
+ }
62
+ /**
63
+ * Apply a same-event candidate batch in the exact frozen priority. The caller
64
+ * must release stops and completed-daily reversals before invoking this
65
+ * function, just as the chronological research engine does.
66
+ */
67
+ export declare function applyWave9AdmissionBatch(inputState: Wave9AdmissionState, rawCandidates: readonly Wave9AdmissionCandidate[], policy?: Readonly<Wave9AdmissionPolicy>): Wave9AdmissionBatchResult;