@reefclaw/connect 0.1.10 → 0.1.12

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 (396) hide show
  1. package/assets/bridge/gateway/event-parser.d.ts +6 -1
  2. package/assets/bridge/gateway/event-parser.js +19 -2
  3. package/assets/bridge/gateway/heartbeat-cron.d.ts +27 -0
  4. package/assets/bridge/gateway/heartbeat-cron.js +85 -0
  5. package/assets/bridge/gateway/poller.d.ts +1 -0
  6. package/assets/bridge/gateway/poller.js +14 -2
  7. package/assets/bridge/providers/gateway.d.ts +24 -2
  8. package/assets/bridge/providers/gateway.js +124 -25
  9. package/assets/bridge/setup.js +6 -51
  10. package/assets/shared/signals/conditions/registry.js +11 -2
  11. package/assets/shared/signals/strategy-adapter.js +17 -7
  12. package/assets/skill/SKILL.md +2 -0
  13. package/dist/deps.js +2 -2
  14. package/dist/plugin.js +35 -7
  15. package/package.json +1 -1
  16. package/assets/plugin/audit/mode-transition-audit.d.ts +0 -11
  17. package/assets/plugin/audit/mode-transition-audit.js +0 -29
  18. package/assets/plugin/balance-utils.d.ts +0 -36
  19. package/assets/plugin/balance-utils.js +0 -98
  20. package/assets/plugin/ccxt/binance-ban-gate.d.ts +0 -47
  21. package/assets/plugin/ccxt/binance-ban-gate.js +0 -420
  22. package/assets/plugin/ccxt/binance-private.d.ts +0 -346
  23. package/assets/plugin/ccxt/binance-private.js +0 -1525
  24. package/assets/plugin/ccxt/binance-public.d.ts +0 -34
  25. package/assets/plugin/ccxt/binance-public.js +0 -180
  26. package/assets/plugin/ccxt/intel-public.d.ts +0 -25
  27. package/assets/plugin/ccxt/intel-public.js +0 -80
  28. package/assets/plugin/ccxt/public-market-data-api.d.ts +0 -12
  29. package/assets/plugin/ccxt/public-market-data-api.js +0 -9
  30. package/assets/plugin/config/agent-config-client.d.ts +0 -77
  31. package/assets/plugin/config/agent-config-client.js +0 -188
  32. package/assets/plugin/config/agent-config-poller.d.ts +0 -32
  33. package/assets/plugin/config/agent-config-poller.js +0 -101
  34. package/assets/plugin/config/brackets-config.d.ts +0 -22
  35. package/assets/plugin/config/brackets-config.js +0 -58
  36. package/assets/plugin/config/entitlement-gate.d.ts +0 -51
  37. package/assets/plugin/config/entitlement-gate.js +0 -137
  38. package/assets/plugin/config/gate-store.d.ts +0 -18
  39. package/assets/plugin/config/gate-store.js +0 -61
  40. package/assets/plugin/config/plugin-config-io.d.ts +0 -215
  41. package/assets/plugin/config/plugin-config-io.js +0 -111
  42. package/assets/plugin/config/position-review-config.d.ts +0 -35
  43. package/assets/plugin/config/position-review-config.js +0 -105
  44. package/assets/plugin/config/tool-gate.d.ts +0 -53
  45. package/assets/plugin/config/tool-gate.js +0 -128
  46. package/assets/plugin/config/user-data-stream-config.d.ts +0 -89
  47. package/assets/plugin/config/user-data-stream-config.js +0 -239
  48. package/assets/plugin/connector-supervisor.d.ts +0 -36
  49. package/assets/plugin/connector-supervisor.js +0 -149
  50. package/assets/plugin/exchange-adapter.d.ts +0 -65
  51. package/assets/plugin/exchange-adapter.js +0 -4
  52. package/assets/plugin/index.d.ts +0 -30
  53. package/assets/plugin/index.js +0 -2678
  54. package/assets/plugin/ingest/pending-entry-metadata.d.ts +0 -74
  55. package/assets/plugin/ingest/pending-entry-metadata.js +0 -236
  56. package/assets/plugin/ingest/position-auto-capture.d.ts +0 -103
  57. package/assets/plugin/ingest/position-auto-capture.js +0 -411
  58. package/assets/plugin/ingest/position-decisions-client.d.ts +0 -322
  59. package/assets/plugin/ingest/position-decisions-client.js +0 -296
  60. package/assets/plugin/ingest/readiness-reporter.d.ts +0 -42
  61. package/assets/plugin/ingest/readiness-reporter.js +0 -163
  62. package/assets/plugin/ingest/reconcile-db-vs-exchange.d.ts +0 -13
  63. package/assets/plugin/ingest/reconcile-db-vs-exchange.js +0 -114
  64. package/assets/plugin/ingest/reconciler-cleanup.d.ts +0 -37
  65. package/assets/plugin/ingest/reconciler-cleanup.js +0 -147
  66. package/assets/plugin/ingest/rest-gap-filler.d.ts +0 -191
  67. package/assets/plugin/ingest/rest-gap-filler.js +0 -565
  68. package/assets/plugin/ingest/touched-symbols-store.d.ts +0 -25
  69. package/assets/plugin/ingest/touched-symbols-store.js +0 -96
  70. package/assets/plugin/ingest/trade-store-client.d.ts +0 -40
  71. package/assets/plugin/ingest/trade-store-client.js +0 -125
  72. package/assets/plugin/ingest/ws-ingest.d.ts +0 -43
  73. package/assets/plugin/ingest/ws-ingest.js +0 -126
  74. package/assets/plugin/learning/setup-family.d.ts +0 -21
  75. package/assets/plugin/learning/setup-family.js +0 -103
  76. package/assets/plugin/lifecycle/install-signal-handlers.d.ts +0 -33
  77. package/assets/plugin/lifecycle/install-signal-handlers.js +0 -112
  78. package/assets/plugin/lifecycle/shutdown-coordinator.d.ts +0 -43
  79. package/assets/plugin/lifecycle/shutdown-coordinator.js +0 -131
  80. package/assets/plugin/lifecycle/trading-operation-lock.d.ts +0 -17
  81. package/assets/plugin/lifecycle/trading-operation-lock.js +0 -14
  82. package/assets/plugin/live/bracket-id.d.ts +0 -26
  83. package/assets/plugin/live/bracket-id.js +0 -112
  84. package/assets/plugin/live/bracket-ledger.d.ts +0 -54
  85. package/assets/plugin/live/bracket-ledger.js +0 -267
  86. package/assets/plugin/live/bracket-manager.d.ts +0 -82
  87. package/assets/plugin/live/bracket-manager.js +0 -478
  88. package/assets/plugin/live/bracket-params.d.ts +0 -22
  89. package/assets/plugin/live/bracket-params.js +0 -124
  90. package/assets/plugin/live/bracket-reconciler.d.ts +0 -95
  91. package/assets/plugin/live/bracket-reconciler.js +0 -573
  92. package/assets/plugin/live/bracket-types.d.ts +0 -102
  93. package/assets/plugin/live/bracket-types.js +0 -8
  94. package/assets/plugin/live/deposit-tracker.d.ts +0 -62
  95. package/assets/plugin/live/deposit-tracker.js +0 -97
  96. package/assets/plugin/live/emergency-controls.d.ts +0 -32
  97. package/assets/plugin/live/emergency-controls.js +0 -226
  98. package/assets/plugin/live/exchange-errors.d.ts +0 -12
  99. package/assets/plugin/live/exchange-errors.js +0 -130
  100. package/assets/plugin/live/exchange-info-cache.d.ts +0 -37
  101. package/assets/plugin/live/exchange-info-cache.js +0 -134
  102. package/assets/plugin/live/fact-subscriber.d.ts +0 -78
  103. package/assets/plugin/live/fact-subscriber.js +0 -182
  104. package/assets/plugin/live/intent-journal.d.ts +0 -42
  105. package/assets/plugin/live/intent-journal.js +0 -122
  106. package/assets/plugin/live/listen-key-manager.d.ts +0 -70
  107. package/assets/plugin/live/listen-key-manager.js +0 -169
  108. package/assets/plugin/live/live-adapter.d.ts +0 -287
  109. package/assets/plugin/live/live-adapter.js +0 -1777
  110. package/assets/plugin/live/live-balance-enricher.d.ts +0 -32
  111. package/assets/plugin/live/live-balance-enricher.js +0 -104
  112. package/assets/plugin/live/live-bracket-api.d.ts +0 -13
  113. package/assets/plugin/live/live-bracket-api.js +0 -20
  114. package/assets/plugin/live/live-state-store.d.ts +0 -194
  115. package/assets/plugin/live/live-state-store.js +0 -450
  116. package/assets/plugin/live/local-signal-service.d.ts +0 -57
  117. package/assets/plugin/live/local-signal-service.js +0 -151
  118. package/assets/plugin/live/local-strategy-evaluator.d.ts +0 -62
  119. package/assets/plugin/live/local-strategy-evaluator.js +0 -131
  120. package/assets/plugin/live/microstructure-assembler.d.ts +0 -54
  121. package/assets/plugin/live/microstructure-assembler.js +0 -148
  122. package/assets/plugin/live/order-poller.d.ts +0 -29
  123. package/assets/plugin/live/order-poller.js +0 -125
  124. package/assets/plugin/live/position-state-store.d.ts +0 -83
  125. package/assets/plugin/live/position-state-store.js +0 -237
  126. package/assets/plugin/live/proposal-decision-listener.d.ts +0 -70
  127. package/assets/plugin/live/proposal-decision-listener.js +0 -292
  128. package/assets/plugin/live/proposal-manager.d.ts +0 -76
  129. package/assets/plugin/live/proposal-manager.js +0 -140
  130. package/assets/plugin/live/rate-limiter.d.ts +0 -47
  131. package/assets/plugin/live/rate-limiter.js +0 -159
  132. package/assets/plugin/live/reconciler.d.ts +0 -39
  133. package/assets/plugin/live/reconciler.js +0 -175
  134. package/assets/plugin/live/setup-buckets.d.ts +0 -7
  135. package/assets/plugin/live/setup-buckets.js +0 -33
  136. package/assets/plugin/live/slippage-tracker.d.ts +0 -45
  137. package/assets/plugin/live/slippage-tracker.js +0 -78
  138. package/assets/plugin/live/stop-watcher.d.ts +0 -60
  139. package/assets/plugin/live/stop-watcher.js +0 -215
  140. package/assets/plugin/live/user-data-active-probe.d.ts +0 -54
  141. package/assets/plugin/live/user-data-active-probe.js +0 -180
  142. package/assets/plugin/live/user-data-stream-controller.d.ts +0 -200
  143. package/assets/plugin/live/user-data-stream-controller.js +0 -579
  144. package/assets/plugin/live/user-data-stream-ws.d.ts +0 -22
  145. package/assets/plugin/live/user-data-stream-ws.js +0 -63
  146. package/assets/plugin/live/user-data-stream.d.ts +0 -243
  147. package/assets/plugin/live/user-data-stream.js +0 -704
  148. package/assets/plugin/logger.d.ts +0 -2
  149. package/assets/plugin/logger.js +0 -2
  150. package/assets/plugin/mfe.d.ts +0 -21
  151. package/assets/plugin/mfe.js +0 -68
  152. package/assets/plugin/onboarding/mode-ladder.d.ts +0 -1
  153. package/assets/plugin/onboarding/mode-ladder.js +0 -3
  154. package/assets/plugin/onboarding/runtime.d.ts +0 -84
  155. package/assets/plugin/onboarding/runtime.js +0 -173
  156. package/assets/plugin/openclaw.plugin.json +0 -92
  157. package/assets/plugin/paper-adapter.d.ts +0 -24
  158. package/assets/plugin/paper-adapter.js +0 -91
  159. package/assets/plugin/persistence/state-manager.d.ts +0 -66
  160. package/assets/plugin/persistence/state-manager.js +0 -222
  161. package/assets/plugin/pinned-plan.d.ts +0 -9
  162. package/assets/plugin/pinned-plan.js +0 -23
  163. package/assets/plugin/portfolio/wave9-admission.d.ts +0 -67
  164. package/assets/plugin/portfolio/wave9-admission.js +0 -262
  165. package/assets/plugin/portfolio/wave9-policy.d.ts +0 -36
  166. package/assets/plugin/portfolio/wave9-policy.js +0 -183
  167. package/assets/plugin/risk/pre-trade-check.d.ts +0 -38
  168. package/assets/plugin/risk/pre-trade-check.js +0 -345
  169. package/assets/plugin/risk/pre-trade-types.d.ts +0 -60
  170. package/assets/plugin/risk/pre-trade-types.js +0 -3
  171. package/assets/plugin/shadow/shadow-tracker.d.ts +0 -36
  172. package/assets/plugin/shadow/shadow-tracker.js +0 -151
  173. package/assets/plugin/shadow/types.d.ts +0 -42
  174. package/assets/plugin/shadow/types.js +0 -20
  175. package/assets/plugin/shared/indicators-extended.d.ts +0 -52
  176. package/assets/plugin/shared/indicators-extended.js +0 -291
  177. package/assets/plugin/shared/indicators.d.ts +0 -15
  178. package/assets/plugin/shared/indicators.js +0 -114
  179. package/assets/plugin/signals/conditions/registry.d.ts +0 -16
  180. package/assets/plugin/signals/conditions/registry.js +0 -1324
  181. package/assets/plugin/signals/conditions/types.d.ts +0 -1
  182. package/assets/plugin/signals/conditions/types.js +0 -4
  183. package/assets/plugin/signals/direction-rules.d.ts +0 -3
  184. package/assets/plugin/signals/direction-rules.js +0 -24
  185. package/assets/plugin/signals/entry-rules.d.ts +0 -6
  186. package/assets/plugin/signals/entry-rules.js +0 -33
  187. package/assets/plugin/signals/serialize-context.d.ts +0 -4
  188. package/assets/plugin/signals/serialize-context.js +0 -39
  189. package/assets/plugin/signals/stop-rules.d.ts +0 -3
  190. package/assets/plugin/signals/stop-rules.js +0 -48
  191. package/assets/plugin/signals/strategy-adapter.d.ts +0 -47
  192. package/assets/plugin/signals/strategy-adapter.js +0 -199
  193. package/assets/plugin/signals/types.d.ts +0 -1
  194. package/assets/plugin/signals/types.js +0 -8
  195. package/assets/plugin/simulator/exchange-simulator.d.ts +0 -93
  196. package/assets/plugin/simulator/exchange-simulator.js +0 -689
  197. package/assets/plugin/simulator/fill-engine.d.ts +0 -53
  198. package/assets/plugin/simulator/fill-engine.js +0 -280
  199. package/assets/plugin/simulator/paper-market-feed.d.ts +0 -26
  200. package/assets/plugin/simulator/paper-market-feed.js +0 -104
  201. package/assets/plugin/simulator/realistic-fills.d.ts +0 -59
  202. package/assets/plugin/simulator/realistic-fills.js +0 -175
  203. package/assets/plugin/simulator/types.d.ts +0 -224
  204. package/assets/plugin/simulator/types.js +0 -43
  205. package/assets/plugin/strategy/builtin-strategies.d.ts +0 -2
  206. package/assets/plugin/strategy/builtin-strategies.js +0 -113
  207. package/assets/plugin/strategy/condition-registry.d.ts +0 -3
  208. package/assets/plugin/strategy/condition-registry.js +0 -153
  209. package/assets/plugin/strategy/evaluator.d.ts +0 -70
  210. package/assets/plugin/strategy/evaluator.js +0 -98
  211. package/assets/plugin/tools/assessment-validation.d.ts +0 -120
  212. package/assets/plugin/tools/assessment-validation.js +0 -415
  213. package/assets/plugin/tools/attach-brackets.d.ts +0 -39
  214. package/assets/plugin/tools/attach-brackets.js +0 -399
  215. package/assets/plugin/tools/audit-bracket-protection.d.ts +0 -49
  216. package/assets/plugin/tools/audit-bracket-protection.js +0 -527
  217. package/assets/plugin/tools/cancel-all-orders.d.ts +0 -9
  218. package/assets/plugin/tools/cancel-all-orders.js +0 -8
  219. package/assets/plugin/tools/cancel-order.d.ts +0 -14
  220. package/assets/plugin/tools/cancel-order.js +0 -60
  221. package/assets/plugin/tools/check-position-health.d.ts +0 -46
  222. package/assets/plugin/tools/check-position-health.js +0 -194
  223. package/assets/plugin/tools/clear-exchange-credentials.d.ts +0 -24
  224. package/assets/plugin/tools/clear-exchange-credentials.js +0 -70
  225. package/assets/plugin/tools/close-position.d.ts +0 -45
  226. package/assets/plugin/tools/close-position.js +0 -722
  227. package/assets/plugin/tools/create-order.d.ts +0 -82
  228. package/assets/plugin/tools/create-order.js +0 -1516
  229. package/assets/plugin/tools/exit-gate.d.ts +0 -58
  230. package/assets/plugin/tools/exit-gate.js +0 -162
  231. package/assets/plugin/tools/fetch-balance.d.ts +0 -5
  232. package/assets/plugin/tools/fetch-balance.js +0 -4
  233. package/assets/plugin/tools/fetch-ohlcv.d.ts +0 -11
  234. package/assets/plugin/tools/fetch-ohlcv.js +0 -8
  235. package/assets/plugin/tools/fetch-open-orders.d.ts +0 -7
  236. package/assets/plugin/tools/fetch-open-orders.js +0 -4
  237. package/assets/plugin/tools/fetch-positions.d.ts +0 -7
  238. package/assets/plugin/tools/fetch-positions.js +0 -4
  239. package/assets/plugin/tools/fetch-ticker.d.ts +0 -11
  240. package/assets/plugin/tools/fetch-ticker.js +0 -5
  241. package/assets/plugin/tools/get-agent-profile.d.ts +0 -4
  242. package/assets/plugin/tools/get-agent-profile.js +0 -6
  243. package/assets/plugin/tools/get-analytics.d.ts +0 -6
  244. package/assets/plugin/tools/get-analytics.js +0 -7
  245. package/assets/plugin/tools/get-backtest.d.ts +0 -12
  246. package/assets/plugin/tools/get-backtest.js +0 -91
  247. package/assets/plugin/tools/get-basis.d.ts +0 -7
  248. package/assets/plugin/tools/get-basis.js +0 -7
  249. package/assets/plugin/tools/get-bracket-config.d.ts +0 -11
  250. package/assets/plugin/tools/get-bracket-config.js +0 -24
  251. package/assets/plugin/tools/get-cascade-risk.d.ts +0 -7
  252. package/assets/plugin/tools/get-cascade-risk.js +0 -8
  253. package/assets/plugin/tools/get-crypto-metrics.d.ts +0 -18
  254. package/assets/plugin/tools/get-crypto-metrics.js +0 -62
  255. package/assets/plugin/tools/get-cvd.d.ts +0 -6
  256. package/assets/plugin/tools/get-cvd.js +0 -6
  257. package/assets/plugin/tools/get-divergences.d.ts +0 -6
  258. package/assets/plugin/tools/get-divergences.js +0 -6
  259. package/assets/plugin/tools/get-funding-context.d.ts +0 -6
  260. package/assets/plugin/tools/get-funding-context.js +0 -16
  261. package/assets/plugin/tools/get-liquidation-levels.d.ts +0 -7
  262. package/assets/plugin/tools/get-liquidation-levels.js +0 -7
  263. package/assets/plugin/tools/get-liquidation-pulse.d.ts +0 -9
  264. package/assets/plugin/tools/get-liquidation-pulse.js +0 -22
  265. package/assets/plugin/tools/get-market-breadth.d.ts +0 -6
  266. package/assets/plugin/tools/get-market-breadth.js +0 -8
  267. package/assets/plugin/tools/get-market-intel.d.ts +0 -19
  268. package/assets/plugin/tools/get-market-intel.js +0 -116
  269. package/assets/plugin/tools/get-market-structure.d.ts +0 -47
  270. package/assets/plugin/tools/get-market-structure.js +0 -198
  271. package/assets/plugin/tools/get-my-mined-patterns.d.ts +0 -20
  272. package/assets/plugin/tools/get-my-mined-patterns.js +0 -61
  273. package/assets/plugin/tools/get-my-proposed-learnings.d.ts +0 -20
  274. package/assets/plugin/tools/get-my-proposed-learnings.js +0 -55
  275. package/assets/plugin/tools/get-my-recent-reviews.d.ts +0 -22
  276. package/assets/plugin/tools/get-my-recent-reviews.js +0 -66
  277. package/assets/plugin/tools/get-orderbook.d.ts +0 -21
  278. package/assets/plugin/tools/get-orderbook.js +0 -32
  279. package/assets/plugin/tools/get-pattern-scan.d.ts +0 -7
  280. package/assets/plugin/tools/get-pattern-scan.js +0 -8
  281. package/assets/plugin/tools/get-regime.d.ts +0 -6
  282. package/assets/plugin/tools/get-regime.js +0 -7
  283. package/assets/plugin/tools/get-relevant-learnings.d.ts +0 -21
  284. package/assets/plugin/tools/get-relevant-learnings.js +0 -65
  285. package/assets/plugin/tools/get-resting-liquidity.d.ts +0 -6
  286. package/assets/plugin/tools/get-resting-liquidity.js +0 -11
  287. package/assets/plugin/tools/get-risk-scenario.d.ts +0 -29
  288. package/assets/plugin/tools/get-risk-scenario.js +0 -47
  289. package/assets/plugin/tools/get-risk-summary.d.ts +0 -51
  290. package/assets/plugin/tools/get-risk-summary.js +0 -118
  291. package/assets/plugin/tools/get-sentiment.d.ts +0 -4
  292. package/assets/plugin/tools/get-sentiment.js +0 -6
  293. package/assets/plugin/tools/get-session-review.d.ts +0 -7
  294. package/assets/plugin/tools/get-session-review.js +0 -8
  295. package/assets/plugin/tools/get-setup-detail.d.ts +0 -7
  296. package/assets/plugin/tools/get-setup-detail.js +0 -311
  297. package/assets/plugin/tools/get-signals.d.ts +0 -15
  298. package/assets/plugin/tools/get-signals.js +0 -54
  299. package/assets/plugin/tools/get-sizing.d.ts +0 -6
  300. package/assets/plugin/tools/get-sizing.js +0 -6
  301. package/assets/plugin/tools/get-trade-feedback.d.ts +0 -7
  302. package/assets/plugin/tools/get-trade-feedback.js +0 -8
  303. package/assets/plugin/tools/get-trade-flow.d.ts +0 -7
  304. package/assets/plugin/tools/get-trade-flow.js +0 -7
  305. package/assets/plugin/tools/get-volume-analysis.d.ts +0 -21
  306. package/assets/plugin/tools/get-volume-analysis.js +0 -74
  307. package/assets/plugin/tools/get-volume-profile.d.ts +0 -7
  308. package/assets/plugin/tools/get-volume-profile.js +0 -7
  309. package/assets/plugin/tools/get-wave9-status.d.ts +0 -127
  310. package/assets/plugin/tools/get-wave9-status.js +0 -796
  311. package/assets/plugin/tools/helpers.d.ts +0 -26
  312. package/assets/plugin/tools/helpers.js +0 -39
  313. package/assets/plugin/tools/intel-api.d.ts +0 -34
  314. package/assets/plugin/tools/intel-api.js +0 -119
  315. package/assets/plugin/tools/intel-cache.d.ts +0 -25
  316. package/assets/plugin/tools/intel-cache.js +0 -148
  317. package/assets/plugin/tools/list-strategies.d.ts +0 -17
  318. package/assets/plugin/tools/list-strategies.js +0 -23
  319. package/assets/plugin/tools/modify-stop.d.ts +0 -21
  320. package/assets/plugin/tools/modify-stop.js +0 -120
  321. package/assets/plugin/tools/modify-target.d.ts +0 -21
  322. package/assets/plugin/tools/modify-target.js +0 -110
  323. package/assets/plugin/tools/propose-learning.d.ts +0 -22
  324. package/assets/plugin/tools/propose-learning.js +0 -65
  325. package/assets/plugin/tools/query-review-outcomes.d.ts +0 -30
  326. package/assets/plugin/tools/query-review-outcomes.js +0 -64
  327. package/assets/plugin/tools/query-trades.d.ts +0 -21
  328. package/assets/plugin/tools/query-trades.js +0 -37
  329. package/assets/plugin/tools/record-position-reviews.d.ts +0 -38
  330. package/assets/plugin/tools/record-position-reviews.js +0 -147
  331. package/assets/plugin/tools/save-strategy.d.ts +0 -16
  332. package/assets/plugin/tools/save-strategy.js +0 -46
  333. package/assets/plugin/tools/scan-pairs.d.ts +0 -18
  334. package/assets/plugin/tools/scan-pairs.js +0 -231
  335. package/assets/plugin/tools/score-setup.d.ts +0 -31
  336. package/assets/plugin/tools/score-setup.js +0 -268
  337. package/assets/plugin/tools/set-bracket-requirement.d.ts +0 -18
  338. package/assets/plugin/tools/set-bracket-requirement.js +0 -81
  339. package/assets/plugin/tools/set-exchange-credentials.d.ts +0 -25
  340. package/assets/plugin/tools/set-exchange-credentials.js +0 -80
  341. package/assets/plugin/tools/set-trading-mode.d.ts +0 -26
  342. package/assets/plugin/tools/set-trading-mode.js +0 -135
  343. package/assets/plugin/tools/test-exchange-credentials.d.ts +0 -16
  344. package/assets/plugin/tools/test-exchange-credentials.js +0 -100
  345. package/assets/plugin/tools/toggle-strategy.d.ts +0 -8
  346. package/assets/plugin/tools/toggle-strategy.js +0 -15
  347. package/assets/plugin/trading-params-cache.d.ts +0 -26
  348. package/assets/plugin/trading-params-cache.js +0 -52
  349. package/assets/plugin/types.d.ts +0 -134
  350. package/assets/plugin/types.js +0 -7
  351. package/assets/plugin/util/plugin-paths.d.ts +0 -3
  352. package/assets/plugin/util/plugin-paths.js +0 -15
  353. package/assets/plugin/venues/hyperliquid/hl-balance.d.ts +0 -116
  354. package/assets/plugin/venues/hyperliquid/hl-balance.js +0 -145
  355. package/assets/plugin/venues/hyperliquid/hl-brackets.d.ts +0 -102
  356. package/assets/plugin/venues/hyperliquid/hl-brackets.js +0 -172
  357. package/assets/plugin/venues/hyperliquid/hl-cloid.d.ts +0 -22
  358. package/assets/plugin/venues/hyperliquid/hl-cloid.js +0 -82
  359. package/assets/plugin/venues/hyperliquid/hl-info-cache.d.ts +0 -46
  360. package/assets/plugin/venues/hyperliquid/hl-info-cache.js +0 -125
  361. package/assets/plugin/venues/hyperliquid/hl-live-adapter.d.ts +0 -88
  362. package/assets/plugin/venues/hyperliquid/hl-live-adapter.js +0 -353
  363. package/assets/plugin/venues/hyperliquid/hl-precision.d.ts +0 -61
  364. package/assets/plugin/venues/hyperliquid/hl-precision.js +0 -176
  365. package/assets/plugin/venues/hyperliquid/hl-private.d.ts +0 -88
  366. package/assets/plugin/venues/hyperliquid/hl-private.js +0 -357
  367. package/assets/plugin/venues/hyperliquid/hl-public.d.ts +0 -79
  368. package/assets/plugin/venues/hyperliquid/hl-public.js +0 -429
  369. package/assets/plugin/venues/hyperliquid/hl-rate-gate.d.ts +0 -57
  370. package/assets/plugin/venues/hyperliquid/hl-rate-gate.js +0 -220
  371. package/assets/plugin/venues/hyperliquid/hl-user-stream.d.ts +0 -90
  372. package/assets/plugin/venues/hyperliquid/hl-user-stream.js +0 -220
  373. package/assets/plugin/venues/registry.d.ts +0 -38
  374. package/assets/plugin/venues/registry.js +0 -46
  375. package/assets/plugin/venues/symbols.d.ts +0 -43
  376. package/assets/plugin/venues/symbols.js +0 -107
  377. package/assets/plugin/wave9/live-account-capture.d.ts +0 -67
  378. package/assets/plugin/wave9/live-account-capture.js +0 -435
  379. package/assets/plugin/wave9/live-autonomous-protection.d.ts +0 -39
  380. package/assets/plugin/wave9/live-autonomous-protection.js +0 -112
  381. package/assets/plugin/wave9/live-durable-reconciliation-scheduler.d.ts +0 -33
  382. package/assets/plugin/wave9/live-durable-reconciliation-scheduler.js +0 -115
  383. package/assets/plugin/wave9/live-execution-ledger.d.ts +0 -107
  384. package/assets/plugin/wave9/live-execution-ledger.js +0 -498
  385. package/assets/plugin/wave9/live-position-confirmation.d.ts +0 -18
  386. package/assets/plugin/wave9/live-position-confirmation.js +0 -111
  387. package/assets/plugin/wave9/live-residual-protection.d.ts +0 -18
  388. package/assets/plugin/wave9/live-residual-protection.js +0 -250
  389. package/assets/plugin/wave9/live-startup-reconciliation.d.ts +0 -38
  390. package/assets/plugin/wave9/live-startup-reconciliation.js +0 -454
  391. package/assets/plugin/wave9/live-symbol-ownership.d.ts +0 -20
  392. package/assets/plugin/wave9/live-symbol-ownership.js +0 -132
  393. package/assets/plugin/wave9/paper-admission-guard.d.ts +0 -199
  394. package/assets/plugin/wave9/paper-admission-guard.js +0 -650
  395. package/assets/plugin/wave9/usdm-evidence-provider.d.ts +0 -42
  396. package/assets/plugin/wave9/usdm-evidence-provider.js +0 -133
