@reefclaw/connect 0.1.12 → 0.1.13

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 (390) 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/package.json +1 -1
@@ -0,0 +1,683 @@
1
+ // Tool: audit_bracket_protection — returns every open live position with a
2
+ // verdict on whether exchange-side SL / TP protection is currently attached.
3
+ // Agent runs this at SESSION START and every heartbeat; any position with
4
+ // `has_stop=false` or `has_target=false` must be resolved (attach_brackets
5
+ // with new levels, or close_position).
6
+ //
7
+ // Cross-references three sources of truth to catch every failure mode:
8
+ // 1. Live positions (adapter.getPositions)
9
+ // 2. Open orders on the exchange (adapter.getOpenOrders) — ground truth
10
+ // for SL/TP orders currently live
11
+ // 3. Bracket ledger (for state + stored price levels)
12
+ //
13
+ // Order checks are by clientOrderId prefix AND by symbol + type, so we catch
14
+ // both (a) bracket orders with reefclaw-managed cids and (b) manually-placed
15
+ // STOP_MARKET / TAKE_PROFIT_MARKET orders from the Binance UI that happen to
16
+ // protect the position. Either is good enough for "position is protected".
17
+ import { parseBracketCid } from '../live/bracket-id.js';
18
+ import { normalizeBracketSymbol } from '../live/bracket-ledger.js';
19
+ import { formatError, logger } from '../logger.js';
20
+ import { HyperliquidLiveAdapter } from '../venues/hyperliquid/hl-live-adapter.js';
21
+ import { isTerminalBracketState } from '../venues/hyperliquid/hl-bracket-coordinator.js';
22
+ import { parseHlBracketCloid } from '../venues/hyperliquid/hl-cloid.js';
23
+ import { isProtectiveHlOrder } from '../venues/hyperliquid/hl-brackets.js';
24
+ const TAG = 'audit-bracket-protection';
25
+ // Per-symbol verdict history for flicker detection. When audit verdicts
26
+ // transition protected→unprotected→protected repeatedly inside a short
27
+ // window, the bracket subsystem itself is unreliable — protection on the
28
+ // exchange isn't changing, our reading of it is. That's the signature of
29
+ // the 2026-05-15 spiral (ATOM/LINK/NEAR all flushed via bracket_integrity
30
+ // while their brackets were really still live). Emitting a structured warn
31
+ // when we see it surfaces the bug to the operator BEFORE the agent
32
+ // escalates to close_position.
33
+ const FLICKER_WINDOW_MS = 5 * 60 * 1000;
34
+ const FLICKER_THRESHOLD = 3; // 3 verdict flips in the window → warn
35
+ // Retention bumped to 60 min so close_position can copy the last hour of
36
+ // audit verdicts into position_closes.close_assessment.metadata.bracket_health_history
37
+ // for post-mortem analysis on the dashboard's Position Timeline drawer.
38
+ // 120 samples × ~120 bytes = ~15KB worst-case per symbol; trivial.
39
+ const HISTORY_RETENTION_MS = 60 * 60 * 1000;
40
+ const HISTORY_MAX_PER_SYMBOL = 120;
41
+ const verdictHistory = new Map();
42
+ let lastFlickerWarnedAt = new Map();
43
+ const FLICKER_WARN_COOLDOWN_MS = 60 * 1000; // don't repeat the warn more than once a minute per symbol
44
+ export async function auditBracketProtectionTool(_args, deps) {
45
+ try {
46
+ const isLive = deps.adapter.isLive;
47
+ // Paper mode: stop protection lives in position metadata + stop-watcher,
48
+ // not exchange orders. Report positions with their metadata for
49
+ // completeness, but mark them all protected (the stop-watcher model is
50
+ // the contract in paper).
51
+ if (!isLive) {
52
+ const positions = await deps.adapter.getPositions();
53
+ const entries = positions
54
+ .filter(p => p.contracts > 0)
55
+ .map(p => ({
56
+ symbol: p.symbol,
57
+ side: p.side,
58
+ contracts: p.contracts,
59
+ entry_price: p.entryPrice,
60
+ mark_price: p.markPrice,
61
+ has_stop: p.stopPrice !== undefined,
62
+ has_target: p.targetPrice !== undefined,
63
+ stop_price: p.stopPrice,
64
+ target_price: p.targetPrice,
65
+ ledger_state: 'no_ledger_row',
66
+ reason: p.stopPrice !== undefined ? 'manual_order_protecting' : 'no_protective_order',
67
+ recommended_action: p.stopPrice !== undefined ? 'none' : 'close_position',
68
+ }));
69
+ const unprotected = entries.filter(e => !e.has_stop).length;
70
+ return {
71
+ ok: true,
72
+ mode: 'paper',
73
+ brackets_enabled: false,
74
+ total_positions: entries.length,
75
+ protected_count: entries.length - unprotected,
76
+ unprotected_count: unprotected,
77
+ positions: entries,
78
+ };
79
+ }
80
+ // Live mode — venue dispatch (issue #209). The Binance-shaped path below
81
+ // reads algo-order fields HL doesn't have; on HL it produced permanent
82
+ // false "unprotected" verdicts (the spiral seed).
83
+ if (deps.adapter instanceof HyperliquidLiveAdapter) {
84
+ return auditHlLive(deps.adapter);
85
+ }
86
+ const live = deps.adapter;
87
+ const ledger = live.getBracketLedger?.() ?? null;
88
+ const bracketsEnabled = ledger !== null;
89
+ // Fetch positions + open orders. If `getOpenOrders` throws (it does so
90
+ // on null = fetch failure / 429 — see live-adapter.ts), we return a
91
+ // clear error instead of falling through with an empty list. The old
92
+ // behaviour was: null collapsed to []; audit said has_stop=false;
93
+ // agent ran attach_brackets; cancelSymbolBracketOrders no-op'd; new
94
+ // brackets piled up on top of orders Binance hadn't surfaced through
95
+ // the 429'd fetch. 2026-05-14 ATOM ran ~17 spurious re-attach cycles
96
+ // before the operator noticed. With this gate, a single 429 just
97
+ // delays the audit one heartbeat — far safer than fabricating
98
+ // "unprotected" verdicts.
99
+ // Weight discipline (2026-05-15, measured): the unscoped getOpenOrders
100
+ // sweep is 80 weight (40 regular + 40 algo). Pre-fix this ran on EVERY
101
+ // audit invocation — including when flat — and the agent's SKILL.md
102
+ // recovery loop (audit→attach) re-runs it every ~3s, so prod measured
103
+ // ~560-640 weight/min from this ONE call, ~40% of the pacer ceiling,
104
+ // which starved every other read and blinded the agent. Two cuts that
105
+ // do NOT change the audit verdict:
106
+ // 1. `openOrders` is consumed ONLY inside `activePositions.map(...)`,
107
+ // so when there are no active positions it is provably unused —
108
+ // skip the call entirely (return the trivial 0-position verdict).
109
+ // 2. When positions exist, fetch open orders SCOPED to those symbols
110
+ // (1 regular + 1 algo = 2 weight each) instead of one 80-weight
111
+ // unscoped sweep. Audit only ever inspects orders for symbols that
112
+ // have a position; cross-symbol orphan detection is the bracket
113
+ // reconciler's job (it keeps its 60s unscoped sweep — the
114
+ // authoritative orphan/naked backstop, unchanged).
115
+ // The null-vs-empty {error} contract is preserved for the calls that
116
+ // matter (verifying real open positions have stops). When flat, the
117
+ // reconciler + user-data WS + ALGO_UPDATE remain the safety net.
118
+ let positions, openOrders;
119
+ try {
120
+ // null = positions fetch FAILED (429 / weight-paced / transient).
121
+ // getPositions() would collapse that to [] → activeSymbols=[] → this
122
+ // audit returns a trivial "0 positions, all protected" verdict during
123
+ // a rate-limit storm, masking a real naked position for a heartbeat.
124
+ // Treat it identically to the getOpenOrders-null case below: surface
125
+ // {error} so the agent skips this cycle and MUST NOT run attach_brackets
126
+ // (see CLAUDE.md audit-vs-action contract).
127
+ const positionsOrNull = await deps.adapter.getPositionsOrNull();
128
+ if (positionsOrNull === null) {
129
+ throw new Error('positions fetch returned null (exchange data unavailable)');
130
+ }
131
+ positions = positionsOrNull;
132
+ const activeSymbols = [
133
+ ...new Set(positions.filter(p => p.contracts > 0).map(p => p.symbol)),
134
+ ];
135
+ if (activeSymbols.length === 0) {
136
+ openOrders = [];
137
+ }
138
+ else {
139
+ const perSymbol = await Promise.all(activeSymbols.map(s => deps.adapter.getOpenOrders(s)));
140
+ openOrders = perSymbol.flat();
141
+ }
142
+ }
143
+ catch (err) {
144
+ const msg = formatError(err);
145
+ logger.warn(TAG, `audit skipped — exchange data unavailable: ${msg}`);
146
+ return {
147
+ error: `Exchange data unavailable (likely Binance 429 or transient network). ` +
148
+ `Skipping audit this cycle — current bracket state on Binance is unchanged. ` +
149
+ `Retry on next heartbeat. Underlying: ${msg}`,
150
+ };
151
+ }
152
+ const activePositions = positions.filter(p => p.contracts > 0);
153
+ // Group open orders by NORMALIZED symbol so position.symbol (may be
154
+ // `:USDT`-suffixed from CCXT fetchPositions) and order.symbol (same
155
+ // source but historically inconsistent across CCXT versions) always
156
+ // collide on the same key. Without this, a suffixed position would miss
157
+ // an un-suffixed order's brackets and audit would return has_stop=false
158
+ // despite the exchange-side stop being live.
159
+ const ordersBySymbol = new Map();
160
+ for (const o of openOrders) {
161
+ if (!o.symbol)
162
+ continue;
163
+ const key = normalizeBracketSymbol(o.symbol);
164
+ const list = ordersBySymbol.get(key) ?? [];
165
+ list.push(o);
166
+ ordersBySymbol.set(key, list);
167
+ }
168
+ // Untrusted-empty contradiction guard (2026-05-15 SOL/INJ spiral).
169
+ // A position whose ledger row is non-terminal WITH stored cids but whose
170
+ // scoped open-orders fetch came back EMPTY is NOT positive evidence the
171
+ // brackets are gone: under weight pressure Binance's algo-orders REST
172
+ // endpoint returns a *successful* [] while ALGO_UPDATE (the authoritative
173
+ // bracket-lifecycle signal) shows the legs still live and never
174
+ // terminated. Emitting a confident has_stop=false / attach_brackets
175
+ // verdict here is what drove the audit → attach → cancel-live-brackets
176
+ // loop AND the bracket_integrity escalation that flushed ATOM/LINK/NEAR.
177
+ // Same null≠empty / require-positive-disconfirmation contract as
178
+ // classifyLedgerVsExchange and the reconciler: surface {error} so the
179
+ // agent skips this cycle and MUST NOT run attach_brackets /
180
+ // close_position(reason='bracket_integrity') (CLAUDE.md audit-vs-action
181
+ // contract). The reconciler + ALGO_UPDATE remain the backstop for any
182
+ // genuinely-naked position on another symbol within one cycle — the
183
+ // file's own stated philosophy ("a single transient gap just delays the
184
+ // audit one heartbeat — far safer than fabricating verdicts").
185
+ const unverifiable = activePositions.filter(p => {
186
+ const normSym = normalizeBracketSymbol(p.symbol);
187
+ if ((ordersBySymbol.get(normSym) ?? []).length > 0)
188
+ return false;
189
+ const lr = ledger?.getBySymbol(p.symbol) ?? null;
190
+ return !!lr
191
+ && (lr.state === 'active' || lr.state === 'partial' || lr.state === 'attaching')
192
+ && (!!lr.slCid || !!lr.tpCid);
193
+ });
194
+ // Before declaring the audit blind, ask the ZERO-WEIGHT authoritative
195
+ // source we already built (Phase 1/2, deployed): the per-cid bracket-leg
196
+ // liveness resolver. `getOpenOrders` came back empty ONLY because the
197
+ // proactive weight pacer shed it (steady-state IP weight pins the soft
198
+ // ceiling 24/7 — the real disease). But ALGO_UPDATE has already pushed
199
+ // every leg's NEW/CANCELED/EXPIRED/TRIGGERED status into the in-memory
200
+ // per-cid map at zero Binance weight. `resolveBracketLegLiveness` reads
201
+ // that (Tier-1, only when the WS store is trusted), falling back to a
202
+ // weight-1 REST query, then to 'unknown'. Pre-fix this branch returned
203
+ // {error} unconditionally → the agent went blind on a live position for
204
+ // HOURS (prod 2026-05-16: INJ/USDT unverifiable every heartbeat 04:29→
205
+ // 05:54 straight) even though the WS knew the brackets were live the
206
+ // whole time. The Phase-2 resolver was dead code in the audit path.
207
+ //
208
+ // stop leg 'live' → position IS protected (positive verdict, w=0)
209
+ // stop leg 'terminal' → positively confirmed naked → attach_brackets
210
+ // 'unknown' → keep the d59e51b safe {error} floor for that
211
+ // symbol only (NEVER infer from absence)
212
+ const wsResolvedProtected = new Set(); // normSym → stop leg confirmed live
213
+ const stillBlind = [];
214
+ if (unverifiable.length > 0) {
215
+ await Promise.all(unverifiable.map(async (p) => {
216
+ const normSym = normalizeBracketSymbol(p.symbol);
217
+ const lr = ledger?.getBySymbol(p.symbol) ?? null;
218
+ // The stop leg is the protective one; resolve it. (A live SL is the
219
+ // bar for "protected"; TP-only is still has_stop=false downstream.)
220
+ let slState = 'unknown';
221
+ if (lr?.slCid) {
222
+ try {
223
+ slState = await live.resolveBracketLegLiveness(lr.slCid);
224
+ }
225
+ catch {
226
+ slState = 'unknown';
227
+ }
228
+ }
229
+ if (slState === 'live') {
230
+ wsResolvedProtected.add(normSym);
231
+ }
232
+ else {
233
+ // #1 (supporting) — the ledger's slCid may be positively terminal
234
+ // while a PRIOR reattach's FRESH stop leg is live on the exchange
235
+ // under a NEW cid the ledger never caught up to (the 2026-05-16 INJ
236
+ // spiral). Declaring the position naked here drives the agent to
237
+ // attach_brackets → clear+reattach → cancels the live leg → spiral.
238
+ // Before that, ask whether ANY trusted-WS rc-*-s stop leg for this
239
+ // symbol is live, not just the ledger's cid. (Authoritative break
240
+ // is #2 in classifyLedgerVsExchange; this keeps the audit verdict
241
+ // consistent so the agent isn't told to attach in the first place.)
242
+ const sweep = live.findTrustedLiveBracketCidsForSymbol(p.symbol);
243
+ const hasLiveStopLeg = sweep.trusted &&
244
+ sweep.liveCids.some(c => parseBracketCid(c)?.role === 'stop');
245
+ if (hasLiveStopLeg) {
246
+ wsResolvedProtected.add(normSym);
247
+ }
248
+ else if (slState === 'terminal') {
249
+ // Positively confirmed gone AND no other live stop leg — let the
250
+ // normal entry builder produce has_stop=false → attach_brackets
251
+ // (licensed: POSITIVE disconfirmation, not inference from absence).
252
+ }
253
+ else {
254
+ stillBlind.push(p);
255
+ }
256
+ }
257
+ }));
258
+ }
259
+ if (stillBlind.length > 0) {
260
+ const blindSyms = stillBlind.map(p => p.symbol).join(', ');
261
+ const seenLive = [...wsResolvedProtected].join(', ') || 'none';
262
+ logger.warn(TAG, `audit unverifiable for [${blindSyms}]: scoped getOpenOrders returned EMPTY ` +
263
+ `(weight-paced) AND the per-cid liveness resolver could not positively confirm ` +
264
+ `(WS untrusted/silent + weight-1 REST unavailable). Empty ≠ "brackets gone". ` +
265
+ `Returning {error} — agent must NOT run attach_brackets or ` +
266
+ `close_position(reason='bracket_integrity') this cycle. ` +
267
+ `(WS positively confirmed LIVE for: [${seenLive}].)`);
268
+ return {
269
+ error: `Cannot confirm bracket protection for [${blindSyms}] — the exchange returned ` +
270
+ `an empty open-orders set (weight-paced) and the zero-weight per-leg liveness ` +
271
+ `resolver could not positively confirm the bracket legs (WS store untrusted ` +
272
+ `or silent on these cids, and the weight-1 REST query was unavailable). An ` +
273
+ `empty result is NOT proof the brackets are gone. Skipping audit this cycle — ` +
274
+ `bracket state on Binance is unchanged. Do NOT run attach_brackets or ` +
275
+ `close_position(reason='bracket_integrity') on the basis of this call. ` +
276
+ `Retry next heartbeat.`,
277
+ };
278
+ }
279
+ if (wsResolvedProtected.size > 0) {
280
+ logger.info(TAG, `per-leg liveness resolver: scoped getOpenOrders was weight-paced-empty but ` +
281
+ `the WS POSITIVELY confirmed the stop leg LIVE for ` +
282
+ `[${[...wsResolvedProtected].join(', ')}] at ZERO Binance weight — ` +
283
+ `reporting protected instead of going blind.`);
284
+ }
285
+ const entries = activePositions.map(p => {
286
+ const normSym = normalizeBracketSymbol(p.symbol);
287
+ const symbolOrders = ordersBySymbol.get(normSym) ?? [];
288
+ // BracketLedger applies normalization internally; pass p.symbol through.
289
+ const ledgerRow = ledger?.getBySymbol(p.symbol) ?? null;
290
+ // WS-confirmed-protected overlay: scoped getOpenOrders was weight-paced
291
+ // to empty for this symbol, so the order-based classification below
292
+ // would falsely report has_stop=false. But the zero-weight per-cid
293
+ // resolver POSITIVELY confirmed the stop leg is live on the exchange.
294
+ // Trust that (it's the authoritative ALGO_UPDATE signal, not inference
295
+ // from an absent REST result). stop_price from the ledger (our intent).
296
+ if (wsResolvedProtected.has(normSym)) {
297
+ return {
298
+ symbol: p.symbol,
299
+ side: p.side,
300
+ contracts: p.contracts,
301
+ entry_price: p.entryPrice,
302
+ mark_price: p.markPrice,
303
+ has_stop: true,
304
+ has_target: ledgerRow?.targetPrice !== undefined,
305
+ stop_price: ledgerRow?.stopPrice,
306
+ target_price: ledgerRow?.targetPrice,
307
+ ledger_state: ledgerRow?.state ?? 'no_ledger_row',
308
+ reason: 'bracket_active',
309
+ recommended_action: 'none',
310
+ };
311
+ }
312
+ // Classify each open order on the symbol: bracket SL, bracket TP,
313
+ // manual SL (non-bracket STOP_MARKET), manual TP (non-bracket TAKE_PROFIT_MARKET).
314
+ let hasBracketStop = false;
315
+ let hasBracketTarget = false;
316
+ let hasManualStop = false;
317
+ let hasManualTarget = false;
318
+ let stopPrice;
319
+ let targetPrice;
320
+ for (const o of symbolOrders) {
321
+ const parsed = o.clientOrderId ? parseBracketCid(o.clientOrderId) : null;
322
+ const triggerPrice = extractTriggerPrice(o);
323
+ if (parsed && parsed.role === 'stop') {
324
+ hasBracketStop = true;
325
+ stopPrice = triggerPrice ?? stopPrice;
326
+ }
327
+ else if (parsed && parsed.role === 'target') {
328
+ hasBracketTarget = true;
329
+ targetPrice = triggerPrice ?? targetPrice;
330
+ }
331
+ else {
332
+ // Prefer Binance's authoritative `orderType` field on the algo
333
+ // response (preserved in `info` by binance-private.ts). This
334
+ // catches externally-placed stops — manual SL via Binance UI —
335
+ // which parseBracketCid can't recognize since they have no
336
+ // `rc-*-s/t` CID. The string heuristic on top-level `type`
337
+ // remains as a secondary signal for legacy / non-algo paths
338
+ // where `info` may be absent.
339
+ // Spec: https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Current-All-Algo-Open-Orders
340
+ const infoOrderType = String(o.info?.orderType ?? '').toUpperCase();
341
+ const type = (o.type ?? '').toLowerCase();
342
+ const isStopType = infoOrderType === 'STOP_MARKET' || infoOrderType === 'STOP' || infoOrderType === 'TRAILING_STOP_MARKET' ||
343
+ (type.includes('stop') && !type.includes('take'));
344
+ const isTargetType = infoOrderType === 'TAKE_PROFIT_MARKET' || infoOrderType === 'TAKE_PROFIT' ||
345
+ type.includes('take_profit') || type.includes('take-profit') || type === 'take_profit_market';
346
+ if (isStopType) {
347
+ hasManualStop = true;
348
+ stopPrice = triggerPrice ?? stopPrice;
349
+ }
350
+ else if (isTargetType) {
351
+ hasManualTarget = true;
352
+ targetPrice = triggerPrice ?? targetPrice;
353
+ }
354
+ }
355
+ }
356
+ const hasStop = hasBracketStop || hasManualStop;
357
+ const hasTarget = hasBracketTarget || hasManualTarget;
358
+ // Prefer ledger price when available — it's our intent, not a re-derived
359
+ // exchange trigger value (which Binance may round).
360
+ if (ledgerRow?.stopPrice !== undefined)
361
+ stopPrice = ledgerRow.stopPrice;
362
+ if (ledgerRow?.targetPrice !== undefined)
363
+ targetPrice = ledgerRow.targetPrice;
364
+ const ledgerState = ledgerRow?.state ?? 'no_ledger_row';
365
+ let reason;
366
+ if (!bracketsEnabled) {
367
+ reason = 'brackets_disabled';
368
+ }
369
+ else if (hasStop || hasTarget) {
370
+ reason = hasBracketStop || hasBracketTarget ? 'bracket_active' : 'manual_order_protecting';
371
+ }
372
+ else if (ledgerRow && (ledgerRow.state === 'active' || ledgerRow.state === 'partial' || ledgerRow.state === 'attaching')) {
373
+ reason = 'stale_ledger_row';
374
+ }
375
+ else if (ledgerRow && isTerminalState(ledgerRow.state)) {
376
+ reason = 'ledger_terminal_no_order';
377
+ }
378
+ else {
379
+ reason = 'no_protective_order';
380
+ }
381
+ let recommended_action = 'none';
382
+ if (!bracketsEnabled)
383
+ recommended_action = 'enable_brackets_mode';
384
+ else if (!hasStop)
385
+ recommended_action = 'attach_brackets';
386
+ return {
387
+ symbol: p.symbol,
388
+ side: p.side,
389
+ contracts: p.contracts,
390
+ entry_price: p.entryPrice,
391
+ mark_price: p.markPrice,
392
+ has_stop: hasStop,
393
+ has_target: hasTarget,
394
+ stop_price: stopPrice,
395
+ target_price: targetPrice,
396
+ ledger_state: ledgerState,
397
+ reason,
398
+ recommended_action,
399
+ };
400
+ });
401
+ const unprotected = entries.filter(e => !e.has_stop).length;
402
+ // Flicker detection — runs after every audit pass. Cheap (a few map ops
403
+ // per open position) and only emits log when the threshold trips.
404
+ const nowTs = Date.now();
405
+ for (const e of entries) {
406
+ recordVerdictAndCheckFlicker(normalizeBracketSymbol(e.symbol), e.has_stop, nowTs);
407
+ }
408
+ // Diagnostic: when we conclude a live position is unprotected, dump the
409
+ // raw openOrders shape for that symbol so post-mortems can tell whether
410
+ // (a) exchange genuinely had no stop/TP, (b) CCXT returned them but the
411
+ // cid/type didn't parse, or (c) the orders came back under a different
412
+ // symbol key than the position. This is the other half of the bug the
413
+ // 2026-04-21 close_position safeguard catches — we want to see WHY the
414
+ // audit said false, not just catch the symptom.
415
+ for (const e of entries) {
416
+ if (e.has_stop)
417
+ continue;
418
+ const normSym = normalizeBracketSymbol(e.symbol);
419
+ const raw = ordersBySymbol.get(normSym) ?? [];
420
+ const orderSnapshot = raw.map(o => ({
421
+ id: o.id,
422
+ cid: o.clientOrderId ?? null,
423
+ type: o.type ?? null,
424
+ side: o.side ?? null,
425
+ reduceOnly: o.reduceOnly ?? null,
426
+ stopPrice: extractTriggerPrice(o) ?? null,
427
+ infoType: o.info
428
+ ? (o.info.type ?? null)
429
+ : null,
430
+ symbol: o.symbol ?? null,
431
+ }));
432
+ const allSymbols = Array.from(ordersBySymbol.keys());
433
+ logger.warn(TAG, `unprotected verdict for ${e.symbol} (norm=${normSym}): has_stop=${e.has_stop} ` +
434
+ `has_target=${e.has_target} reason=${e.reason} ledger=${e.ledger_state}. ` +
435
+ `openOrders keyed under ${normSym}: ${orderSnapshot.length} ` +
436
+ `(all symbol keys in map: ${JSON.stringify(allSymbols)}). ` +
437
+ `orders=${JSON.stringify(orderSnapshot)}`);
438
+ }
439
+ return {
440
+ ok: true,
441
+ mode: 'live',
442
+ brackets_enabled: bracketsEnabled,
443
+ total_positions: entries.length,
444
+ protected_count: entries.length - unprotected,
445
+ unprotected_count: unprotected,
446
+ positions: entries,
447
+ };
448
+ }
449
+ catch (err) {
450
+ logger.error(TAG, `audit failed: ${formatError(err)}`);
451
+ return { error: `audit_bracket_protection failed: ${formatError(err)}` };
452
+ }
453
+ }
454
+ function isTerminalState(s) {
455
+ return s === 'cancelled' || s === 'failed' || s === 'triggered_sl' || s === 'triggered_tp';
456
+ }
457
+ /** Append a verdict sample for the symbol and emit a flicker warn when the
458
+ * recent history shows ≥ FLICKER_THRESHOLD verdict transitions (true↔false)
459
+ * inside FLICKER_WINDOW_MS. Trims the history to retention bounds. */
460
+ function recordVerdictAndCheckFlicker(symbol, isProtected, nowTs) {
461
+ const history = verdictHistory.get(symbol) ?? [];
462
+ history.push({ ts: nowTs, protected: isProtected });
463
+ // Trim by both age and length.
464
+ const cutoff = nowTs - HISTORY_RETENTION_MS;
465
+ while (history.length > 0 && history[0].ts < cutoff)
466
+ history.shift();
467
+ while (history.length > HISTORY_MAX_PER_SYMBOL)
468
+ history.shift();
469
+ verdictHistory.set(symbol, history);
470
+ // Count verdict transitions inside the flicker window.
471
+ const windowStart = nowTs - FLICKER_WINDOW_MS;
472
+ let transitions = 0;
473
+ let prev;
474
+ for (const sample of history) {
475
+ if (sample.ts < windowStart)
476
+ continue;
477
+ if (prev !== undefined && prev !== sample.protected)
478
+ transitions++;
479
+ prev = sample.protected;
480
+ }
481
+ if (transitions < FLICKER_THRESHOLD)
482
+ return;
483
+ const lastWarned = lastFlickerWarnedAt.get(symbol) ?? 0;
484
+ if (nowTs - lastWarned < FLICKER_WARN_COOLDOWN_MS)
485
+ return;
486
+ lastFlickerWarnedAt.set(symbol, nowTs);
487
+ logger.warn(TAG, `AUDIT FLICKER on ${symbol}: ${transitions} protected↔unprotected transitions ` +
488
+ `in the last ${FLICKER_WINDOW_MS / 60_000} min. ` +
489
+ `Bracket subsystem is reading exchange state inconsistently. ` +
490
+ `Suspect transient fetchOpenOrders gaps, attach_brackets re-entry races, or ` +
491
+ `CCXT symbol-form drift. Operator should investigate BEFORE the agent escalates ` +
492
+ `to close_position(reason='bracket_integrity'). ` +
493
+ `Recent samples: ${history.slice(-6).map(s => `${new Date(s.ts).toISOString().slice(11, 19)}:${s.protected ? 'P' : 'U'}`).join(' ')}`);
494
+ }
495
+ /** Public getter — returns the recent audit verdict samples for a symbol so
496
+ * close_position can copy them into the position's close record for the
497
+ * dashboard Position Timeline drawer. Read-only snapshot; mutating the
498
+ * return value does not affect internal state. */
499
+ export function getRecentAuditVerdictHistory(symbol) {
500
+ const history = verdictHistory.get(normalizeBracketSymbol(symbol)) ?? [];
501
+ // Defensive copy so callers can't mutate the live buffer.
502
+ return history.map(s => ({ ts: s.ts, protected: s.protected }));
503
+ }
504
+ /** Test seam — clears the in-memory flicker history between unit tests. */
505
+ export const __testing__ = {
506
+ resetFlickerHistory() {
507
+ verdictHistory.clear();
508
+ lastFlickerWarnedAt = new Map();
509
+ },
510
+ /** Inspect current history for a symbol — used by tests to assert state. */
511
+ getHistory(symbol) {
512
+ return verdictHistory.get(normalizeBracketSymbol(symbol)) ?? [];
513
+ },
514
+ };
515
+ // CCXT returns STOP_MARKET / TAKE_PROFIT_MARKET trigger prices in one of a
516
+ // few spots depending on version + exchange. Check the most common ones.
517
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
518
+ function extractTriggerPrice(o) {
519
+ const candidates = [
520
+ o?.stopPrice,
521
+ o?.triggerPrice,
522
+ o?.info?.stopPrice,
523
+ o?.info?.triggerPrice,
524
+ o?.params?.stopPrice,
525
+ ];
526
+ for (const c of candidates) {
527
+ if (typeof c === 'number' && Number.isFinite(c) && c > 0)
528
+ return c;
529
+ if (typeof c === 'string') {
530
+ const n = Number(c);
531
+ if (Number.isFinite(n) && n > 0)
532
+ return n;
533
+ }
534
+ }
535
+ return undefined;
536
+ }
537
+ /**
538
+ * Hyperliquid live audit (issue #209). Same contracts as the Binance path:
539
+ * null ≠ empty ({error} on an unavailable read — the agent skips the cycle and
540
+ * MUST NOT act), and an EMPTY open-orders set against a non-terminal ledger row
541
+ * WITH cids is unverifiable, never "unprotected" (HL has no zero-weight per-leg
542
+ * resolver, so the honest floor is the whole-audit {error}). External trigger
543
+ * legs count as protection (`manual_order_protecting`) via the HL order shape
544
+ * (isTrigger/reduceOnly/orderType — T-7 fields), mirroring the Binance rule
545
+ * that a manually-placed stop must never be reported as naked.
546
+ */
547
+ async function auditHlLive(adapter) {
548
+ const ledger = adapter.getHlBracketCoordinator().getLedger();
549
+ const positionsOrNull = await adapter.getPositionsOrNull();
550
+ if (positionsOrNull === null) {
551
+ return {
552
+ error: 'Exchange data unavailable (Hyperliquid fetch failed / rate-gated). Skipping audit ' +
553
+ 'this cycle — bracket state on the exchange is unchanged. Retry on next heartbeat.',
554
+ };
555
+ }
556
+ const activePositions = positionsOrNull.filter(p => Math.abs(Number(p.contracts ?? 0)) > 0);
557
+ if (activePositions.length === 0) {
558
+ return {
559
+ ok: true,
560
+ mode: 'live',
561
+ brackets_enabled: true,
562
+ total_positions: 0,
563
+ protected_count: 0,
564
+ unprotected_count: 0,
565
+ positions: [],
566
+ };
567
+ }
568
+ const entries = [];
569
+ for (const p of activePositions) {
570
+ let symbolOrders;
571
+ try {
572
+ symbolOrders = await adapter.getOpenOrders(p.symbol);
573
+ }
574
+ catch (err) {
575
+ const m = formatError(err);
576
+ logger.warn(TAG, `HL audit skipped — open orders unavailable for ${p.symbol}: ${m}`);
577
+ return {
578
+ error: `Exchange data unavailable for ${p.symbol} (Hyperliquid open-orders fetch failed). ` +
579
+ `Skipping audit this cycle — do NOT run attach_brackets or ` +
580
+ `close_position(reason='bracket_integrity') on the basis of this call. Underlying: ${m}`,
581
+ };
582
+ }
583
+ const ledgerRow = ledger.getBySymbol(p.symbol) ?? null;
584
+ const rowNonTerminalWithCids = !!ledgerRow && !isTerminalBracketState(ledgerRow.state) && Boolean(ledgerRow.slCid || ledgerRow.tpCid);
585
+ if (symbolOrders.length === 0 && rowNonTerminalWithCids) {
586
+ // Untrusted-empty contradiction (the SOL/INJ lesson, HL edition): the
587
+ // ledger says legs are live but the successful fetch shows nothing.
588
+ // Empty is NOT positive disconfirmation — refuse honestly.
589
+ return {
590
+ error: `Cannot confirm bracket protection for ${p.symbol} — the exchange returned an empty ` +
591
+ `open-orders set while the ledger row is ${ledgerRow.state} with stored cloids. ` +
592
+ `Empty ≠ "brackets gone". Skipping audit this cycle; do NOT run attach_brackets or ` +
593
+ `close_position(reason='bracket_integrity'). Retry next heartbeat.`,
594
+ };
595
+ }
596
+ let hasBracketStop = false;
597
+ let hasBracketTarget = false;
598
+ let hasManualStop = false;
599
+ let hasManualTarget = false;
600
+ let stopPrice;
601
+ let targetPrice;
602
+ for (const o of symbolOrders) {
603
+ const parsed = o.clientOrderId ? parseHlBracketCloid(o.clientOrderId) : null;
604
+ const triggerPrice = extractTriggerPrice(o);
605
+ const info = o.info ?? {};
606
+ if (parsed?.role === 'stop') {
607
+ hasBracketStop = true;
608
+ stopPrice = triggerPrice ?? stopPrice;
609
+ }
610
+ else if (parsed?.role === 'target') {
611
+ hasBracketTarget = true;
612
+ targetPrice = triggerPrice ?? targetPrice;
613
+ }
614
+ else if (isProtectiveHlOrder(info)) {
615
+ const t = String(info.orderType ?? o.type ?? '').toLowerCase();
616
+ if (t.includes('take profit') || t.includes('tp') || t.includes('take_profit')) {
617
+ hasManualTarget = true;
618
+ targetPrice = triggerPrice ?? targetPrice;
619
+ }
620
+ else {
621
+ hasManualStop = true;
622
+ stopPrice = triggerPrice ?? stopPrice;
623
+ }
624
+ }
625
+ }
626
+ const hasStop = hasBracketStop || hasManualStop;
627
+ const hasTarget = hasBracketTarget || hasManualTarget;
628
+ if (ledgerRow?.stopPrice !== undefined)
629
+ stopPrice = ledgerRow.stopPrice;
630
+ if (ledgerRow?.targetPrice !== undefined)
631
+ targetPrice = ledgerRow.targetPrice;
632
+ let reason;
633
+ if (hasStop || hasTarget) {
634
+ reason = hasBracketStop || hasBracketTarget ? 'bracket_active' : 'manual_order_protecting';
635
+ }
636
+ else if (ledgerRow &&
637
+ (ledgerRow.state === 'active' || ledgerRow.state === 'partial' || ledgerRow.state === 'attaching')) {
638
+ reason = 'stale_ledger_row';
639
+ }
640
+ else if (ledgerRow && isTerminalBracketState(ledgerRow.state)) {
641
+ reason = 'ledger_terminal_no_order';
642
+ }
643
+ else {
644
+ reason = 'no_protective_order';
645
+ }
646
+ // ★ T-2 under-coverage: a stop can exist AND still leave scaled-in size
647
+ // naked (fixed-size legs). Surface it in logs; the adapter's 60s
648
+ // truth-check sweep auto-resizes.
649
+ const contracts = Math.abs(Number(p.contracts ?? 0));
650
+ if (hasBracketStop && ledgerRow?.qty !== undefined && ledgerRow.qty + 1e-8 < contracts) {
651
+ logger.warn(TAG, `HL audit: ${p.symbol} stop leg sized ${ledgerRow.qty} vs position ${contracts} — ` +
652
+ 'under-covered (T-2); the truth-check sweep will resize');
653
+ }
654
+ entries.push({
655
+ symbol: p.symbol,
656
+ side: p.side,
657
+ contracts: p.contracts,
658
+ entry_price: p.entryPrice,
659
+ mark_price: p.markPrice,
660
+ has_stop: hasStop,
661
+ has_target: hasTarget,
662
+ stop_price: stopPrice,
663
+ target_price: targetPrice,
664
+ ledger_state: ledgerRow?.state ?? 'no_ledger_row',
665
+ reason,
666
+ recommended_action: hasStop ? 'none' : 'attach_brackets',
667
+ });
668
+ }
669
+ const nowTs = Date.now();
670
+ for (const e of entries) {
671
+ recordVerdictAndCheckFlicker(normalizeBracketSymbol(e.symbol), e.has_stop, nowTs);
672
+ }
673
+ const unprotected = entries.filter(e => !e.has_stop).length;
674
+ return {
675
+ ok: true,
676
+ mode: 'live',
677
+ brackets_enabled: true,
678
+ total_positions: entries.length,
679
+ protected_count: entries.length - unprotected,
680
+ unprotected_count: unprotected,
681
+ positions: entries,
682
+ };
683
+ }