@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.
- package/assets/bridge/gateway/event-parser.d.ts +6 -1
- package/assets/bridge/gateway/event-parser.js +19 -2
- package/assets/bridge/gateway/heartbeat-cron.d.ts +27 -0
- package/assets/bridge/gateway/heartbeat-cron.js +85 -0
- package/assets/bridge/gateway/poller.d.ts +1 -0
- package/assets/bridge/gateway/poller.js +14 -2
- package/assets/bridge/providers/gateway.d.ts +24 -2
- package/assets/bridge/providers/gateway.js +124 -25
- package/assets/bridge/setup.js +6 -51
- package/assets/shared/signals/conditions/registry.js +11 -2
- package/assets/shared/signals/strategy-adapter.js +17 -7
- package/assets/skill/SKILL.md +2 -0
- package/dist/deps.js +2 -2
- package/dist/plugin.js +35 -7
- package/package.json +1 -1
- package/assets/plugin/audit/mode-transition-audit.d.ts +0 -11
- package/assets/plugin/audit/mode-transition-audit.js +0 -29
- package/assets/plugin/balance-utils.d.ts +0 -36
- package/assets/plugin/balance-utils.js +0 -98
- package/assets/plugin/ccxt/binance-ban-gate.d.ts +0 -47
- package/assets/plugin/ccxt/binance-ban-gate.js +0 -420
- package/assets/plugin/ccxt/binance-private.d.ts +0 -346
- package/assets/plugin/ccxt/binance-private.js +0 -1525
- package/assets/plugin/ccxt/binance-public.d.ts +0 -34
- package/assets/plugin/ccxt/binance-public.js +0 -180
- package/assets/plugin/ccxt/intel-public.d.ts +0 -25
- package/assets/plugin/ccxt/intel-public.js +0 -80
- package/assets/plugin/ccxt/public-market-data-api.d.ts +0 -12
- package/assets/plugin/ccxt/public-market-data-api.js +0 -9
- package/assets/plugin/config/agent-config-client.d.ts +0 -77
- package/assets/plugin/config/agent-config-client.js +0 -188
- package/assets/plugin/config/agent-config-poller.d.ts +0 -32
- package/assets/plugin/config/agent-config-poller.js +0 -101
- package/assets/plugin/config/brackets-config.d.ts +0 -22
- package/assets/plugin/config/brackets-config.js +0 -58
- package/assets/plugin/config/entitlement-gate.d.ts +0 -51
- package/assets/plugin/config/entitlement-gate.js +0 -137
- package/assets/plugin/config/gate-store.d.ts +0 -18
- package/assets/plugin/config/gate-store.js +0 -61
- package/assets/plugin/config/plugin-config-io.d.ts +0 -215
- package/assets/plugin/config/plugin-config-io.js +0 -111
- package/assets/plugin/config/position-review-config.d.ts +0 -35
- package/assets/plugin/config/position-review-config.js +0 -105
- package/assets/plugin/config/tool-gate.d.ts +0 -53
- package/assets/plugin/config/tool-gate.js +0 -128
- package/assets/plugin/config/user-data-stream-config.d.ts +0 -89
- package/assets/plugin/config/user-data-stream-config.js +0 -239
- package/assets/plugin/connector-supervisor.d.ts +0 -36
- package/assets/plugin/connector-supervisor.js +0 -149
- package/assets/plugin/exchange-adapter.d.ts +0 -65
- package/assets/plugin/exchange-adapter.js +0 -4
- package/assets/plugin/index.d.ts +0 -30
- package/assets/plugin/index.js +0 -2678
- package/assets/plugin/ingest/pending-entry-metadata.d.ts +0 -74
- package/assets/plugin/ingest/pending-entry-metadata.js +0 -236
- package/assets/plugin/ingest/position-auto-capture.d.ts +0 -103
- package/assets/plugin/ingest/position-auto-capture.js +0 -411
- package/assets/plugin/ingest/position-decisions-client.d.ts +0 -322
- package/assets/plugin/ingest/position-decisions-client.js +0 -296
- package/assets/plugin/ingest/readiness-reporter.d.ts +0 -42
- package/assets/plugin/ingest/readiness-reporter.js +0 -163
- package/assets/plugin/ingest/reconcile-db-vs-exchange.d.ts +0 -13
- package/assets/plugin/ingest/reconcile-db-vs-exchange.js +0 -114
- package/assets/plugin/ingest/reconciler-cleanup.d.ts +0 -37
- package/assets/plugin/ingest/reconciler-cleanup.js +0 -147
- package/assets/plugin/ingest/rest-gap-filler.d.ts +0 -191
- package/assets/plugin/ingest/rest-gap-filler.js +0 -565
- package/assets/plugin/ingest/touched-symbols-store.d.ts +0 -25
- package/assets/plugin/ingest/touched-symbols-store.js +0 -96
- package/assets/plugin/ingest/trade-store-client.d.ts +0 -40
- package/assets/plugin/ingest/trade-store-client.js +0 -125
- package/assets/plugin/ingest/ws-ingest.d.ts +0 -43
- package/assets/plugin/ingest/ws-ingest.js +0 -126
- package/assets/plugin/learning/setup-family.d.ts +0 -21
- package/assets/plugin/learning/setup-family.js +0 -103
- package/assets/plugin/lifecycle/install-signal-handlers.d.ts +0 -33
- package/assets/plugin/lifecycle/install-signal-handlers.js +0 -112
- package/assets/plugin/lifecycle/shutdown-coordinator.d.ts +0 -43
- package/assets/plugin/lifecycle/shutdown-coordinator.js +0 -131
- package/assets/plugin/lifecycle/trading-operation-lock.d.ts +0 -17
- package/assets/plugin/lifecycle/trading-operation-lock.js +0 -14
- package/assets/plugin/live/bracket-id.d.ts +0 -26
- package/assets/plugin/live/bracket-id.js +0 -112
- package/assets/plugin/live/bracket-ledger.d.ts +0 -54
- package/assets/plugin/live/bracket-ledger.js +0 -267
- package/assets/plugin/live/bracket-manager.d.ts +0 -82
- package/assets/plugin/live/bracket-manager.js +0 -478
- package/assets/plugin/live/bracket-params.d.ts +0 -22
- package/assets/plugin/live/bracket-params.js +0 -124
- package/assets/plugin/live/bracket-reconciler.d.ts +0 -95
- package/assets/plugin/live/bracket-reconciler.js +0 -573
- package/assets/plugin/live/bracket-types.d.ts +0 -102
- package/assets/plugin/live/bracket-types.js +0 -8
- package/assets/plugin/live/deposit-tracker.d.ts +0 -62
- package/assets/plugin/live/deposit-tracker.js +0 -97
- package/assets/plugin/live/emergency-controls.d.ts +0 -32
- package/assets/plugin/live/emergency-controls.js +0 -226
- package/assets/plugin/live/exchange-errors.d.ts +0 -12
- package/assets/plugin/live/exchange-errors.js +0 -130
- package/assets/plugin/live/exchange-info-cache.d.ts +0 -37
- package/assets/plugin/live/exchange-info-cache.js +0 -134
- package/assets/plugin/live/fact-subscriber.d.ts +0 -78
- package/assets/plugin/live/fact-subscriber.js +0 -182
- package/assets/plugin/live/intent-journal.d.ts +0 -42
- package/assets/plugin/live/intent-journal.js +0 -122
- package/assets/plugin/live/listen-key-manager.d.ts +0 -70
- package/assets/plugin/live/listen-key-manager.js +0 -169
- package/assets/plugin/live/live-adapter.d.ts +0 -287
- package/assets/plugin/live/live-adapter.js +0 -1777
- package/assets/plugin/live/live-balance-enricher.d.ts +0 -32
- package/assets/plugin/live/live-balance-enricher.js +0 -104
- package/assets/plugin/live/live-bracket-api.d.ts +0 -13
- package/assets/plugin/live/live-bracket-api.js +0 -20
- package/assets/plugin/live/live-state-store.d.ts +0 -194
- package/assets/plugin/live/live-state-store.js +0 -450
- package/assets/plugin/live/local-signal-service.d.ts +0 -57
- package/assets/plugin/live/local-signal-service.js +0 -151
- package/assets/plugin/live/local-strategy-evaluator.d.ts +0 -62
- package/assets/plugin/live/local-strategy-evaluator.js +0 -131
- package/assets/plugin/live/microstructure-assembler.d.ts +0 -54
- package/assets/plugin/live/microstructure-assembler.js +0 -148
- package/assets/plugin/live/order-poller.d.ts +0 -29
- package/assets/plugin/live/order-poller.js +0 -125
- package/assets/plugin/live/position-state-store.d.ts +0 -83
- package/assets/plugin/live/position-state-store.js +0 -237
- package/assets/plugin/live/proposal-decision-listener.d.ts +0 -70
- package/assets/plugin/live/proposal-decision-listener.js +0 -292
- package/assets/plugin/live/proposal-manager.d.ts +0 -76
- package/assets/plugin/live/proposal-manager.js +0 -140
- package/assets/plugin/live/rate-limiter.d.ts +0 -47
- package/assets/plugin/live/rate-limiter.js +0 -159
- package/assets/plugin/live/reconciler.d.ts +0 -39
- package/assets/plugin/live/reconciler.js +0 -175
- package/assets/plugin/live/setup-buckets.d.ts +0 -7
- package/assets/plugin/live/setup-buckets.js +0 -33
- package/assets/plugin/live/slippage-tracker.d.ts +0 -45
- package/assets/plugin/live/slippage-tracker.js +0 -78
- package/assets/plugin/live/stop-watcher.d.ts +0 -60
- package/assets/plugin/live/stop-watcher.js +0 -215
- package/assets/plugin/live/user-data-active-probe.d.ts +0 -54
- package/assets/plugin/live/user-data-active-probe.js +0 -180
- package/assets/plugin/live/user-data-stream-controller.d.ts +0 -200
- package/assets/plugin/live/user-data-stream-controller.js +0 -579
- package/assets/plugin/live/user-data-stream-ws.d.ts +0 -22
- package/assets/plugin/live/user-data-stream-ws.js +0 -63
- package/assets/plugin/live/user-data-stream.d.ts +0 -243
- package/assets/plugin/live/user-data-stream.js +0 -704
- package/assets/plugin/logger.d.ts +0 -2
- package/assets/plugin/logger.js +0 -2
- package/assets/plugin/mfe.d.ts +0 -21
- package/assets/plugin/mfe.js +0 -68
- package/assets/plugin/onboarding/mode-ladder.d.ts +0 -1
- package/assets/plugin/onboarding/mode-ladder.js +0 -3
- package/assets/plugin/onboarding/runtime.d.ts +0 -84
- package/assets/plugin/onboarding/runtime.js +0 -173
- package/assets/plugin/openclaw.plugin.json +0 -92
- package/assets/plugin/paper-adapter.d.ts +0 -24
- package/assets/plugin/paper-adapter.js +0 -91
- package/assets/plugin/persistence/state-manager.d.ts +0 -66
- package/assets/plugin/persistence/state-manager.js +0 -222
- package/assets/plugin/pinned-plan.d.ts +0 -9
- package/assets/plugin/pinned-plan.js +0 -23
- package/assets/plugin/portfolio/wave9-admission.d.ts +0 -67
- package/assets/plugin/portfolio/wave9-admission.js +0 -262
- package/assets/plugin/portfolio/wave9-policy.d.ts +0 -36
- package/assets/plugin/portfolio/wave9-policy.js +0 -183
- package/assets/plugin/risk/pre-trade-check.d.ts +0 -38
- package/assets/plugin/risk/pre-trade-check.js +0 -345
- package/assets/plugin/risk/pre-trade-types.d.ts +0 -60
- package/assets/plugin/risk/pre-trade-types.js +0 -3
- package/assets/plugin/shadow/shadow-tracker.d.ts +0 -36
- package/assets/plugin/shadow/shadow-tracker.js +0 -151
- package/assets/plugin/shadow/types.d.ts +0 -42
- package/assets/plugin/shadow/types.js +0 -20
- package/assets/plugin/shared/indicators-extended.d.ts +0 -52
- package/assets/plugin/shared/indicators-extended.js +0 -291
- package/assets/plugin/shared/indicators.d.ts +0 -15
- package/assets/plugin/shared/indicators.js +0 -114
- package/assets/plugin/signals/conditions/registry.d.ts +0 -16
- package/assets/plugin/signals/conditions/registry.js +0 -1324
- package/assets/plugin/signals/conditions/types.d.ts +0 -1
- package/assets/plugin/signals/conditions/types.js +0 -4
- package/assets/plugin/signals/direction-rules.d.ts +0 -3
- package/assets/plugin/signals/direction-rules.js +0 -24
- package/assets/plugin/signals/entry-rules.d.ts +0 -6
- package/assets/plugin/signals/entry-rules.js +0 -33
- package/assets/plugin/signals/serialize-context.d.ts +0 -4
- package/assets/plugin/signals/serialize-context.js +0 -39
- package/assets/plugin/signals/stop-rules.d.ts +0 -3
- package/assets/plugin/signals/stop-rules.js +0 -48
- package/assets/plugin/signals/strategy-adapter.d.ts +0 -47
- package/assets/plugin/signals/strategy-adapter.js +0 -199
- package/assets/plugin/signals/types.d.ts +0 -1
- package/assets/plugin/signals/types.js +0 -8
- package/assets/plugin/simulator/exchange-simulator.d.ts +0 -93
- package/assets/plugin/simulator/exchange-simulator.js +0 -689
- package/assets/plugin/simulator/fill-engine.d.ts +0 -53
- package/assets/plugin/simulator/fill-engine.js +0 -280
- package/assets/plugin/simulator/paper-market-feed.d.ts +0 -26
- package/assets/plugin/simulator/paper-market-feed.js +0 -104
- package/assets/plugin/simulator/realistic-fills.d.ts +0 -59
- package/assets/plugin/simulator/realistic-fills.js +0 -175
- package/assets/plugin/simulator/types.d.ts +0 -224
- package/assets/plugin/simulator/types.js +0 -43
- package/assets/plugin/strategy/builtin-strategies.d.ts +0 -2
- package/assets/plugin/strategy/builtin-strategies.js +0 -113
- package/assets/plugin/strategy/condition-registry.d.ts +0 -3
- package/assets/plugin/strategy/condition-registry.js +0 -153
- package/assets/plugin/strategy/evaluator.d.ts +0 -70
- package/assets/plugin/strategy/evaluator.js +0 -98
- package/assets/plugin/tools/assessment-validation.d.ts +0 -120
- package/assets/plugin/tools/assessment-validation.js +0 -415
- package/assets/plugin/tools/attach-brackets.d.ts +0 -39
- package/assets/plugin/tools/attach-brackets.js +0 -399
- package/assets/plugin/tools/audit-bracket-protection.d.ts +0 -49
- package/assets/plugin/tools/audit-bracket-protection.js +0 -527
- package/assets/plugin/tools/cancel-all-orders.d.ts +0 -9
- package/assets/plugin/tools/cancel-all-orders.js +0 -8
- package/assets/plugin/tools/cancel-order.d.ts +0 -14
- package/assets/plugin/tools/cancel-order.js +0 -60
- package/assets/plugin/tools/check-position-health.d.ts +0 -46
- package/assets/plugin/tools/check-position-health.js +0 -194
- package/assets/plugin/tools/clear-exchange-credentials.d.ts +0 -24
- package/assets/plugin/tools/clear-exchange-credentials.js +0 -70
- package/assets/plugin/tools/close-position.d.ts +0 -45
- package/assets/plugin/tools/close-position.js +0 -722
- package/assets/plugin/tools/create-order.d.ts +0 -82
- package/assets/plugin/tools/create-order.js +0 -1516
- package/assets/plugin/tools/exit-gate.d.ts +0 -58
- package/assets/plugin/tools/exit-gate.js +0 -162
- package/assets/plugin/tools/fetch-balance.d.ts +0 -5
- package/assets/plugin/tools/fetch-balance.js +0 -4
- package/assets/plugin/tools/fetch-ohlcv.d.ts +0 -11
- package/assets/plugin/tools/fetch-ohlcv.js +0 -8
- package/assets/plugin/tools/fetch-open-orders.d.ts +0 -7
- package/assets/plugin/tools/fetch-open-orders.js +0 -4
- package/assets/plugin/tools/fetch-positions.d.ts +0 -7
- package/assets/plugin/tools/fetch-positions.js +0 -4
- package/assets/plugin/tools/fetch-ticker.d.ts +0 -11
- package/assets/plugin/tools/fetch-ticker.js +0 -5
- package/assets/plugin/tools/get-agent-profile.d.ts +0 -4
- package/assets/plugin/tools/get-agent-profile.js +0 -6
- package/assets/plugin/tools/get-analytics.d.ts +0 -6
- package/assets/plugin/tools/get-analytics.js +0 -7
- package/assets/plugin/tools/get-backtest.d.ts +0 -12
- package/assets/plugin/tools/get-backtest.js +0 -91
- package/assets/plugin/tools/get-basis.d.ts +0 -7
- package/assets/plugin/tools/get-basis.js +0 -7
- package/assets/plugin/tools/get-bracket-config.d.ts +0 -11
- package/assets/plugin/tools/get-bracket-config.js +0 -24
- package/assets/plugin/tools/get-cascade-risk.d.ts +0 -7
- package/assets/plugin/tools/get-cascade-risk.js +0 -8
- package/assets/plugin/tools/get-crypto-metrics.d.ts +0 -18
- package/assets/plugin/tools/get-crypto-metrics.js +0 -62
- package/assets/plugin/tools/get-cvd.d.ts +0 -6
- package/assets/plugin/tools/get-cvd.js +0 -6
- package/assets/plugin/tools/get-divergences.d.ts +0 -6
- package/assets/plugin/tools/get-divergences.js +0 -6
- package/assets/plugin/tools/get-funding-context.d.ts +0 -6
- package/assets/plugin/tools/get-funding-context.js +0 -16
- package/assets/plugin/tools/get-liquidation-levels.d.ts +0 -7
- package/assets/plugin/tools/get-liquidation-levels.js +0 -7
- package/assets/plugin/tools/get-liquidation-pulse.d.ts +0 -9
- package/assets/plugin/tools/get-liquidation-pulse.js +0 -22
- package/assets/plugin/tools/get-market-breadth.d.ts +0 -6
- package/assets/plugin/tools/get-market-breadth.js +0 -8
- package/assets/plugin/tools/get-market-intel.d.ts +0 -19
- package/assets/plugin/tools/get-market-intel.js +0 -116
- package/assets/plugin/tools/get-market-structure.d.ts +0 -47
- package/assets/plugin/tools/get-market-structure.js +0 -198
- package/assets/plugin/tools/get-my-mined-patterns.d.ts +0 -20
- package/assets/plugin/tools/get-my-mined-patterns.js +0 -61
- package/assets/plugin/tools/get-my-proposed-learnings.d.ts +0 -20
- package/assets/plugin/tools/get-my-proposed-learnings.js +0 -55
- package/assets/plugin/tools/get-my-recent-reviews.d.ts +0 -22
- package/assets/plugin/tools/get-my-recent-reviews.js +0 -66
- package/assets/plugin/tools/get-orderbook.d.ts +0 -21
- package/assets/plugin/tools/get-orderbook.js +0 -32
- package/assets/plugin/tools/get-pattern-scan.d.ts +0 -7
- package/assets/plugin/tools/get-pattern-scan.js +0 -8
- package/assets/plugin/tools/get-regime.d.ts +0 -6
- package/assets/plugin/tools/get-regime.js +0 -7
- package/assets/plugin/tools/get-relevant-learnings.d.ts +0 -21
- package/assets/plugin/tools/get-relevant-learnings.js +0 -65
- package/assets/plugin/tools/get-resting-liquidity.d.ts +0 -6
- package/assets/plugin/tools/get-resting-liquidity.js +0 -11
- package/assets/plugin/tools/get-risk-scenario.d.ts +0 -29
- package/assets/plugin/tools/get-risk-scenario.js +0 -47
- package/assets/plugin/tools/get-risk-summary.d.ts +0 -51
- package/assets/plugin/tools/get-risk-summary.js +0 -118
- package/assets/plugin/tools/get-sentiment.d.ts +0 -4
- package/assets/plugin/tools/get-sentiment.js +0 -6
- package/assets/plugin/tools/get-session-review.d.ts +0 -7
- package/assets/plugin/tools/get-session-review.js +0 -8
- package/assets/plugin/tools/get-setup-detail.d.ts +0 -7
- package/assets/plugin/tools/get-setup-detail.js +0 -311
- package/assets/plugin/tools/get-signals.d.ts +0 -15
- package/assets/plugin/tools/get-signals.js +0 -54
- package/assets/plugin/tools/get-sizing.d.ts +0 -6
- package/assets/plugin/tools/get-sizing.js +0 -6
- package/assets/plugin/tools/get-trade-feedback.d.ts +0 -7
- package/assets/plugin/tools/get-trade-feedback.js +0 -8
- package/assets/plugin/tools/get-trade-flow.d.ts +0 -7
- package/assets/plugin/tools/get-trade-flow.js +0 -7
- package/assets/plugin/tools/get-volume-analysis.d.ts +0 -21
- package/assets/plugin/tools/get-volume-analysis.js +0 -74
- package/assets/plugin/tools/get-volume-profile.d.ts +0 -7
- package/assets/plugin/tools/get-volume-profile.js +0 -7
- package/assets/plugin/tools/get-wave9-status.d.ts +0 -127
- package/assets/plugin/tools/get-wave9-status.js +0 -796
- package/assets/plugin/tools/helpers.d.ts +0 -26
- package/assets/plugin/tools/helpers.js +0 -39
- package/assets/plugin/tools/intel-api.d.ts +0 -34
- package/assets/plugin/tools/intel-api.js +0 -119
- package/assets/plugin/tools/intel-cache.d.ts +0 -25
- package/assets/plugin/tools/intel-cache.js +0 -148
- package/assets/plugin/tools/list-strategies.d.ts +0 -17
- package/assets/plugin/tools/list-strategies.js +0 -23
- package/assets/plugin/tools/modify-stop.d.ts +0 -21
- package/assets/plugin/tools/modify-stop.js +0 -120
- package/assets/plugin/tools/modify-target.d.ts +0 -21
- package/assets/plugin/tools/modify-target.js +0 -110
- package/assets/plugin/tools/propose-learning.d.ts +0 -22
- package/assets/plugin/tools/propose-learning.js +0 -65
- package/assets/plugin/tools/query-review-outcomes.d.ts +0 -30
- package/assets/plugin/tools/query-review-outcomes.js +0 -64
- package/assets/plugin/tools/query-trades.d.ts +0 -21
- package/assets/plugin/tools/query-trades.js +0 -37
- package/assets/plugin/tools/record-position-reviews.d.ts +0 -38
- package/assets/plugin/tools/record-position-reviews.js +0 -147
- package/assets/plugin/tools/save-strategy.d.ts +0 -16
- package/assets/plugin/tools/save-strategy.js +0 -46
- package/assets/plugin/tools/scan-pairs.d.ts +0 -18
- package/assets/plugin/tools/scan-pairs.js +0 -231
- package/assets/plugin/tools/score-setup.d.ts +0 -31
- package/assets/plugin/tools/score-setup.js +0 -268
- package/assets/plugin/tools/set-bracket-requirement.d.ts +0 -18
- package/assets/plugin/tools/set-bracket-requirement.js +0 -81
- package/assets/plugin/tools/set-exchange-credentials.d.ts +0 -25
- package/assets/plugin/tools/set-exchange-credentials.js +0 -80
- package/assets/plugin/tools/set-trading-mode.d.ts +0 -26
- package/assets/plugin/tools/set-trading-mode.js +0 -135
- package/assets/plugin/tools/test-exchange-credentials.d.ts +0 -16
- package/assets/plugin/tools/test-exchange-credentials.js +0 -100
- package/assets/plugin/tools/toggle-strategy.d.ts +0 -8
- package/assets/plugin/tools/toggle-strategy.js +0 -15
- package/assets/plugin/trading-params-cache.d.ts +0 -26
- package/assets/plugin/trading-params-cache.js +0 -52
- package/assets/plugin/types.d.ts +0 -134
- package/assets/plugin/types.js +0 -7
- package/assets/plugin/util/plugin-paths.d.ts +0 -3
- package/assets/plugin/util/plugin-paths.js +0 -15
- package/assets/plugin/venues/hyperliquid/hl-balance.d.ts +0 -116
- package/assets/plugin/venues/hyperliquid/hl-balance.js +0 -145
- package/assets/plugin/venues/hyperliquid/hl-brackets.d.ts +0 -102
- package/assets/plugin/venues/hyperliquid/hl-brackets.js +0 -172
- package/assets/plugin/venues/hyperliquid/hl-cloid.d.ts +0 -22
- package/assets/plugin/venues/hyperliquid/hl-cloid.js +0 -82
- package/assets/plugin/venues/hyperliquid/hl-info-cache.d.ts +0 -46
- package/assets/plugin/venues/hyperliquid/hl-info-cache.js +0 -125
- package/assets/plugin/venues/hyperliquid/hl-live-adapter.d.ts +0 -88
- package/assets/plugin/venues/hyperliquid/hl-live-adapter.js +0 -353
- package/assets/plugin/venues/hyperliquid/hl-precision.d.ts +0 -61
- package/assets/plugin/venues/hyperliquid/hl-precision.js +0 -176
- package/assets/plugin/venues/hyperliquid/hl-private.d.ts +0 -88
- package/assets/plugin/venues/hyperliquid/hl-private.js +0 -357
- package/assets/plugin/venues/hyperliquid/hl-public.d.ts +0 -79
- package/assets/plugin/venues/hyperliquid/hl-public.js +0 -429
- package/assets/plugin/venues/hyperliquid/hl-rate-gate.d.ts +0 -57
- package/assets/plugin/venues/hyperliquid/hl-rate-gate.js +0 -220
- package/assets/plugin/venues/hyperliquid/hl-user-stream.d.ts +0 -90
- package/assets/plugin/venues/hyperliquid/hl-user-stream.js +0 -220
- package/assets/plugin/venues/registry.d.ts +0 -38
- package/assets/plugin/venues/registry.js +0 -46
- package/assets/plugin/venues/symbols.d.ts +0 -43
- package/assets/plugin/venues/symbols.js +0 -107
- package/assets/plugin/wave9/live-account-capture.d.ts +0 -67
- package/assets/plugin/wave9/live-account-capture.js +0 -435
- package/assets/plugin/wave9/live-autonomous-protection.d.ts +0 -39
- package/assets/plugin/wave9/live-autonomous-protection.js +0 -112
- package/assets/plugin/wave9/live-durable-reconciliation-scheduler.d.ts +0 -33
- package/assets/plugin/wave9/live-durable-reconciliation-scheduler.js +0 -115
- package/assets/plugin/wave9/live-execution-ledger.d.ts +0 -107
- package/assets/plugin/wave9/live-execution-ledger.js +0 -498
- package/assets/plugin/wave9/live-position-confirmation.d.ts +0 -18
- package/assets/plugin/wave9/live-position-confirmation.js +0 -111
- package/assets/plugin/wave9/live-residual-protection.d.ts +0 -18
- package/assets/plugin/wave9/live-residual-protection.js +0 -250
- package/assets/plugin/wave9/live-startup-reconciliation.d.ts +0 -38
- package/assets/plugin/wave9/live-startup-reconciliation.js +0 -454
- package/assets/plugin/wave9/live-symbol-ownership.d.ts +0 -20
- package/assets/plugin/wave9/live-symbol-ownership.js +0 -132
- package/assets/plugin/wave9/paper-admission-guard.d.ts +0 -199
- package/assets/plugin/wave9/paper-admission-guard.js +0 -650
- package/assets/plugin/wave9/usdm-evidence-provider.d.ts +0 -42
- package/assets/plugin/wave9/usdm-evidence-provider.js +0 -133
|
@@ -1,722 +0,0 @@
|
|
|
1
|
-
// Tool: close_position — close a position at market (paper or live)
|
|
2
|
-
// NO readiness gate — emergency control (flatten), must always work.
|
|
3
|
-
//
|
|
4
|
-
// SKILL.md v2.10.0 gate (Position Management Discipline): the agent must
|
|
5
|
-
// submit a documented `reason` and (except for operator_command) a
|
|
6
|
-
// structured `assessment` describing the reasoning behind the close. The
|
|
7
|
-
// LLM's value is context-sensitive reasoning; we enforce the reasoning
|
|
8
|
-
// at the API boundary via a schema, not a time floor.
|
|
9
|
-
//
|
|
10
|
-
// 2026-04-21 false-bracket_integrity safeguard: audit_bracket_protection
|
|
11
|
-
// was observed reporting has_stop=false while the reconciler (same data
|
|
12
|
-
// source, same call) consistently confirmed 2 live bracket orders on the
|
|
13
|
-
// exchange. Agent used this false negative to trigger close_position with
|
|
14
|
-
// reason=bracket_integrity, burning ~8–20 bps per cycle, 14+ cycles today.
|
|
15
|
-
// Fix: before executing a bracket_integrity close, the plugin independently
|
|
16
|
-
// verifies the ledger + exchange state. If the bracket is genuinely live
|
|
17
|
-
// (ledger active/partial AND an exchange order matches the stored cid),
|
|
18
|
-
// reject the close — audit was wrong, the position is protected. This is
|
|
19
|
-
// a same-signal re-check at the API boundary, not a duplicate of the
|
|
20
|
-
// audit tool; it catches the observed class of false negatives without
|
|
21
|
-
// trusting the audit's own verdict.
|
|
22
|
-
import { formatError, logger } from '../logger.js';
|
|
23
|
-
import { fetchCurrentPrice, fetchOrderBook, isError } from './helpers.js';
|
|
24
|
-
import { validateClosePosition, } from './assessment-validation.js';
|
|
25
|
-
import { onClosePositionFilled } from '../ingest/position-auto-capture.js';
|
|
26
|
-
import { evaluateExitGate, } from './exit-gate.js';
|
|
27
|
-
import { getRecentAuditVerdictHistory } from './audit-bracket-protection.js';
|
|
28
|
-
import { loadExitGateMode } from '../config/position-review-config.js';
|
|
29
|
-
import { confirmWave9LivePositionFlat } from '../wave9/live-position-confirmation.js';
|
|
30
|
-
import { reprotectWave9LiveResidual, } from '../wave9/live-residual-protection.js';
|
|
31
|
-
import { captureWave9PaperPositionFingerprint, isWave9ManagedPosition, WAVE9_MECHANICAL_EXIT_REASON, } from '../wave9/paper-admission-guard.js';
|
|
32
|
-
const TAG = 'close-position';
|
|
33
|
-
function currentWave9ExecutionMode(deps) {
|
|
34
|
-
const runtimeMode = deps.wave9TradingModeCheck?.() ?? deps.adapter.mode;
|
|
35
|
-
if (!deps.adapter.isLive && deps.adapter.mode === 'PAPER' && runtimeMode === 'PAPER')
|
|
36
|
-
return 'PAPER';
|
|
37
|
-
if (deps.adapter.isLive && deps.adapter.mode === 'LIVE' && runtimeMode === 'LIVE')
|
|
38
|
-
return 'LIVE';
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
// Bracket-integrity circuit-breaker. Counts SUCCESSFUL close_position calls
|
|
42
|
-
// with reason='bracket_integrity' in a rolling 60-min window. When the 3rd
|
|
43
|
-
// such close is attempted, reject — repeated bracket-integrity flushes in
|
|
44
|
-
// the same hour means EITHER the bracket subsystem is actually broken (in
|
|
45
|
-
// which case the operator needs to know, not the agent quietly burning more
|
|
46
|
-
// positions) OR the audit tool is false-negativing (same outcome: stop the
|
|
47
|
-
// burn). 2026-05-15 session ran this exact pattern 3 times in 4 hours and
|
|
48
|
-
// realised −$3.20 of bracket-integrity flushes before the operator caught it.
|
|
49
|
-
const BRACKET_INTEGRITY_WINDOW_MS = 60 * 60 * 1000;
|
|
50
|
-
const BRACKET_INTEGRITY_LIMIT = 3;
|
|
51
|
-
let bracketIntegrityCloses = []; // timestamps of successful closes
|
|
52
|
-
export async function closePositionTool(args, deps) {
|
|
53
|
-
// Schema gate FIRST — reject before touching the exchange.
|
|
54
|
-
const wave9ExitClaimed = args.reason !== 'operator_command' && (args.reason === WAVE9_MECHANICAL_EXIT_REASON
|
|
55
|
-
|| args.wave9_exit_token !== undefined
|
|
56
|
-
|| args.candidate_id !== undefined);
|
|
57
|
-
if (wave9ExitClaimed && deps.wave9VenueCheck?.() !== 'binance') {
|
|
58
|
-
return { error: 'Wave 9 reversal close refused: execution is pinned to Binance USD-M futures.' };
|
|
59
|
-
}
|
|
60
|
-
if (wave9ExitClaimed && !deps.operationLock) {
|
|
61
|
-
return { error: 'Wave 9 reversal close refused: process-local trading operation lock is unavailable.' };
|
|
62
|
-
}
|
|
63
|
-
const initialWave9Mode = wave9ExitClaimed ? currentWave9ExecutionMode(deps) : null;
|
|
64
|
-
let wave9Lease;
|
|
65
|
-
if (wave9ExitClaimed) {
|
|
66
|
-
if (!initialWave9Mode) {
|
|
67
|
-
return {
|
|
68
|
-
error: 'Wave 9 reversal close refused: capability execution requires an exact PAPER/paper-adapter ' +
|
|
69
|
-
'or LIVE/live-adapter runtime match.',
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
if (args.reason !== WAVE9_MECHANICAL_EXIT_REASON
|
|
73
|
-
|| !args.wave9_exit_token
|
|
74
|
-
|| !args.candidate_id
|
|
75
|
-
|| !deps.wave9AdmissionGuard) {
|
|
76
|
-
return { error: 'Wave 9 reversal close requires its exact reason, candidate identity, and short-lived exit token.' };
|
|
77
|
-
}
|
|
78
|
-
const executionCanonical = args.symbol.toUpperCase().replace(/[^A-Z0-9]/g, '').replace(/USDTUSDT$/, 'USDT');
|
|
79
|
-
if (!executionCanonical.endsWith('USDT') || executionCanonical.length <= 4) {
|
|
80
|
-
return { error: `Wave 9 reversal close refused: unsupported execution symbol ${args.symbol}.` };
|
|
81
|
-
}
|
|
82
|
-
if (initialWave9Mode === 'LIVE' && (!deps.captureWave9PositionFingerprint || !deps.wave9LiveLedger)) {
|
|
83
|
-
return {
|
|
84
|
-
error: 'Wave 9 live reversal close refused: authoritative live position capture and the durable ' +
|
|
85
|
-
'execution ledger are required.',
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
args = { ...args, symbol: `${executionCanonical.slice(0, -4)}/USDT:USDT` };
|
|
89
|
-
try {
|
|
90
|
-
wave9Lease = await deps.operationLock.withAccountLock(`wave9-begin-close:${args.candidate_id ?? args.symbol}`, async () => {
|
|
91
|
-
if (currentWave9ExecutionMode(deps) !== initialWave9Mode) {
|
|
92
|
-
throw new Error('adapter or trading mode changed before Wave 9 reversal began');
|
|
93
|
-
}
|
|
94
|
-
let position;
|
|
95
|
-
let positionFingerprint;
|
|
96
|
-
if (initialWave9Mode === 'LIVE') {
|
|
97
|
-
const capture = await deps.captureWave9PositionFingerprint(args.symbol);
|
|
98
|
-
position = capture.position;
|
|
99
|
-
positionFingerprint = capture.fingerprint;
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
deps.refreshPaperState?.();
|
|
103
|
-
const positions = await deps.adapter.getPositionsOrNull();
|
|
104
|
-
if (positions === null)
|
|
105
|
-
throw new Error('paper position snapshot unavailable');
|
|
106
|
-
const canonical = (value) => value.toUpperCase().replace(/[^A-Z0-9]/g, '').replace(/USDTUSDT$/, 'USDT');
|
|
107
|
-
const matches = positions.filter((candidate) => canonical(candidate.symbol) === canonical(args.symbol));
|
|
108
|
-
if (matches.length !== 1)
|
|
109
|
-
throw new Error('exactly one matching held position is required');
|
|
110
|
-
position = matches[0];
|
|
111
|
-
positionFingerprint = captureWave9PaperPositionFingerprint(deps.adapter, args.symbol).fingerprint;
|
|
112
|
-
}
|
|
113
|
-
if (!isWave9ManagedPosition(position)
|
|
114
|
-
|| position.candidateId !== args.candidate_id
|
|
115
|
-
|| !position.missionId) {
|
|
116
|
-
throw new Error('held position lacks exact Wave 9 identity/geometry');
|
|
117
|
-
}
|
|
118
|
-
return deps.wave9AdmissionGuard.beginExit({
|
|
119
|
-
token: args.wave9_exit_token,
|
|
120
|
-
candidateId: args.candidate_id,
|
|
121
|
-
missionId: position.missionId,
|
|
122
|
-
symbol: args.symbol,
|
|
123
|
-
positionSide: position.side,
|
|
124
|
-
setupType: position.setupType,
|
|
125
|
-
reason: args.reason,
|
|
126
|
-
positionFingerprint,
|
|
127
|
-
tradingMode: initialWave9Mode,
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
catch (err) {
|
|
132
|
-
return { error: `Wave 9 reversal close refused: ${formatError(err)}` };
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
else {
|
|
136
|
-
// Preserve the generic tool contract: malformed calls are rejected before
|
|
137
|
-
// any adapter read. Wave 9 classification is an additional check only for
|
|
138
|
-
// already-valid, non-operator risk-reducing closes.
|
|
139
|
-
const v = validateClosePosition(args);
|
|
140
|
-
if (!v.ok) {
|
|
141
|
-
logger.warn(TAG, `close_position rejected: ${v.error} (symbol=${args.symbol}, reason=${args.reason ?? 'missing'})`);
|
|
142
|
-
return { error: v.error ?? 'Invalid close_position arguments.' };
|
|
143
|
-
}
|
|
144
|
-
if (args.reason !== 'operator_command'
|
|
145
|
-
&& deps.adapter.isLive
|
|
146
|
-
&& deps.checkWave9LiveSymbolOwnership
|
|
147
|
-
&& !deps.operationLock) {
|
|
148
|
-
return {
|
|
149
|
-
error: 'Generic live close_position refused: the shared trading operation lock is required ' +
|
|
150
|
-
'while Wave 9 LIVE ownership checks are enabled.',
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
// When a trusted position snapshot is available, do not route a held
|
|
154
|
-
// Wave 9 position through a generic thesis/risk/bracket reason. Snapshot
|
|
155
|
-
// failure stays fail-open because an ordinary risk-reducing close must not
|
|
156
|
-
// be trapped by extra strategy-lifecycle I/O. Operator remains unconditional.
|
|
157
|
-
if (args.reason !== 'operator_command') {
|
|
158
|
-
try {
|
|
159
|
-
const getTrusted = deps.adapter.getPositionsOrNull?.bind(deps.adapter);
|
|
160
|
-
const held = getTrusted ? await getTrusted() : undefined;
|
|
161
|
-
if (held) {
|
|
162
|
-
const canonical = (value) => value.toUpperCase().replace(/[^A-Z0-9]/g, '').replace(/USDTUSDT$/, 'USDT');
|
|
163
|
-
if (held.some((position) => canonical(position.symbol) === canonical(args.symbol)
|
|
164
|
-
&& isWave9ManagedPosition(position))) {
|
|
165
|
-
return {
|
|
166
|
-
error: `Wave 9 position close refused: call get_wave9_status and use reason=${WAVE9_MECHANICAL_EXIT_REASON} ` +
|
|
167
|
-
'with its single-use exit token. Only an explicit operator_command bypasses the strategy exit policy.',
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
else if (held === null) {
|
|
172
|
-
logger.warn(TAG, 'Wave 9 generic-close classification unavailable; proceeding with legacy risk-reducing close semantics.');
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
catch (err) {
|
|
176
|
-
logger.warn(TAG, `Wave 9 generic-close classification failed (${formatError(err)}); proceeding with legacy risk-reducing close semantics.`);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
// Exit-gate check — see docs/EXIT_GATE_DESIGN.md. The gate is orthogonal to
|
|
181
|
-
// the bracket_integrity safeguard below; both can fire on the same call.
|
|
182
|
-
// Behaviour by mode:
|
|
183
|
-
// off — gate skipped entirely (no input fetch, no log).
|
|
184
|
-
// shadow — gate runs, verdict logged to close_assessment.metadata.gate_eval,
|
|
185
|
-
// close_position always proceeds.
|
|
186
|
-
// observe — gate runs; on BLOCK we still proceed but the verdict is logged
|
|
187
|
-
// and a warning printed to journalctl.
|
|
188
|
-
// enforce — gate runs; on BLOCK we hard-reject with the recovery hint.
|
|
189
|
-
const gateMode = deps.exitGateMode ?? loadExitGateMode();
|
|
190
|
-
let gateVerdict = null;
|
|
191
|
-
// 0a (2026-06-16): hoist the gate inputs to function scope so the post-close
|
|
192
|
-
// capture block can persist a full inputs snapshot. Previously `inputs` was a
|
|
193
|
-
// block-local const that went out of scope before the capture write, which is
|
|
194
|
-
// why only {mode,outcome,tier,code} ever reached the journal (the §5 `inputs`
|
|
195
|
-
// snapshot was never constructed). See docs/EXIT_DISCIPLINE_BUILD_PLAN.md
|
|
196
|
-
// Step 0a + docs/EXIT_GATE_DESIGN.md §5.
|
|
197
|
-
let gateInputs = null;
|
|
198
|
-
if (!wave9ExitClaimed && gateMode !== 'off') {
|
|
199
|
-
gateInputs = await buildExitGateInputs(args, deps);
|
|
200
|
-
gateVerdict = evaluateExitGate(gateInputs);
|
|
201
|
-
logger.info(TAG, `exit_gate mode=${gateMode} ${gateVerdict.outcome} tier=${gateVerdict.tier} code=${gateVerdict.code} (symbol=${args.symbol}, reason=${args.reason})`);
|
|
202
|
-
if (gateVerdict.outcome === 'BLOCK' && gateMode === 'enforce') {
|
|
203
|
-
logger.warn(TAG, `close_position REJECTED by exit gate (enforce): ${gateVerdict.code} — ${gateVerdict.recovery_hint ?? '(no hint)'}`);
|
|
204
|
-
return {
|
|
205
|
-
error: `close_position blocked by exit gate (${gateVerdict.code}). ` +
|
|
206
|
-
(gateVerdict.recovery_hint ?? 'See docs/EXIT_GATE_DESIGN.md.'),
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
if (gateVerdict.outcome === 'BLOCK' && gateMode === 'observe') {
|
|
210
|
-
logger.warn(TAG, `close_position WOULD BE BLOCKED by exit gate (observe): ${gateVerdict.code} — ${gateVerdict.recovery_hint ?? '(no hint)'} — proceeding because mode=observe`);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
// In paper mode, fetch latest ticker + order book for realistic fills
|
|
214
|
-
if (!deps.adapter.isLive) {
|
|
215
|
-
try {
|
|
216
|
-
const paperDeps = { binanceApi: deps.binanceApi, simulator: deps.adapter.getSimulator() };
|
|
217
|
-
const [priceResult] = await Promise.all([
|
|
218
|
-
fetchCurrentPrice(args.symbol, paperDeps),
|
|
219
|
-
fetchOrderBook(args.symbol, paperDeps),
|
|
220
|
-
]);
|
|
221
|
-
if (!isError(priceResult)) {
|
|
222
|
-
// The helper updates the simulator mark used by the actual close fill.
|
|
223
|
-
}
|
|
224
|
-
else {
|
|
225
|
-
if (wave9Lease) {
|
|
226
|
-
deps.wave9AdmissionGuard.abort(wave9Lease, 'exit_market_data_unavailable', { retryable: true });
|
|
227
|
-
wave9Lease = undefined;
|
|
228
|
-
}
|
|
229
|
-
return priceResult;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
catch (err) {
|
|
233
|
-
if (wave9Lease) {
|
|
234
|
-
deps.wave9AdmissionGuard.abort(wave9Lease, 'exit_market_data_threw', { retryable: true });
|
|
235
|
-
wave9Lease = undefined;
|
|
236
|
-
}
|
|
237
|
-
return { error: `close_position market-data refresh failed: ${formatError(err)}` };
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
// Log the assessment so every agent close is auditable in the journal.
|
|
241
|
-
// We log after validation (we've confirmed the shape is sound) and before
|
|
242
|
-
// the adapter call so the record is written even if the close fails.
|
|
243
|
-
const reason = args.reason;
|
|
244
|
-
const summary = formatAssessmentSummary(args.assessment);
|
|
245
|
-
logger.info(TAG, `close_position ${args.symbol} reason=${reason}${summary ? ' | ' + summary : ''}`);
|
|
246
|
-
// Circuit-breaker: if we've already let 2 bracket_integrity closes through
|
|
247
|
-
// in the last hour, the 3rd is almost certainly the audit lying to us
|
|
248
|
-
// rather than a real protection failure. Force the operator to either ack
|
|
249
|
-
// by retrying with a different reason (regime_flip / risk_limit /
|
|
250
|
-
// operator_command) or investigate the bracket subsystem.
|
|
251
|
-
if (reason === 'bracket_integrity' && deps.adapter.isLive) {
|
|
252
|
-
const now = Date.now();
|
|
253
|
-
const windowStart = now - BRACKET_INTEGRITY_WINDOW_MS;
|
|
254
|
-
bracketIntegrityCloses = bracketIntegrityCloses.filter(ts => ts >= windowStart);
|
|
255
|
-
if (bracketIntegrityCloses.length >= BRACKET_INTEGRITY_LIMIT - 1) {
|
|
256
|
-
logger.warn(TAG, `BRACKET-INTEGRITY CIRCUIT-BREAKER TRIPPED for ${args.symbol}: ` +
|
|
257
|
-
`${bracketIntegrityCloses.length} prior bracket_integrity closes in the last ` +
|
|
258
|
-
`${BRACKET_INTEGRITY_WINDOW_MS / 60_000} min. Refusing the ${bracketIntegrityCloses.length + 1}th. ` +
|
|
259
|
-
`Audit-vs-reality bug is likelier than ${bracketIntegrityCloses.length + 1} consecutive real protection losses.`);
|
|
260
|
-
return {
|
|
261
|
-
error: `close_position rejected: circuit-breaker tripped — ` +
|
|
262
|
-
`${bracketIntegrityCloses.length} bracket_integrity closes already fired in the last ` +
|
|
263
|
-
`${BRACKET_INTEGRITY_WINDOW_MS / 60_000} min. This pattern almost always means the audit ` +
|
|
264
|
-
`is unreliable, not that brackets are repeatedly failing on the exchange. ` +
|
|
265
|
-
`Investigation steps: (1) run audit_bracket_protection and inspect 'reason' + ` +
|
|
266
|
-
`ledger_state; (2) check the journal for 'AUDIT FLICKER' warnings; ` +
|
|
267
|
-
`(3) if you truly need to exit, use reason='operator_command' (bypasses this check) ` +
|
|
268
|
-
`or escalate to the operator.`,
|
|
269
|
-
};
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
// False-bracket_integrity safeguard — see module header comment.
|
|
273
|
-
if (reason === 'bracket_integrity' && deps.adapter.isLive) {
|
|
274
|
-
const integrity = await verifyBracketsGenuinelyMissing(deps.adapter, args.symbol);
|
|
275
|
-
if (integrity.protected) {
|
|
276
|
-
logger.warn(TAG, `close_position REJECTED — reason=bracket_integrity but plugin verified brackets live: ${integrity.detail} (symbol=${args.symbol}). This is the audit-vs-reality bug; the position is protected. If you want to close anyway, use reason=regime_flip, risk_limit, or operator_command.`);
|
|
277
|
-
return {
|
|
278
|
-
error: `close_position rejected: bracket_integrity claim contradicted by plugin (${integrity.detail}). ` +
|
|
279
|
-
`Brackets are live on exchange. Use a different reason if you want to exit.`,
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
logger.info(TAG, `bracket_integrity safeguard: ${integrity.detail} — allowing close`);
|
|
283
|
-
}
|
|
284
|
-
try {
|
|
285
|
-
const close = async () => {
|
|
286
|
-
if (!wave9ExitClaimed && !deps.adapter.isLive && reason !== 'operator_command') {
|
|
287
|
-
deps.refreshPaperState?.();
|
|
288
|
-
const positions = await deps.adapter.getPositionsOrNull();
|
|
289
|
-
if (positions === null) {
|
|
290
|
-
// Preserve the existing risk-reduction contract: the extra
|
|
291
|
-
// classification read cannot trap an ordinary close.
|
|
292
|
-
logger.warn(TAG, 'Wave 9 final close classification unavailable; proceeding risk-reducing fail-open.');
|
|
293
|
-
}
|
|
294
|
-
else {
|
|
295
|
-
const canonical = (value) => value.toUpperCase().replace(/[^A-Z0-9]/g, '').replace(/USDTUSDT$/, 'USDT');
|
|
296
|
-
const target = positions.find((position) => canonical(position.symbol) === canonical(args.symbol));
|
|
297
|
-
if (target && isWave9ManagedPosition(target)) {
|
|
298
|
-
throw new Error(`Generic close_position refused at mutation boundary: ${args.symbol} is now held by Wave 9.`);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
if (!wave9ExitClaimed
|
|
303
|
-
&& deps.adapter.isLive
|
|
304
|
-
&& reason !== 'operator_command'
|
|
305
|
-
&& deps.checkWave9LiveSymbolOwnership) {
|
|
306
|
-
let ownership;
|
|
307
|
-
try {
|
|
308
|
-
ownership = await deps.checkWave9LiveSymbolOwnership(args.symbol);
|
|
309
|
-
}
|
|
310
|
-
catch (err) {
|
|
311
|
-
throw new Error(`Generic close_position refused at mutation boundary: Wave 9 LIVE ownership ` +
|
|
312
|
-
`check failed for ${args.symbol} (${formatError(err)}).`);
|
|
313
|
-
}
|
|
314
|
-
if (ownership.status === 'owned' || ownership.status === 'ambiguous') {
|
|
315
|
-
throw new Error(`Generic close_position refused at mutation boundary: ${args.symbol} has ` +
|
|
316
|
-
`${ownership.status} Wave 9 LIVE ownership (${ownership.reason}). ` +
|
|
317
|
-
'Use get_wave9_status for a reversal authorization or operator_command for an emergency close.');
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
return wave9ExitClaimed
|
|
321
|
-
? deps.adapter.closePosition(args.symbol, 'wave9_signal_reversal')
|
|
322
|
-
: deps.adapter.closePosition(args.symbol);
|
|
323
|
-
};
|
|
324
|
-
const closeWave9 = async () => {
|
|
325
|
-
if (!wave9Lease)
|
|
326
|
-
throw new Error('Wave 9 exit lease is unavailable at mutation boundary.');
|
|
327
|
-
if (currentWave9ExecutionMode(deps) !== initialWave9Mode) {
|
|
328
|
-
deps.wave9AdmissionGuard.abort(wave9Lease, 'trading_mode_changed_before_exit_mutation', { retryable: true });
|
|
329
|
-
wave9Lease = undefined;
|
|
330
|
-
throw new Error('Wave 9 reversal close refused: adapter or trading mode changed before mutation.');
|
|
331
|
-
}
|
|
332
|
-
if (deps.wave9VenueCheck?.() !== 'binance') {
|
|
333
|
-
deps.wave9AdmissionGuard.abort(wave9Lease, 'execution_venue_changed_before_exit_mutation', { retryable: true });
|
|
334
|
-
wave9Lease = undefined;
|
|
335
|
-
throw new Error('Wave 9 reversal close refused: execution venue changed away from Binance before mutation.');
|
|
336
|
-
}
|
|
337
|
-
let currentFingerprint;
|
|
338
|
-
if (initialWave9Mode === 'LIVE') {
|
|
339
|
-
const capture = await deps.captureWave9PositionFingerprint(args.symbol);
|
|
340
|
-
if (!isWave9ManagedPosition(capture.position)
|
|
341
|
-
|| capture.position.candidateId !== args.candidate_id
|
|
342
|
-
|| !capture.position.missionId) {
|
|
343
|
-
throw new Error('held live position no longer matches its exact Wave 9 identity');
|
|
344
|
-
}
|
|
345
|
-
currentFingerprint = capture.fingerprint;
|
|
346
|
-
}
|
|
347
|
-
else {
|
|
348
|
-
deps.refreshPaperState?.();
|
|
349
|
-
currentFingerprint = captureWave9PaperPositionFingerprint(deps.adapter, args.symbol).fingerprint;
|
|
350
|
-
}
|
|
351
|
-
deps.wave9AdmissionGuard.revalidate(wave9Lease, currentFingerprint);
|
|
352
|
-
let order;
|
|
353
|
-
let closeError;
|
|
354
|
-
try {
|
|
355
|
-
order = await close();
|
|
356
|
-
}
|
|
357
|
-
catch (err) {
|
|
358
|
-
if (initialWave9Mode !== 'LIVE')
|
|
359
|
-
throw err;
|
|
360
|
-
closeError = formatError(err);
|
|
361
|
-
}
|
|
362
|
-
if (initialWave9Mode === 'LIVE') {
|
|
363
|
-
const flat = await confirmWave9LivePositionFlat(deps.adapter, args.symbol);
|
|
364
|
-
if (!flat.confirmed) {
|
|
365
|
-
let protection;
|
|
366
|
-
try {
|
|
367
|
-
protection = await (deps.reprotectWave9LiveResidual ?? reprotectWave9LiveResidual)(deps.adapter, deps.wave9LiveLedger, args.candidate_id, args.symbol);
|
|
368
|
-
}
|
|
369
|
-
catch (err) {
|
|
370
|
-
deps.wave9AdmissionGuard.abort(wave9Lease, `live_close_residual_reprotection_threw:${formatError(err)}`, { retryable: true });
|
|
371
|
-
wave9Lease = undefined;
|
|
372
|
-
throw new Error(`CRITICAL: Wave 9 LIVE reversal is not stably flat (${flat.detail}), and residual ` +
|
|
373
|
-
`re-protection threw (${formatError(err)}). Durable ownership remains OPEN. ` +
|
|
374
|
-
'IMMEDIATE MANUAL INTERVENTION REQUIRED; a fresh exit authorization may retry.');
|
|
375
|
-
}
|
|
376
|
-
if (protection.status === 'protected') {
|
|
377
|
-
deps.wave9AdmissionGuard.abort(wave9Lease, `live_close_residual_reprotected:${protection.stopClientOrderId ?? 'exact_stop'}`, { retryable: true });
|
|
378
|
-
wave9Lease = undefined;
|
|
379
|
-
throw new Error(`Wave 9 LIVE reversal close${closeError ? ` threw (${closeError}) and` : ''} left ` +
|
|
380
|
-
`${protection.residualQuantity ?? 'a'} residual ` +
|
|
381
|
-
`contract position. Durable ownership remains OPEN and the exact frozen stop ` +
|
|
382
|
-
`${protection.stopPrice} is proven live; refresh get_wave9_status and use the ` +
|
|
383
|
-
'fresh exit authorization to retry the reduce-only close.');
|
|
384
|
-
}
|
|
385
|
-
deps.wave9AdmissionGuard.abort(wave9Lease, `live_close_residual_requires_manual_intervention:${protection.detail}`, { retryable: true });
|
|
386
|
-
wave9Lease = undefined;
|
|
387
|
-
throw new Error(`CRITICAL: Wave 9 LIVE reversal close${closeError ? ` threw (${closeError}) and` : ''} ` +
|
|
388
|
-
`stable flat was not confirmed ` +
|
|
389
|
-
`(${flat.detail}). Durable ownership remains OPEN. ${protection.detail}`);
|
|
390
|
-
}
|
|
391
|
-
await deps.wave9LiveLedger.markClosed(args.candidate_id);
|
|
392
|
-
}
|
|
393
|
-
deps.wave9AdmissionGuard.commit(wave9Lease);
|
|
394
|
-
wave9Lease = undefined;
|
|
395
|
-
if (closeError) {
|
|
396
|
-
throw new Error(`Wave 9 LIVE reversal close acknowledgement failed (${closeError}), but stable flat was ` +
|
|
397
|
-
'proven and durable ownership is CLOSED. Do not retry this candidate.');
|
|
398
|
-
}
|
|
399
|
-
return order;
|
|
400
|
-
};
|
|
401
|
-
const order = wave9ExitClaimed
|
|
402
|
-
? await deps.operationLock.withAccountLock(`wave9-close-final:${args.symbol}`, closeWave9)
|
|
403
|
-
: reason !== 'operator_command' && deps.operationLock
|
|
404
|
-
? await deps.operationLock.withAccountLock(`generic-close-final:${args.symbol}`, close)
|
|
405
|
-
: await close();
|
|
406
|
-
// Successful close — record the bracket_integrity timestamp so the
|
|
407
|
-
// circuit-breaker can see the trend on the next attempt.
|
|
408
|
-
if (reason === 'bracket_integrity' && deps.adapter.isLive) {
|
|
409
|
-
bracketIntegrityCloses.push(Date.now());
|
|
410
|
-
}
|
|
411
|
-
// Auto-capture close to the Position Decision Journal — fail-open.
|
|
412
|
-
if (deps.autoCapture) {
|
|
413
|
-
const a = args.assessment;
|
|
414
|
-
const assessmentForCapture = {
|
|
415
|
-
...a ?? {},
|
|
416
|
-
};
|
|
417
|
-
if (gateVerdict) {
|
|
418
|
-
// 0a: persist the full inputs snapshot + would_have_blocked so shadow
|
|
419
|
-
// verdicts are auditable from the journal (EXIT_GATE_DESIGN.md §5).
|
|
420
|
-
// Keys are snake_case per the canonical-JSONB-key rule; every input is
|
|
421
|
-
// null-coalesced so a MISSING input is recorded explicitly (that is the
|
|
422
|
-
// point — it makes the inputs_unavailable_* skips diagnosable). The key
|
|
423
|
-
// stays `outcome` (not §5's older `verdict`) to match the 148 historical
|
|
424
|
-
// rows. `gateInputs` is non-null whenever `gateVerdict` is set (both are
|
|
425
|
-
// assigned together when gateMode!=='off'); `gi` guard is for the type.
|
|
426
|
-
const gi = gateInputs;
|
|
427
|
-
const stopAtBE = gi && gi.side && typeof gi.stopPrice === 'number' && typeof gi.entryPrice === 'number'
|
|
428
|
-
? gi.side === 'long'
|
|
429
|
-
? gi.stopPrice >= gi.entryPrice
|
|
430
|
-
: gi.stopPrice <= gi.entryPrice
|
|
431
|
-
: null;
|
|
432
|
-
assessmentForCapture.metadata = {
|
|
433
|
-
...assessmentForCapture.metadata ?? {},
|
|
434
|
-
gate_eval: {
|
|
435
|
-
mode: gateMode,
|
|
436
|
-
outcome: gateVerdict.outcome,
|
|
437
|
-
tier: gateVerdict.tier,
|
|
438
|
-
code: gateVerdict.code,
|
|
439
|
-
would_have_blocked: gateVerdict.outcome === 'BLOCK',
|
|
440
|
-
...(gateVerdict.discipline_failure
|
|
441
|
-
? { discipline_failure: gateVerdict.discipline_failure }
|
|
442
|
-
: {}),
|
|
443
|
-
...(gi
|
|
444
|
-
? {
|
|
445
|
-
inputs: {
|
|
446
|
-
mfe_r_peak: gi.mfe_r_peak ?? null,
|
|
447
|
-
current_r: gi.current_r ?? null,
|
|
448
|
-
stop_at_BE: stopAtBE,
|
|
449
|
-
last_review_verdict: gi.lastReview?.verdict ?? null,
|
|
450
|
-
last_review_age_minutes: gi.lastReview
|
|
451
|
-
? Math.round((gi.now_ms - gi.lastReview.review_at_ms) / 6000) / 10
|
|
452
|
-
: null,
|
|
453
|
-
thesis_status: gi.lastReview?.thesis_status ?? null,
|
|
454
|
-
// vol_shock is never computed by buildExitGateInputs yet, so
|
|
455
|
-
// this is always false until the 3xATR shock is wired — do
|
|
456
|
-
// NOT read it as a real signal during the soak.
|
|
457
|
-
vol_shock: gi.volShock ?? false,
|
|
458
|
-
// Provenance (set in buildExitGateInputs): which source
|
|
459
|
-
// supplied each value — makes the inputs_unavailable_* and
|
|
460
|
-
// computed-fallback paths diagnosable from the journal.
|
|
461
|
-
mfe_src: gi.mfe_src ?? null,
|
|
462
|
-
current_r_src: gi.current_r_src ?? null,
|
|
463
|
-
},
|
|
464
|
-
}
|
|
465
|
-
: {}),
|
|
466
|
-
},
|
|
467
|
-
};
|
|
468
|
-
}
|
|
469
|
-
// Forensics: snapshot the audit verdict history (last 60min, up to
|
|
470
|
-
// 120 samples) so the dashboard Position Timeline drawer can flag
|
|
471
|
-
// closes that look like audit-flicker artefacts rather than real
|
|
472
|
-
// market exits. The flicker-warn line in journal logs the same data
|
|
473
|
-
// in real time; this lets us audit historical closes after the fact.
|
|
474
|
-
// 2026-05-15 spiral root-cause work, item #8 of the bundle.
|
|
475
|
-
if (deps.adapter.isLive) {
|
|
476
|
-
const history = getRecentAuditVerdictHistory(args.symbol);
|
|
477
|
-
if (history.length > 0) {
|
|
478
|
-
assessmentForCapture.metadata = {
|
|
479
|
-
...assessmentForCapture.metadata ?? {},
|
|
480
|
-
bracket_health_history: history,
|
|
481
|
-
};
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
onClosePositionFilled(deps.autoCapture, {
|
|
485
|
-
symbol: args.symbol,
|
|
486
|
-
closeReason: reason,
|
|
487
|
-
closeAssessment: assessmentForCapture,
|
|
488
|
-
scorecardVerdict: typeof a?.current_score === 'number' ? undefined : undefined,
|
|
489
|
-
confluenceScore: typeof a?.current_score === 'number' ? a.current_score : undefined,
|
|
490
|
-
regime: a?.current_regime,
|
|
491
|
-
regimeConfidence: undefined,
|
|
492
|
-
}, order).catch((err) => {
|
|
493
|
-
// eslint-disable-next-line no-console
|
|
494
|
-
console.warn(`[position-auto-capture] close capture threw: ${formatError(err)}`);
|
|
495
|
-
});
|
|
496
|
-
}
|
|
497
|
-
return order;
|
|
498
|
-
}
|
|
499
|
-
catch (err) {
|
|
500
|
-
if (wave9Lease) {
|
|
501
|
-
deps.wave9AdmissionGuard.abort(wave9Lease, `exit_execution_failed:${formatError(err)}`, { retryable: initialWave9Mode === 'LIVE' });
|
|
502
|
-
wave9Lease = undefined;
|
|
503
|
-
}
|
|
504
|
-
return { error: formatError(err) };
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
/** Independent check used by the bracket_integrity safeguard. Looks at the
|
|
508
|
-
* plugin's bracket ledger + a fresh exchange-side open-orders fetch; returns
|
|
509
|
-
* `{protected: true}` only when BOTH confirm a live bracket (ledger row in a
|
|
510
|
-
* non-terminal state with stored cids, AND at least one exchange order
|
|
511
|
-
* carrying a matching `rc-<bracketId>-s` or `rc-<bracketId>-t` cid). Any
|
|
512
|
-
* uncertainty (no ledger row, cids not stored, fetch error, nothing on
|
|
513
|
-
* exchange) returns `{protected: false}` so the close is allowed — we only
|
|
514
|
-
* block when we can definitively prove the audit was wrong. */
|
|
515
|
-
async function verifyBracketsGenuinelyMissing(adapter, symbol) {
|
|
516
|
-
const ledger = adapter.getBracketLedger?.();
|
|
517
|
-
if (!ledger)
|
|
518
|
-
return { protected: false, detail: 'brackets disabled' };
|
|
519
|
-
const row = ledger.getBySymbol(symbol);
|
|
520
|
-
if (!row)
|
|
521
|
-
return { protected: false, detail: 'no ledger row' };
|
|
522
|
-
const NON_TERMINAL = new Set(['pending_entry', 'attaching', 'active', 'partial']);
|
|
523
|
-
if (!NON_TERMINAL.has(row.state)) {
|
|
524
|
-
return { protected: false, detail: `ledger state=${row.state} (terminal)` };
|
|
525
|
-
}
|
|
526
|
-
if (!row.slCid && !row.tpCid) {
|
|
527
|
-
return { protected: false, detail: `ledger state=${row.state} but no cids stored` };
|
|
528
|
-
}
|
|
529
|
-
let open = [];
|
|
530
|
-
try {
|
|
531
|
-
open = await adapter.getOpenOrders(symbol);
|
|
532
|
-
}
|
|
533
|
-
catch (err) {
|
|
534
|
-
return { protected: false, detail: `getOpenOrders failed: ${formatError(err)}` };
|
|
535
|
-
}
|
|
536
|
-
const liveCids = new Set();
|
|
537
|
-
for (const o of open) {
|
|
538
|
-
if (o.clientOrderId)
|
|
539
|
-
liveCids.add(o.clientOrderId);
|
|
540
|
-
}
|
|
541
|
-
const slLive = Boolean(row.slCid && liveCids.has(row.slCid));
|
|
542
|
-
const tpLive = Boolean(row.tpCid && liveCids.has(row.tpCid));
|
|
543
|
-
// Block the close only when BOTH bracket legs are live — that's the only
|
|
544
|
-
// shape that proves the audit was definitively wrong (the original 2026-04-21
|
|
545
|
-
// symbol-mapping bug). A position with only one leg live is half-bracketed:
|
|
546
|
-
// the audit's `has_stop=false` (or `has_target=false`) is correct, the
|
|
547
|
-
// operator/agent needs to flatten or re-attach, and the safeguard would
|
|
548
|
-
// wrongly trap them. Per the docstring: only block when we can prove the
|
|
549
|
-
// audit was wrong; one-leg-live does not prove that.
|
|
550
|
-
if (slLive && tpLive) {
|
|
551
|
-
return {
|
|
552
|
-
protected: true,
|
|
553
|
-
detail: `ledger state=${row.state}, exchange has SL(${row.slCid}) + TP(${row.tpCid}) open (${open.length} total orders on ${symbol})`,
|
|
554
|
-
};
|
|
555
|
-
}
|
|
556
|
-
const observed = [];
|
|
557
|
-
if (slLive)
|
|
558
|
-
observed.push(`SL(${row.slCid}) only`);
|
|
559
|
-
if (tpLive)
|
|
560
|
-
observed.push(`TP(${row.tpCid}) only`);
|
|
561
|
-
if (observed.length === 0)
|
|
562
|
-
observed.push('neither cid on exchange');
|
|
563
|
-
return {
|
|
564
|
-
protected: false,
|
|
565
|
-
detail: `ledger state=${row.state} (slCid=${row.slCid ?? '-'}, tpCid=${row.tpCid ?? '-'}) — ${observed.join(', ')} (${open.length} orders)`,
|
|
566
|
-
};
|
|
567
|
-
}
|
|
568
|
-
/** Gather inputs for the exit gate from adapter + bracket ledger + state store.
|
|
569
|
-
* Best-effort: any missing piece becomes `undefined` so the pure gate function
|
|
570
|
-
* can decide whether to PASS('skipped') or proceed. Never throws — gate
|
|
571
|
-
* evaluation must never crash close_position.
|
|
572
|
-
*/
|
|
573
|
-
async function buildExitGateInputs(args, deps) {
|
|
574
|
-
const reason = (args.reason ?? 'regime_flip');
|
|
575
|
-
const a = args.assessment;
|
|
576
|
-
const inputs = {
|
|
577
|
-
reason,
|
|
578
|
-
now_ms: Date.now(),
|
|
579
|
-
mfe_r_peak: typeof a?.mfe_r_peak === 'number' ? a.mfe_r_peak : undefined,
|
|
580
|
-
current_r: typeof a?.r_multiple_at_close === 'number' ? a.r_multiple_at_close : undefined,
|
|
581
|
-
};
|
|
582
|
-
// Provenance: agent-supplied values win (set the src tags now); the adapter
|
|
583
|
-
// and computed fallbacks below only fire when these stay undefined.
|
|
584
|
-
if (inputs.mfe_r_peak !== undefined)
|
|
585
|
-
inputs.mfe_src = 'assessment';
|
|
586
|
-
if (inputs.current_r !== undefined)
|
|
587
|
-
inputs.current_r_src = 'assessment';
|
|
588
|
-
// Bracket ledger — stop price + (canonical) ledger entry.
|
|
589
|
-
// Only LiveAdapter exposes getBracketLedger; paper adapter falls back.
|
|
590
|
-
try {
|
|
591
|
-
const ledger = deps.adapter.getBracketLedger?.();
|
|
592
|
-
if (ledger) {
|
|
593
|
-
const row = ledger.getBySymbol(args.symbol);
|
|
594
|
-
if (row) {
|
|
595
|
-
if (typeof row.stopPrice === 'number' && Number.isFinite(row.stopPrice)) {
|
|
596
|
-
inputs.stopPrice = row.stopPrice;
|
|
597
|
-
}
|
|
598
|
-
if (row.entrySide === 'buy')
|
|
599
|
-
inputs.side = 'long';
|
|
600
|
-
else if (row.entrySide === 'sell')
|
|
601
|
-
inputs.side = 'short';
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
catch (err) {
|
|
606
|
-
logger.warn(TAG, `exit_gate input fetch (bracket ledger): ${formatError(err)}`);
|
|
607
|
-
}
|
|
608
|
-
// Position — for entryPrice + side fallback, plus mfeR + bracket fallbacks.
|
|
609
|
-
// LiveAdapter.getPositions decorates each row with a running mfeR (updated
|
|
610
|
-
// from mark price on every call) and a bracket snapshot. When the agent
|
|
611
|
-
// omits `assessment.mfe_r_peak` (observed on ~77% of closes during the
|
|
612
|
-
// 2026-05-14 shadow soak), we read mfeR from the adapter so the gate can
|
|
613
|
-
// still tier the close instead of returning inputs_unavailable_mfe.
|
|
614
|
-
try {
|
|
615
|
-
const positions = await deps.adapter.getPositions(args.symbol);
|
|
616
|
-
const pos = positions.find((p) => p.contracts && p.contracts > 0);
|
|
617
|
-
if (pos) {
|
|
618
|
-
if (typeof pos.entryPrice === 'number' && Number.isFinite(pos.entryPrice)) {
|
|
619
|
-
inputs.entryPrice = pos.entryPrice;
|
|
620
|
-
}
|
|
621
|
-
if (!inputs.side && pos.side === 'long')
|
|
622
|
-
inputs.side = 'long';
|
|
623
|
-
if (!inputs.side && pos.side === 'short')
|
|
624
|
-
inputs.side = 'short';
|
|
625
|
-
if (inputs.mfe_r_peak === undefined
|
|
626
|
-
&& typeof pos.mfeR === 'number'
|
|
627
|
-
&& Number.isFinite(pos.mfeR)) {
|
|
628
|
-
inputs.mfe_r_peak = pos.mfeR;
|
|
629
|
-
inputs.mfe_src = 'pos.mfeR';
|
|
630
|
-
}
|
|
631
|
-
if (inputs.stopPrice === undefined
|
|
632
|
-
&& pos.bracket
|
|
633
|
-
&& typeof pos.bracket.slPrice === 'number'
|
|
634
|
-
&& Number.isFinite(pos.bracket.slPrice)) {
|
|
635
|
-
inputs.stopPrice = pos.bracket.slPrice;
|
|
636
|
-
}
|
|
637
|
-
// 0b: plugin-computed fallbacks for current_r (SIGNED) + an mfe peak-FLOOR
|
|
638
|
-
// when the agent AND the adapter both left them undefined — the
|
|
639
|
-
// inputs_unavailable_* skips (~16-30% of evals). R denominator is the
|
|
640
|
-
// frozen entry→stop distance (originalStopPrice preferred; else the bracket
|
|
641
|
-
// stop resolved above). Both gated on `=== undefined` so agent-supplied
|
|
642
|
-
// values still win. current_r MUST stay signed (the T1-escape check
|
|
643
|
-
// compares current_r <= -0.5R); the mfe value is a NON-NEGATIVE FLOOR (true
|
|
644
|
-
// peak >= current excursion) — it lets the gate tier the close instead of
|
|
645
|
-
// skipping, at the cost of under-classifying a round-tripped winner as T1
|
|
646
|
-
// (acceptable: errs toward BLOCK in enforce). A position with no frozen
|
|
647
|
-
// stop (no originalStopPrice, no bracket) still legitimately skips.
|
|
648
|
-
// See docs/EXIT_DISCIPLINE_BUILD_PLAN.md Step 0b.
|
|
649
|
-
const denomStop = typeof pos.originalStopPrice === 'number' && Number.isFinite(pos.originalStopPrice)
|
|
650
|
-
? pos.originalStopPrice
|
|
651
|
-
: inputs.stopPrice;
|
|
652
|
-
if (inputs.side
|
|
653
|
-
&& typeof pos.entryPrice === 'number' && Number.isFinite(pos.entryPrice)
|
|
654
|
-
&& typeof pos.markPrice === 'number' && Number.isFinite(pos.markPrice)
|
|
655
|
-
&& typeof denomStop === 'number' && Number.isFinite(denomStop)) {
|
|
656
|
-
const denom = Math.abs(pos.entryPrice - denomStop);
|
|
657
|
-
if (denom > 0) {
|
|
658
|
-
const fav = inputs.side === 'long'
|
|
659
|
-
? pos.markPrice - pos.entryPrice
|
|
660
|
-
: pos.entryPrice - pos.markPrice;
|
|
661
|
-
if (inputs.current_r === undefined) {
|
|
662
|
-
inputs.current_r = fav / denom; // signed
|
|
663
|
-
inputs.current_r_src = 'computed';
|
|
664
|
-
}
|
|
665
|
-
if (inputs.mfe_r_peak === undefined) {
|
|
666
|
-
inputs.mfe_r_peak = Math.max(0, fav / denom); // non-negative floor
|
|
667
|
-
inputs.mfe_src = 'computed_floor';
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
catch (err) {
|
|
674
|
-
logger.warn(TAG, `exit_gate input fetch (positions): ${formatError(err)}`);
|
|
675
|
-
}
|
|
676
|
-
// Last review — from state store, for contradicts-own-review + review override.
|
|
677
|
-
try {
|
|
678
|
-
const entry = deps.autoCapture?.stateStore?.get(args.symbol);
|
|
679
|
-
if (entry?.lastVerdict && typeof entry.lastReviewAt === 'number') {
|
|
680
|
-
inputs.lastReview = {
|
|
681
|
-
verdict: entry.lastVerdict,
|
|
682
|
-
thesis_status: entry.lastThesisStatus ?? 'intact',
|
|
683
|
-
review_at_ms: entry.lastReviewAt,
|
|
684
|
-
};
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
catch (err) {
|
|
688
|
-
logger.warn(TAG, `exit_gate input fetch (state store): ${formatError(err)}`);
|
|
689
|
-
}
|
|
690
|
-
return inputs;
|
|
691
|
-
}
|
|
692
|
-
/** Test seam — clears the circuit-breaker state between unit tests. */
|
|
693
|
-
export const __testing__ = {
|
|
694
|
-
resetCircuitBreaker() {
|
|
695
|
-
bracketIntegrityCloses = [];
|
|
696
|
-
},
|
|
697
|
-
/** Inspect current circuit-breaker state — for assertions. */
|
|
698
|
-
getCircuitBreakerCount() {
|
|
699
|
-
const windowStart = Date.now() - BRACKET_INTEGRITY_WINDOW_MS;
|
|
700
|
-
return bracketIntegrityCloses.filter(ts => ts >= windowStart).length;
|
|
701
|
-
},
|
|
702
|
-
};
|
|
703
|
-
function formatAssessmentSummary(a) {
|
|
704
|
-
if (!a)
|
|
705
|
-
return '';
|
|
706
|
-
const parts = [];
|
|
707
|
-
if (typeof a.entry_score === 'number')
|
|
708
|
-
parts.push(`entry=${a.entry_score}`);
|
|
709
|
-
if (typeof a.current_score === 'number')
|
|
710
|
-
parts.push(`current=${a.current_score}`);
|
|
711
|
-
if (a.entry_regime)
|
|
712
|
-
parts.push(`er=${a.entry_regime}`);
|
|
713
|
-
if (a.current_regime)
|
|
714
|
-
parts.push(`cr=${a.current_regime}`);
|
|
715
|
-
if (a.contradicting_metric)
|
|
716
|
-
parts.push(`metric="${a.contradicting_metric.slice(0, 80)}"`);
|
|
717
|
-
if (typeof a.position_age_seconds === 'number')
|
|
718
|
-
parts.push(`age=${a.position_age_seconds}s`);
|
|
719
|
-
if (typeof a.r_multiple_at_close === 'number')
|
|
720
|
-
parts.push(`R=${a.r_multiple_at_close}`);
|
|
721
|
-
return parts.join(' ');
|
|
722
|
-
}
|