@@ -1,689 +0,0 @@
1
- // In-memory exchange simulator.
2
- // Maintains wallet, positions, open orders, and trade history.
3
- // Emits 'stateChanged' event for persistence.
4
- //
5
- // Phase 9a: Supports realistic fills (book-aware VWAP, latency, maker/taker fees)
6
- // via SimulationConfig and OrderBookDepth.
7
- import { EventEmitter } from 'node:events';
8
- import { randomUUID } from 'node:crypto';
9
- import { logger } from '../logger.js';
10
- import { MAX_TRADE_HISTORY, DEFAULT_SIMULATION_CONFIG } from './types.js';
11
- import { fillMarketOrder, fillLimitOrder, parseSymbol } from './fill-engine.js';
12
- import { updateMfe } from '../mfe.js';
13
- import { computeInvalidationHit } from '../pinned-plan.js';
14
- const TAG = 'simulator';
15
- export class ExchangeSimulator extends EventEmitter {
16
- state;
17
- lastTicker = new Map();
18
- lastOrderBook = new Map();
19
- simulationConfig;
20
- /** Metadata for pending limit orders, keyed by order ID. Cleaned up on fill/cancel. */
21
- pendingOrderMetadata = new Map();
22
- // ---- Volatility caching (set by plugin after market structure fetch) ----
23
- cachedVolFactor = 1.0;
24
- baselineAtr = 0;
25
- atrSampleCount = 0;
26
- // ---- Startup trade lockout ----
27
- // Prevents stale agent sessions from executing trades during gateway restart.
28
- // Without this, the agent resumes mid-action and sells positions it doesn't remember.
29
- startupTime = Date.now();
30
- hadPositionsAtStartup;
31
- static STARTUP_LOCKOUT_MS = 15_000; // 15 seconds
32
- constructor(initialState, config) {
33
- super();
34
- this.state = initialState;
35
- this.simulationConfig = config ?? DEFAULT_SIMULATION_CONFIG;
36
- this.hadPositionsAtStartup = initialState.positions.length > 0;
37
- if (this.hadPositionsAtStartup) {
38
- logger.info(TAG, `Startup lockout ACTIVE for 15s — ${initialState.positions.length} existing position(s) protected`);
39
- }
40
- logger.info(TAG, `Simulator initialized: ${this.state.positions.length} positions, ${this.state.openOrders.length} open orders (realistic fills enabled)`);
41
- }
42
- // ---- Simulation config ----
43
- getSimulationConfig() {
44
- return this.simulationConfig;
45
- }
46
- // ---- Volatility factor accessors ----
47
- setVolFactor(factor) {
48
- this.cachedVolFactor = factor;
49
- }
50
- getVolFactor() {
51
- return this.cachedVolFactor;
52
- }
53
- /** Update baseline ATR using exponential moving average of samples. */
54
- updateBaselineAtr(atr14) {
55
- if (atr14 <= 0)
56
- return;
57
- this.atrSampleCount++;
58
- if (this.baselineAtr === 0) {
59
- this.baselineAtr = atr14;
60
- }
61
- else {
62
- // EMA with alpha = 2/(n+1), capped at 20 samples for stability
63
- const n = Math.min(this.atrSampleCount, 20);
64
- const alpha = 2 / (n + 1);
65
- this.baselineAtr = alpha * atr14 + (1 - alpha) * this.baselineAtr;
66
- }
67
- }
68
- getBaselineAtr() {
69
- return this.baselineAtr;
70
- }
71
- // ---- Session start NAV ----
72
- /**
73
- * Returns today's session-start NAV, lazily seeding it from current equity
74
- * if unset or stale (different UTC day). This is the plugin-side anchor used
75
- * by the pre-trade risk gate; a stale/missing anchor silently disables the
76
- * drawdown zones, so callers must never see a zero.
77
- */
78
- getSessionStartNav() {
79
- this.ensureSessionAnchor();
80
- return this.state.sessionStartNav ?? 0;
81
- }
82
- setSessionStartNav(nav) {
83
- const today = new Date().toISOString().slice(0, 10);
84
- if (this.state.sessionDate !== today || this.state.sessionStartNav === undefined) {
85
- this.state.sessionStartNav = nav;
86
- this.state.sessionDate = today;
87
- this.emitStateChanged();
88
- }
89
- }
90
- /** Seed sessionStartNav from current equity on the first check of each UTC day.
91
- * Safe to call repeatedly — no-op once the anchor matches today's date. */
92
- ensureSessionAnchor() {
93
- const today = new Date().toISOString().slice(0, 10);
94
- if (this.state.sessionDate === today && this.state.sessionStartNav !== undefined) {
95
- return;
96
- }
97
- const equity = this.computeEquity();
98
- this.state.sessionStartNav = equity;
99
- this.state.sessionDate = today;
100
- logger.info(TAG, `Session NAV anchored: $${equity.toFixed(2)} for ${today} (was: date=${this.state.sessionDate ?? 'none'}, nav=${this.state.sessionStartNav ?? 'none'})`);
101
- this.emitStateChanged();
102
- }
103
- /** Mark-to-market equity = walletTotal + for each open position, the
104
- * collateral locked at entry + current unrealized P&L. Paper simulator is
105
- * SPOT-collateral style: the full entry notional was deducted from wallet
106
- * on open and is released on close, so we must add it back here. */
107
- computeEquity() {
108
- const quote = this.getQuoteCurrency();
109
- const walletTotal = this.state.wallet[quote]?.total ?? 0;
110
- let positionEquity = 0;
111
- for (const pos of this.state.positions) {
112
- const ticker = this.lastTicker.get(pos.symbol);
113
- const mark = ticker?.last ?? pos.entryPrice;
114
- const entryNotional = pos.entryPrice * pos.quantity;
115
- const unrealized = pos.side === 'long'
116
- ? (mark - pos.entryPrice) * pos.quantity
117
- : (pos.entryPrice - mark) * pos.quantity;
118
- positionEquity += entryNotional + unrealized;
119
- }
120
- return walletTotal + positionEquity;
121
- }
122
- getQuoteCurrency() {
123
- return this.state.config?.quoteCurrency ?? 'USDT';
124
- }
125
- // ---- Read operations (for tools) ----
126
- getBalance() {
127
- const free = {};
128
- const used = {};
129
- const total = {};
130
- const result = { free, used, total };
131
- // Derivatives model: only quote currency (USDT) in wallet
132
- for (const [currency, bal] of Object.entries(this.state.wallet)) {
133
- free[currency] = bal.available;
134
- used[currency] = bal.locked;
135
- total[currency] = bal.total;
136
- result[currency] = {
137
- free: bal.available,
138
- used: bal.locked,
139
- total: bal.total,
140
- };
141
- }
142
- // All-time realized P&L from trade history (restart-proof).
143
- // Includes BOTH open-side and close-side fees — prior versions omitted the
144
- // open-side fee and under-reported fee drag by ~50%.
145
- let realizedPnlAllTime = 0;
146
- let totalRoundtripFees = 0;
147
- const today = new Date().toISOString().slice(0, 10);
148
- let realizedPnlToday = 0;
149
- for (const t of this.state.tradeHistory) {
150
- const roundtripFee = t.fee + (t.openFee ?? 0);
151
- const net = t.realizedPnl - roundtripFee;
152
- realizedPnlAllTime += net;
153
- totalRoundtripFees += roundtripFee;
154
- if (typeof t.closedAt === 'string' && t.closedAt.slice(0, 10) === today) {
155
- realizedPnlToday += net;
156
- }
157
- }
158
- const round4 = (n) => +n.toFixed(4);
159
- result.realizedPnlAllTime = round4(realizedPnlAllTime);
160
- result.realizedPnlToday = round4(realizedPnlToday);
161
- result.totalRoundtripFees = round4(totalRoundtripFees);
162
- // Session execution-quality costs (since boot) for the dashboard cost cells
163
- // (M1). These are the SAME fees/slippage already baked into equity/NAV —
164
- // surfaced so the "Fees" / "Avg Slip" breakdown cells don't read $0 while
165
- // the headline PnL clearly shows the drag.
166
- const execStats = this.state.executionStats;
167
- result.sessionFeesPaid = round4(execStats?.totalFeesPaid ?? 0);
168
- result.sessionAvgSlippageBps = round4(execStats?.avgSlippageBps ?? 0);
169
- // Equity = mark-to-market total account value. Use this (NOT walletTotal)
170
- // for heat / leverage / exposure math — walletTotal drops as notional is
171
- // locked into open positions, but that collateral is released on close.
172
- const equity = this.computeEquity();
173
- result.equity = round4(equity);
174
- // Session anchor (for drawdown zone calculation). Side-effect: seeds on
175
- // first read each UTC day if stale/missing.
176
- const sessionNav = this.getSessionStartNav();
177
- result.sessionStartNav = round4(sessionNav);
178
- return result;
179
- }
180
- getPositions(symbol) {
181
- const positions = symbol
182
- ? this.state.positions.filter(p => p.symbol === symbol)
183
- : this.state.positions;
184
- return positions.map(p => {
185
- const ticker = this.lastTicker.get(p.symbol);
186
- const markPrice = ticker?.last ?? p.entryPrice;
187
- const notional = p.quantity * markPrice;
188
- const pnlMultiplier = p.side === 'long' ? 1 : -1;
189
- const unrealizedPnl = (markPrice - p.entryPrice) * p.quantity * pnlMultiplier;
190
- const percentage = p.entryPrice > 0
191
- ? ((markPrice - p.entryPrice) / p.entryPrice) * 100 * pnlMultiplier
192
- : 0;
193
- return {
194
- symbol: p.symbol,
195
- side: p.side,
196
- contracts: p.quantity,
197
- contractSize: 1,
198
- entryPrice: p.entryPrice,
199
- markPrice,
200
- notional,
201
- unrealizedPnl,
202
- percentage,
203
- timestamp: Date.now(),
204
- datetime: new Date().toISOString(),
205
- // Surface entry metadata (if available)
206
- ...(p.metadata && {
207
- setupType: p.metadata.setupType,
208
- missionId: p.metadata.missionId,
209
- candidateId: p.metadata.candidateId,
210
- strategy: p.metadata.strategy,
211
- accruedFundingUsd: p.metadata.accruedFundingUsd,
212
- fundingThroughTime: p.metadata.fundingThroughTime,
213
- thesis: p.metadata.thesis,
214
- stopPrice: p.metadata.stopPrice,
215
- targetPrice: p.metadata.targetPrice,
216
- regime: p.metadata.regime,
217
- regimeConfidence: p.metadata.regimeConfidence,
218
- scorecardVerdict: p.metadata.scorecardVerdict,
219
- confluenceScore: p.metadata.confluenceScore,
220
- originalStopPrice: p.metadata.originalStopPrice,
221
- mfePeakPrice: p.metadata.mfePeakPrice,
222
- mfeR: p.metadata.mfeR,
223
- giveBackRatio: p.metadata.giveBackRatio,
224
- invalidationPrice: p.metadata.invalidationPrice,
225
- realizationRule: p.metadata.realizationRule,
226
- invalidationHit: computeInvalidationHit(p.side, markPrice, p.metadata.invalidationPrice),
227
- }),
228
- };
229
- });
230
- }
231
- getOpenOrders(symbol) {
232
- const orders = symbol
233
- ? this.state.openOrders.filter(o => o.symbol === symbol)
234
- : this.state.openOrders;
235
- return orders.map(o => this.toCcxtOrder(o));
236
- }
237
- /** Get cumulative execution quality stats. */
238
- getExecutionStats() {
239
- return this.state.executionStats;
240
- }
241
- // ---- Order book ----
242
- /** Cache the latest order book snapshot for a symbol. */
243
- updateOrderBook(symbol, orderbook) {
244
- this.lastOrderBook.set(symbol, orderbook);
245
- }
246
- getLastOrderBook(symbol) {
247
- return this.lastOrderBook.get(symbol);
248
- }
249
- // ---- Write operations (for tools) ----
250
- createOrder(symbol, side, type, amount, price, metadata) {
251
- // ---- Startup trade lockout ----
252
- // Block trades during the first 15s after gateway restart IF there were
253
- // existing positions at startup. This prevents stale agent sessions from
254
- // selling positions before the session is cleared and the agent re-reads SKILL.md.
255
- // Only activates when positions exist (nothing to protect if starting empty).
256
- const elapsed = Date.now() - this.startupTime;
257
- if (this.hadPositionsAtStartup && elapsed < ExchangeSimulator.STARTUP_LOCKOUT_MS) {
258
- const remaining = Math.ceil((ExchangeSimulator.STARTUP_LOCKOUT_MS - elapsed) / 1000);
259
- logger.warn(TAG, `STARTUP LOCKOUT: Blocked ${side} ${amount} ${symbol} — ${remaining}s remaining. This prevents stale session trades during restart.`);
260
- throw new Error(`Trade blocked: startup lockout (${remaining}s remaining). The gateway just restarted — wait for the agent to re-read its instructions and check positions before trading.`);
261
- }
262
- if (amount <= 0) {
263
- throw new Error('Order amount must be positive');
264
- }
265
- if (type === 'limit' && (price === undefined || price <= 0)) {
266
- throw new Error('Limit orders require a positive price');
267
- }
268
- const now = new Date().toISOString();
269
- const order = {
270
- id: randomUUID(),
271
- symbol,
272
- side,
273
- type,
274
- status: 'open',
275
- amount,
276
- price: type === 'limit' ? price : null,
277
- filled: 0,
278
- average: null,
279
- cost: 0,
280
- fee: { cost: 0, currency: parseSymbol(symbol).quote },
281
- createdAt: now,
282
- };
283
- if (type === 'market') {
284
- // Market orders fill immediately at current price
285
- const ticker = this.lastTicker.get(symbol);
286
- if (!ticker) {
287
- throw new Error(`No ticker data for ${symbol}. Call updateTicker() first.`);
288
- }
289
- return this.executeMarketFill(order, ticker.last, metadata);
290
- }
291
- // Limit order — check if it crosses the current price
292
- const ticker = this.lastTicker.get(symbol);
293
- if (ticker && this.shouldFillLimit(order, ticker.last)) {
294
- return this.executeLimitFill(order, ticker.last, metadata);
295
- }
296
- // Limit order doesn't cross — add to open orders. Pin the entry metadata
297
- // ONTO the order itself (durable home, persisted in state.json) AND in the
298
- // in-memory cache (fast path). order.metadata is the one that survives a
299
- // restart / two-process reload, so a resting limit never fills naked.
300
- if (metadata) {
301
- order.metadata = metadata;
302
- this.pendingOrderMetadata.set(order.id, metadata);
303
- }
304
- this.state.openOrders.push(order);
305
- this.emitStateChanged();
306
- logger.info(TAG, `Limit order created: ${side} ${amount} ${symbol} @ ${price}`);
307
- return this.toCcxtOrder(order);
308
- }
309
- cancelOrder(orderId) {
310
- const idx = this.state.openOrders.findIndex(o => o.id === orderId);
311
- if (idx === -1) {
312
- throw new Error(`Order not found: ${orderId}`);
313
- }
314
- const order = this.state.openOrders.splice(idx, 1)[0];
315
- order.status = 'canceled';
316
- this.pendingOrderMetadata.delete(orderId);
317
- this.emitStateChanged();
318
- logger.info(TAG, `Order cancelled: ${orderId}`);
319
- return this.toCcxtOrder(order);
320
- }
321
- cancelAllOrders(symbol) {
322
- const cancelled = [];
323
- const remaining = [];
324
- for (const order of this.state.openOrders) {
325
- if (!symbol || order.symbol === symbol) {
326
- order.status = 'canceled';
327
- cancelled.push(order);
328
- this.pendingOrderMetadata.delete(order.id);
329
- }
330
- else {
331
- remaining.push(order);
332
- }
333
- }
334
- this.state.openOrders = remaining;
335
- if (cancelled.length > 0) {
336
- this.emitStateChanged();
337
- logger.info(TAG, `Cancelled ${cancelled.length} orders${symbol ? ` for ${symbol}` : ''}`);
338
- }
339
- return cancelled.map(o => this.toCcxtOrder(o));
340
- }
341
- closePosition(symbol, closeReason) {
342
- const position = this.state.positions.find(p => p.symbol === symbol);
343
- if (!position) {
344
- throw new Error(`No open position for ${symbol}`);
345
- }
346
- // Tag the position's metadata with the close reason BEFORE firing the close
347
- // order. The closing Trade record copies `existingPosition.metadata` in
348
- // fill-engine.executeOrderFill, so this is what makes the reason reach
349
- // the trade history (and therefore the agent on its next heartbeat).
350
- if (closeReason) {
351
- position.metadata = { ...(position.metadata ?? {}), closeReason };
352
- }
353
- // Create opposing market order to close the position
354
- const closeSide = position.side === 'long' ? 'sell' : 'buy';
355
- return this.createOrder(symbol, closeSide, 'market', position.quantity);
356
- }
357
- /** Paper-only: move an open position's MUTABLE protective levels (stopPrice /
358
- * targetPrice) in place and persist, WITHOUT the close+reopen round-trip
359
- * (which pays an extra taker fee and resets the R/MFE denominators). The
360
- * frozen originalStopPrice / originalEntryPrice are intentionally left
361
- * untouched so R-multiples stay anchored at entry. The paper stop-watcher
362
- * and getPositions both read metadata.stopPrice, so a moved stop takes
363
- * effect on the next watcher tick. Throws if there is no open position. (M9) */
364
- updatePositionMetadata(symbol, patch) {
365
- const pos = this.state.positions.find(p => p.symbol === symbol);
366
- if (!pos) {
367
- throw new Error(`No open position for ${symbol}`);
368
- }
369
- const meta = { ...(pos.metadata ?? {}) };
370
- if (patch.stopPrice !== undefined)
371
- meta.stopPrice = patch.stopPrice;
372
- if (patch.targetPrice !== undefined)
373
- meta.targetPrice = patch.targetPrice;
374
- pos.metadata = meta;
375
- this.emitStateChanged();
376
- }
377
- // ---- Ticker updates (checks pending limit fills) ----
378
- updateTicker(ticker) {
379
- this.lastTicker.set(ticker.symbol, ticker);
380
- this.refreshMfeForSymbol(ticker.symbol, ticker.last);
381
- // Check if any pending limit orders should fill
382
- const toFill = [];
383
- const remaining = [];
384
- for (const order of this.state.openOrders) {
385
- if (order.symbol === ticker.symbol && this.shouldFillLimit(order, ticker.last)) {
386
- toFill.push(order);
387
- }
388
- else {
389
- remaining.push(order);
390
- }
391
- }
392
- if (toFill.length > 0) {
393
- this.state.openOrders = remaining;
394
- for (const order of toFill) {
395
- // Prefer the durable metadata pinned on the order (survives restart);
396
- // fall back to the in-memory cache for any legacy in-flight order.
397
- const meta = order.metadata ?? this.pendingOrderMetadata.get(order.id);
398
- try {
399
- this.executeLimitFill(order, ticker.last, meta);
400
- // Clear the cache only AFTER a successful fill so a throw-then-retry
401
- // (e.g. transient insufficient balance) keeps the metadata for the
402
- // next tick instead of filling naked.
403
- this.pendingOrderMetadata.delete(order.id);
404
- }
405
- catch (err) {
406
- // Fill failed (e.g. insufficient balance) — restore order to open
407
- // list. order.metadata stays intact, so the retry is not naked.
408
- order.status = 'open';
409
- this.state.openOrders.push(order);
410
- const message = err instanceof Error ? err.message : String(err);
411
- logger.warn(TAG, `Limit fill failed for ${order.id}, order restored: ${message}`);
412
- this.emit('fillError', {
413
- orderId: order.id,
414
- symbol: order.symbol,
415
- error: message,
416
- timestamp: new Date().toISOString(),
417
- });
418
- }
419
- }
420
- }
421
- }
422
- getLastTicker(symbol) {
423
- return this.lastTicker.get(symbol);
424
- }
425
- /** Walk every position for `symbol` and refresh MFE / give-back from the
426
- * latest mark. Idempotent — pure update of `metadata.mfePeakPrice` (only
427
- * ratchets favourably) plus derived `mfeR` and `giveBackRatio`. Safe to
428
- * call before any positions exist (no-op). */
429
- refreshMfeForSymbol(symbol, mark) {
430
- if (!Number.isFinite(mark) || mark <= 0)
431
- return;
432
- let peakAdvanced = false;
433
- for (const p of this.state.positions) {
434
- if (p.symbol !== symbol)
435
- continue;
436
- const meta = { ...(p.metadata ?? {}) };
437
- const priorPeak = meta.mfePeakPrice;
438
- const out = updateMfe({
439
- side: p.side,
440
- // R/MFE are denominated against the FROZEN original entry (and stop),
441
- // never the running averaged entryPrice — otherwise a scale-in
442
- // retroactively shrinks an already-achieved excursion (M4).
443
- entryPrice: meta.originalEntryPrice ?? p.entryPrice,
444
- originalStopPrice: meta.originalStopPrice,
445
- markPrice: mark,
446
- priorPeakPrice: meta.mfePeakPrice,
447
- });
448
- if (out.mfePeakPrice !== priorPeak)
449
- peakAdvanced = true;
450
- meta.mfePeakPrice = out.mfePeakPrice;
451
- meta.mfeR = out.mfeR;
452
- meta.giveBackRatio = out.giveBackRatio;
453
- p.metadata = meta;
454
- }
455
- // Persist ONLY when a peak strictly advances (M3). The monotone peak moves
456
- // less and less over time and debouncedSave coalesces to <=1/s, so this
457
- // does not flood — and it is what makes the MFE ratchet survive a restart
458
- // and a reloadState() (which previously discarded the unpersisted peak,
459
- // feeding a stale/zeroed mfeR to the agent and the exit gate). mfeR /
460
- // giveBackRatio are recomputed from the persisted peak on read, so they
461
- // don't need a per-tick write.
462
- if (peakAdvanced) {
463
- this.emitStateChanged();
464
- }
465
- }
466
- // ---- State management ----
467
- /** Replace internal state with a fresh copy from disk.
468
- * Used by the gateway process to pick up state saved by the agent process.
469
- *
470
- * Non-destructive for the MFE ratchet (M3): the disk copy can lag the live
471
- * peak (refreshMfeForSymbol ratchets every tick; persistence coalesces), so
472
- * a wholesale swap would discard it. For each position present in BOTH
473
- * snapshots (same symbol+side+openedAt) we carry over the MORE-favourable
474
- * monotone peak and recompute mfeR/giveBackRatio from the current mark, so a
475
- * reload never regresses the agent's give-back signal. */
476
- replaceState(newState) {
477
- // M8: refuse a disk snapshot OLDER than what we already hold in memory.
478
- // reloadState() reads disk that lags memory by the debounce window; without
479
- // this guard a reload fired within ~1s of a local mutation would revert it
480
- // (and a second mutation could then re-persist the reverted state, dropping
481
- // a position + its realized PnL). A genuinely newer cross-process write
482
- // (savedAt >= ours) still installs. Equal stamps install (idempotent).
483
- const incomingAt = newState.savedAt ?? 0;
484
- const currentAt = this.state.savedAt ?? 0;
485
- if (incomingAt < currentAt) {
486
- logger.debug(TAG, `Ignoring stale state reload (disk savedAt=${incomingAt} < memory savedAt=${currentAt})`);
487
- return;
488
- }
489
- const priorPeakByKey = new Map();
490
- for (const p of this.state.positions) {
491
- if (p.metadata?.mfePeakPrice !== undefined) {
492
- priorPeakByKey.set(`${p.symbol}|${p.side}|${p.openedAt}`, p.metadata.mfePeakPrice);
493
- }
494
- }
495
- this.state = newState;
496
- for (const p of this.state.positions) {
497
- const priorPeak = priorPeakByKey.get(`${p.symbol}|${p.side}|${p.openedAt}`);
498
- if (priorPeak === undefined)
499
- continue;
500
- const meta = { ...(p.metadata ?? {}) };
501
- const diskPeak = meta.mfePeakPrice;
502
- // Monotone: keep the better of disk vs in-memory (max for long, min short).
503
- const keptPeak = diskPeak === undefined
504
- ? priorPeak
505
- : (p.side === 'long' ? Math.max(priorPeak, diskPeak) : Math.min(priorPeak, diskPeak));
506
- const mark = this.lastTicker.get(p.symbol)?.last ?? meta.originalEntryPrice ?? p.entryPrice;
507
- const out = updateMfe({
508
- side: p.side,
509
- entryPrice: meta.originalEntryPrice ?? p.entryPrice,
510
- originalStopPrice: meta.originalStopPrice,
511
- markPrice: mark,
512
- priorPeakPrice: keptPeak,
513
- });
514
- meta.mfePeakPrice = out.mfePeakPrice;
515
- meta.mfeR = out.mfeR;
516
- meta.giveBackRatio = out.giveBackRatio;
517
- p.metadata = meta;
518
- }
519
- logger.debug(TAG, `State replaced: ${newState.positions.length} positions, ${newState.openOrders.length} orders`);
520
- }
521
- getState() {
522
- // Spread each element + deep-copy ONLY the nested objects that need
523
- // isolation (metadata — which holds the nested realizationRule.scale array
524
- // — plus executionQuality and fee). This keeps a consumer mutating the
525
- // snapshot, or the JSON-persisted copy, from corrupting live state, while
526
- // staying cheap on the hot persistence path: elements without metadata
527
- // (the common case) pay only a shallow spread, never a full structuredClone.
528
- return {
529
- ...this.state,
530
- wallet: Object.fromEntries(Object.entries(this.state.wallet).map(([k, v]) => [k, { ...v }])),
531
- // Positions + open orders ARE mutated in place (updatePositionMetadata,
532
- // refreshMfeForSymbol, scale-in, limit metadata), so deep-copy their
533
- // nested metadata to keep a snapshot consumer from corrupting live state.
534
- positions: this.state.positions.map(p => ({
535
- ...p,
536
- metadata: p.metadata ? structuredClone(p.metadata) : undefined,
537
- })),
538
- openOrders: this.state.openOrders.map(o => ({
539
- ...o,
540
- fee: { ...o.fee },
541
- metadata: o.metadata ? structuredClone(o.metadata) : undefined,
542
- })),
543
- // Trade records are append-only + immutable after close, so a shallow copy
544
- // is safe and keeps getState() O(n)-cheap on the hot persistence path even
545
- // with a full 1000-entry history (JSON persistence still deep-serializes).
546
- tradeHistory: this.state.tradeHistory.map(t => ({ ...t })),
547
- executionStats: this.state.executionStats ? { ...this.state.executionStats } : undefined,
548
- };
549
- }
550
- // ---- Private helpers ----
551
- shouldFillLimit(order, currentPrice) {
552
- if (order.price === null)
553
- return false;
554
- // BUY limit fills when price <= limit price
555
- // SELL limit fills when price >= limit price
556
- return order.side === 'buy'
557
- ? currentPrice <= order.price
558
- : currentPrice >= order.price;
559
- }
560
- executeMarketFill(order, currentPrice, metadata) {
561
- const position = this.state.positions.find(p => p.symbol === order.symbol) ?? null;
562
- const orderbook = this.lastOrderBook.get(order.symbol) ?? null;
563
- const realistic = {
564
- orderbook,
565
- config: this.simulationConfig,
566
- volFactor: this.cachedVolFactor,
567
- metadata,
568
- };
569
- const result = fillMarketOrder(order, currentPrice, this.state.wallet, position, realistic);
570
- const ccxtOrder = this.applyFillResult(result);
571
- const eq = result.executionQuality;
572
- if (eq) {
573
- logger.info(TAG, `Market order filled: ${order.side} ${order.amount} ${order.symbol} @ ${result.order.average}` +
574
- ` (decision: ${eq.decisionPrice.toFixed(2)}, slippage: ${eq.slippageBps.toFixed(2)}bps` +
575
- `, latency: ${eq.latencyMs.toFixed(0)}ms, fee: ${eq.feeRate * 100}%` +
576
- `, book: ${eq.bookDepthAvailable ? `${eq.bookLevelsConsumed} levels` : 'unavailable'})`);
577
- }
578
- else {
579
- logger.info(TAG, `Market order filled: ${order.side} ${order.amount} ${order.symbol} @ ${result.order.average}`);
580
- }
581
- return ccxtOrder;
582
- }
583
- executeLimitFill(order, decisionPrice, metadata) {
584
- const position = this.state.positions.find(p => p.symbol === order.symbol) ?? null;
585
- const result = fillLimitOrder(order, this.state.wallet, position, this.simulationConfig, decisionPrice, metadata);
586
- const ccxtOrder = this.applyFillResult(result);
587
- const eq = result.executionQuality;
588
- if (eq) {
589
- logger.info(TAG, `Limit order filled: ${order.side} ${order.amount} ${order.symbol} @ ${result.order.average}` +
590
- ` (maker fee: ${eq.feeRate * 100}%)`);
591
- }
592
- else {
593
- logger.info(TAG, `Limit order filled: ${order.side} ${order.amount} ${order.symbol} @ ${result.order.average}`);
594
- }
595
- return ccxtOrder;
596
- }
597
- /** Apply a fill result: update positions, record trade, track stats, emit state change. */
598
- applyFillResult(result) {
599
- this.updatePosition(result.order.symbol, result.position);
600
- if (result.trade)
601
- this.addTrade(result.trade);
602
- if (result.executionQuality)
603
- this.updateExecutionStats(result.executionQuality);
604
- this.emitStateChanged();
605
- // Emit fill event for shadow tracker (Phase 9b)
606
- this.emit('fill', {
607
- trade: result.trade,
608
- orderId: result.order.id,
609
- symbol: result.order.symbol,
610
- side: result.order.side,
611
- type: result.order.type,
612
- amount: result.order.amount,
613
- fillPrice: result.order.average ?? 0,
614
- fee: result.order.fee.cost,
615
- });
616
- return this.toCcxtOrder(result.order);
617
- }
618
- updatePosition(symbol, newPosition) {
619
- const idx = this.state.positions.findIndex(p => p.symbol === symbol);
620
- if (newPosition) {
621
- if (idx >= 0) {
622
- this.state.positions[idx] = newPosition;
623
- }
624
- else {
625
- this.state.positions.push(newPosition);
626
- }
627
- }
628
- else if (idx >= 0) {
629
- this.state.positions.splice(idx, 1);
630
- }
631
- }
632
- addTrade(trade) {
633
- this.state.tradeHistory.push(trade);
634
- // Keep only the last MAX_TRADE_HISTORY trades
635
- if (this.state.tradeHistory.length > MAX_TRADE_HISTORY) {
636
- this.state.tradeHistory = this.state.tradeHistory.slice(-MAX_TRADE_HISTORY);
637
- }
638
- }
639
- /** Update cumulative execution stats from a fill's execution quality. */
640
- updateExecutionStats(eq) {
641
- if (!this.state.executionStats) {
642
- this.state.executionStats = {
643
- totalTrades: 0,
644
- totalSlippageBps: 0,
645
- totalFeesPaid: 0,
646
- worstSlippageBps: 0,
647
- avgSlippageBps: 0,
648
- avgLatencyMs: 0,
649
- };
650
- }
651
- const stats = this.state.executionStats;
652
- stats.totalTrades++;
653
- const absSlippage = Math.abs(eq.slippageBps);
654
- stats.totalSlippageBps += absSlippage;
655
- stats.totalFeesPaid += eq.feePaid;
656
- if (absSlippage > stats.worstSlippageBps) {
657
- stats.worstSlippageBps = absSlippage;
658
- }
659
- stats.avgSlippageBps = stats.totalSlippageBps / stats.totalTrades;
660
- stats.avgLatencyMs =
661
- (stats.avgLatencyMs * (stats.totalTrades - 1) + eq.latencyMs) / stats.totalTrades;
662
- }
663
- emitStateChanged() {
664
- // Stamp the mutation time so a stale-disk reloadState() can be detected and
665
- // dropped (M8). Must be set BEFORE getState() snapshots the state.
666
- this.state.savedAt = Date.now();
667
- this.emit('stateChanged', this.getState());
668
- }
669
- toCcxtOrder(order) {
670
- const ts = new Date(order.createdAt).getTime();
671
- return {
672
- id: order.id,
673
- symbol: order.symbol,
674
- side: order.side,
675
- type: order.type,
676
- status: order.status,
677
- amount: order.amount,
678
- filled: order.filled,
679
- remaining: order.amount - order.filled,
680
- average: order.average,
681
- price: order.price,
682
- cost: order.cost,
683
- fee: order.fee,
684
- timestamp: ts,
685
- datetime: order.createdAt,
686
- timeInForce: 'GTC',
687
- };
688
- }
689
- }