@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
|
@@ -170,8 +170,13 @@ export interface ParsedEvent<E extends ProviderEventName = ProviderEventName> {
|
|
|
170
170
|
export declare class EventParser {
|
|
171
171
|
/** Buffered assistant text per runId, with timestamps for expiry */
|
|
172
172
|
private assistantBuffers;
|
|
173
|
-
/** Last decision timestamp (set on lifecycle '
|
|
173
|
+
/** Last decision timestamp (set on lifecycle 'end' of a non-errored run) */
|
|
174
174
|
private lastDecisionTs;
|
|
175
|
+
/** Runs that emitted a lifecycle 'error' — their 'end' must NOT count as a
|
|
176
|
+
* decision. Issue #194: bumping on 'start' kept "last decision" fresh
|
|
177
|
+
* through an 18h all-models-failed outage, so the dashboard's 2×-interval
|
|
178
|
+
* "unresponsive" rung could never fire. Bounded (oldest evicted). */
|
|
179
|
+
private erroredRuns;
|
|
175
180
|
/** Error timestamps within the rolling window */
|
|
176
181
|
private errorTimestamps;
|
|
177
182
|
/** Symbol for balance currency extraction */
|
|
@@ -417,8 +417,13 @@ const BUFFER_INACTIVITY_MS = 120_000; // 120 seconds — matches webapp streamin
|
|
|
417
417
|
export class EventParser {
|
|
418
418
|
/** Buffered assistant text per runId, with timestamps for expiry */
|
|
419
419
|
assistantBuffers = new Map();
|
|
420
|
-
/** Last decision timestamp (set on lifecycle '
|
|
420
|
+
/** Last decision timestamp (set on lifecycle 'end' of a non-errored run) */
|
|
421
421
|
lastDecisionTs = null;
|
|
422
|
+
/** Runs that emitted a lifecycle 'error' — their 'end' must NOT count as a
|
|
423
|
+
* decision. Issue #194: bumping on 'start' kept "last decision" fresh
|
|
424
|
+
* through an 18h all-models-failed outage, so the dashboard's 2×-interval
|
|
425
|
+
* "unresponsive" rung could never fire. Bounded (oldest evicted). */
|
|
426
|
+
erroredRuns = new Set();
|
|
422
427
|
/** Error timestamps within the rolling window */
|
|
423
428
|
errorTimestamps = [];
|
|
424
429
|
/** Symbol for balance currency extraction */
|
|
@@ -465,10 +470,15 @@ export class EventParser {
|
|
|
465
470
|
}
|
|
466
471
|
switch (phase) {
|
|
467
472
|
case 'start':
|
|
468
|
-
this.lastDecisionTs = new Date().toISOString();
|
|
469
473
|
logger.debug(TAG, `Agent turn started: ${runId}`);
|
|
470
474
|
return [];
|
|
471
475
|
case 'end': {
|
|
476
|
+
// A decision = a turn that ENDED without erroring. Bumping on 'start'
|
|
477
|
+
// (pre-#194) kept the timestamp fresh while every run failed, hiding
|
|
478
|
+
// an all-models-failed outage from the unresponsive heuristics.
|
|
479
|
+
if (!this.erroredRuns.delete(runId)) {
|
|
480
|
+
this.lastDecisionTs = new Date().toISOString();
|
|
481
|
+
}
|
|
472
482
|
logger.debug(TAG, `Agent turn ended: ${runId}`);
|
|
473
483
|
return this.flushAssistantBuffer(runId);
|
|
474
484
|
}
|
|
@@ -476,6 +486,13 @@ export class EventParser {
|
|
|
476
486
|
const errMsg = data.error ?? 'Unknown agent error';
|
|
477
487
|
logger.warn(TAG, `Agent error (run ${runId}): ${errMsg}`);
|
|
478
488
|
this.errorTimestamps.push(Date.now());
|
|
489
|
+
this.erroredRuns.add(runId);
|
|
490
|
+
// Bound the set: an errored run whose 'end' never arrives would leak.
|
|
491
|
+
if (this.erroredRuns.size > 100) {
|
|
492
|
+
const oldest = this.erroredRuns.values().next().value;
|
|
493
|
+
if (oldest !== undefined)
|
|
494
|
+
this.erroredRuns.delete(oldest);
|
|
495
|
+
}
|
|
479
496
|
// Still flush the buffer — partial responses are better than nothing
|
|
480
497
|
return this.flushAssistantBuffer(runId);
|
|
481
498
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export declare const HEARTBEAT_CRON_NAME = "reefclaw-heartbeat";
|
|
2
|
+
export declare const HEARTBEAT_EVERY_MS: number;
|
|
3
|
+
export declare const HEARTBEAT_MESSAGE: string;
|
|
4
|
+
export interface CronRpcClient {
|
|
5
|
+
sendRpc(method: string, params?: Record<string, unknown>): Promise<unknown>;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Whether an existing cron job counts as "the heartbeat already exists".
|
|
9
|
+
* Union of the two matchers already in the codebase: the old setup path
|
|
10
|
+
* matched /reefclaw/, while resolveHeartbeatSeconds() (the cadence reader that
|
|
11
|
+
* drives the dashboard header) matches /heart\s*beat/. A job satisfying either
|
|
12
|
+
* must suppress creation — prod/wisekid boxes carry heartbeat jobs whose names
|
|
13
|
+
* predate the reefclaw- prefix, and a duplicate 15m heartbeat would double the
|
|
14
|
+
* agent's token burn.
|
|
15
|
+
*/
|
|
16
|
+
export declare function isHeartbeatLikeName(name: unknown): boolean;
|
|
17
|
+
export type EnsureHeartbeatOutcome = 'already_ensured' | 'found_existing' | 'created' | 'failed';
|
|
18
|
+
/**
|
|
19
|
+
* Ensure a heartbeat cron exists. Non-fatal by contract: every failure path
|
|
20
|
+
* returns 'failed' rather than throwing, and only success writes the marker so
|
|
21
|
+
* a transient gateway error retries on the next boot.
|
|
22
|
+
*/
|
|
23
|
+
export declare function ensureHeartbeatCron(opts: {
|
|
24
|
+
rpc: CronRpcClient;
|
|
25
|
+
markerPath: string;
|
|
26
|
+
log: (msg: string) => void;
|
|
27
|
+
}): Promise<EnsureHeartbeatOutcome>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Ensures the ReefClaw heartbeat cron job exists — once per install — via
|
|
2
|
+
// gateway RPC (`cron.list` / `cron.add`).
|
|
3
|
+
//
|
|
4
|
+
// This replaces the old setup-time shell-out to the openclaw CLI. The CLI's
|
|
5
|
+
// cron commands are themselves gateway RPC clients, so shelling out bought
|
|
6
|
+
// nothing except a subprocess + PATH dependency — and it ran at
|
|
7
|
+
// setup time, when the gateway is typically NOT up yet (setup's printed next
|
|
8
|
+
// step is "Start your OpenClaw agent"), which is why creation silently
|
|
9
|
+
// no-op'd on fresh installs without a running gateway. The bridge holds an
|
|
10
|
+
// authenticated gateway WS by construction, so the ensure runs there instead.
|
|
11
|
+
//
|
|
12
|
+
// Once-per-install semantics: a marker file records that the ensure has run to
|
|
13
|
+
// completion. Without it, a user who deliberately deleted their heartbeat cron
|
|
14
|
+
// would get it resurrected on every bridge boot — the old setup-time path ran
|
|
15
|
+
// once, and that operator-override behaviour must be preserved.
|
|
16
|
+
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
17
|
+
import { dirname } from 'path';
|
|
18
|
+
export const HEARTBEAT_CRON_NAME = 'reefclaw-heartbeat';
|
|
19
|
+
export const HEARTBEAT_EVERY_MS = 15 * 60 * 1000;
|
|
20
|
+
// Byte-identical to the message the setup-time CLI path created, so new jobs
|
|
21
|
+
// match every existing install's job.
|
|
22
|
+
export const HEARTBEAT_MESSAGE = 'Heartbeat. Run SESSION START mandatory checks, then the full Decision Loop (Steps 0-9) from SKILL.md. ' +
|
|
23
|
+
'Check tradingMode from fetch_balance — it is your source of truth for paper vs live. ' +
|
|
24
|
+
'Use tools in parallel where possible.';
|
|
25
|
+
/**
|
|
26
|
+
* Whether an existing cron job counts as "the heartbeat already exists".
|
|
27
|
+
* Union of the two matchers already in the codebase: the old setup path
|
|
28
|
+
* matched /reefclaw/, while resolveHeartbeatSeconds() (the cadence reader that
|
|
29
|
+
* drives the dashboard header) matches /heart\s*beat/. A job satisfying either
|
|
30
|
+
* must suppress creation — prod/wisekid boxes carry heartbeat jobs whose names
|
|
31
|
+
* predate the reefclaw- prefix, and a duplicate 15m heartbeat would double the
|
|
32
|
+
* agent's token burn.
|
|
33
|
+
*/
|
|
34
|
+
export function isHeartbeatLikeName(name) {
|
|
35
|
+
return typeof name === 'string' && /reefclaw|heart\s*beat/i.test(name);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Ensure a heartbeat cron exists. Non-fatal by contract: every failure path
|
|
39
|
+
* returns 'failed' rather than throwing, and only success writes the marker so
|
|
40
|
+
* a transient gateway error retries on the next boot.
|
|
41
|
+
*/
|
|
42
|
+
export async function ensureHeartbeatCron(opts) {
|
|
43
|
+
const { rpc, markerPath, log } = opts;
|
|
44
|
+
try {
|
|
45
|
+
if (existsSync(markerPath))
|
|
46
|
+
return 'already_ensured';
|
|
47
|
+
// includeDisabled: a job the user disabled still means "exists" — re-adding
|
|
48
|
+
// a duplicate next to a deliberately-disabled one is worse than doing nothing.
|
|
49
|
+
const listResp = (await rpc.sendRpc('cron.list', { includeDisabled: true }));
|
|
50
|
+
const jobs = Array.isArray(listResp?.jobs) ? listResp.jobs : null;
|
|
51
|
+
if (!jobs) {
|
|
52
|
+
log('Heartbeat cron: skipped (cron.list returned no job list)');
|
|
53
|
+
return 'failed';
|
|
54
|
+
}
|
|
55
|
+
const existing = jobs.find((j) => isHeartbeatLikeName(j?.name));
|
|
56
|
+
if (existing) {
|
|
57
|
+
writeMarker(markerPath, { ensuredAt: new Date().toISOString(), found: String(existing.name) });
|
|
58
|
+
log(`Heartbeat cron: already exists (${String(existing.name)})`);
|
|
59
|
+
return 'found_existing';
|
|
60
|
+
}
|
|
61
|
+
// Parity with the params the CLI built for the old setup command
|
|
62
|
+
// (`openclaw cron add --name reefclaw-heartbeat --every 15m --session isolated --message ...`):
|
|
63
|
+
// isolated agentTurn defaults to delivery announce on the 'last' channel.
|
|
64
|
+
await rpc.sendRpc('cron.add', {
|
|
65
|
+
name: HEARTBEAT_CRON_NAME,
|
|
66
|
+
enabled: true,
|
|
67
|
+
schedule: { kind: 'every', everyMs: HEARTBEAT_EVERY_MS },
|
|
68
|
+
sessionTarget: 'isolated',
|
|
69
|
+
wakeMode: 'now',
|
|
70
|
+
payload: { kind: 'agentTurn', message: HEARTBEAT_MESSAGE },
|
|
71
|
+
delivery: { mode: 'announce', channel: 'last' },
|
|
72
|
+
});
|
|
73
|
+
writeMarker(markerPath, { ensuredAt: new Date().toISOString(), created: HEARTBEAT_CRON_NAME });
|
|
74
|
+
log(`Heartbeat cron: created (${HEARTBEAT_CRON_NAME}, every 15m)`);
|
|
75
|
+
return 'created';
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
log(`Heartbeat cron: skipped (${err instanceof Error ? err.message.split('\n')[0] : String(err)})`);
|
|
79
|
+
return 'failed';
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function writeMarker(markerPath, data) {
|
|
83
|
+
mkdirSync(dirname(markerPath), { recursive: true });
|
|
84
|
+
writeFileSync(markerPath, JSON.stringify(data, null, 2) + '\n', 'utf-8');
|
|
85
|
+
}
|
|
@@ -4,6 +4,7 @@ import type { TickerData, CandleData, OrderData, MarketStructureData, CryptoMetr
|
|
|
4
4
|
export declare const TICKER_INTERVAL_MS = 5000;
|
|
5
5
|
export declare const OHLCV_INTERVAL_MS = 15000;
|
|
6
6
|
export declare const POSITIONS_INTERVAL_MS = 10000;
|
|
7
|
+
export declare const OPEN_ORDERS_INTERVAL_MS = 60000;
|
|
7
8
|
export declare const MARKET_STRUCTURE_INTERVAL_MS = 60000;
|
|
8
9
|
/** CCXT position — minimal shape needed by poller */
|
|
9
10
|
export interface CcxtPosition {
|
|
@@ -25,7 +25,17 @@ export const OHLCV_INTERVAL_MS = 15_000;
|
|
|
25
25
|
// startup handshake is extra live-system surface area for no extra weight.
|
|
26
26
|
export const POSITIONS_INTERVAL_MS = 10_000;
|
|
27
27
|
const BALANCE_INTERVAL_MS = 10_000;
|
|
28
|
-
|
|
28
|
+
// 2026-07-21: 3s → 60s, and the poll is now UNSCOPED (no symbol filter). Its
|
|
29
|
+
// only consumer is the fallback cache behind Kill and the reconcile snapshot
|
|
30
|
+
// (no event emission — live order updates ride the WS stream), and both of
|
|
31
|
+
// those are portfolio-wide by contract: a { symbol }-scoped cache silently
|
|
32
|
+
// degraded them to one symbol whenever the fresh all-symbol fetch failed.
|
|
33
|
+
// Unscoped fetchOpenOrders costs Binance weight 80 (regular + algo merged) vs
|
|
34
|
+
// 2 scoped, so the cadence drops to 60s (80/min, vs 40/min before; the old 3s
|
|
35
|
+
// cadence unscoped would be 1600/min ≈ the whole ceiling). Matches the
|
|
36
|
+
// plugin's own 60s algo-refresh; in userDataStream enforce mode the read is
|
|
37
|
+
// served from the WS store at zero REST weight anyway.
|
|
38
|
+
export const OPEN_ORDERS_INTERVAL_MS = 60_000;
|
|
29
39
|
// 2026-05-15: 30s → 60s. get_market_structure fetches SIX timeframes of
|
|
30
40
|
// OHLCV per poll (the heaviest single skill poll). Multi-timeframe trend
|
|
31
41
|
// structure does not meaningfully change in 30s; 60s keeps the Agent-State
|
|
@@ -357,7 +367,9 @@ export class Poller {
|
|
|
357
367
|
}
|
|
358
368
|
async pollOpenOrders() {
|
|
359
369
|
const tool = this.toolMap.fetch_open_orders;
|
|
360
|
-
|
|
370
|
+
// Fetch ALL open orders (no symbol filter) — this cache is the fallback
|
|
371
|
+
// for the portfolio-wide Kill + reconcile snapshot (see interval comment).
|
|
372
|
+
const result = await this.http.invoke(tool, {});
|
|
361
373
|
const orders = [];
|
|
362
374
|
if (Array.isArray(result.data)) {
|
|
363
375
|
for (const ccxt of result.data) {
|
|
@@ -29,6 +29,8 @@ export declare class GatewayProvider implements OpenClawProvider {
|
|
|
29
29
|
private agentIdentity;
|
|
30
30
|
/** Emit the one-time rollout probe (gateway response shape) only on the first attempt. */
|
|
31
31
|
private loggedAgentIdentityProbe;
|
|
32
|
+
/** One-shot latch for the boot-time heartbeat-cron ensure (re-armed on failure). */
|
|
33
|
+
private heartbeatCronEnsureStarted;
|
|
32
34
|
/** Live heartbeat cadence (seconds), read from the OpenClaw cron store; cached 60s. */
|
|
33
35
|
private heartbeatSeconds?;
|
|
34
36
|
private heartbeatReadAtMs;
|
|
@@ -61,6 +63,18 @@ export declare class GatewayProvider implements OpenClawProvider {
|
|
|
61
63
|
/** Track whether we've received at least one balance poll (needed for equity calculation). */
|
|
62
64
|
private hasReceivedBalance;
|
|
63
65
|
private readonly quoteCurrency;
|
|
66
|
+
/** issue #213 RED-zone debounce: consecutive RED evaluations + when the
|
|
67
|
+
* streak began + when the position snapshot last refreshed. A RED verdict
|
|
68
|
+
* must PERSIST and SURVIVE a positions refresh before auto-flatten fires —
|
|
69
|
+
* in paper mode the wallet drops by FULL NOTIONAL at open, so a balance
|
|
70
|
+
* poll landing before the new position reaches the snapshot reads the
|
|
71
|
+
* entry's own notional as a phantom drawdown (observed live: a 38%-of-NAV
|
|
72
|
+
* entry reported as a -38.41% RED zone 2s after its fill and was
|
|
73
|
+
* auto-flattened). A race artifact cannot outlive one positions poll; a
|
|
74
|
+
* real drawdown easily persists. */
|
|
75
|
+
private redZoneStreak;
|
|
76
|
+
private redZoneSince;
|
|
77
|
+
private positionsUpdatedAt;
|
|
64
78
|
private orderTimestamps;
|
|
65
79
|
private cancelTimestamps;
|
|
66
80
|
private agentStateInterval;
|
|
@@ -301,8 +315,16 @@ export declare class GatewayProvider implements OpenClawProvider {
|
|
|
301
315
|
*/
|
|
302
316
|
private reportTradeResult;
|
|
303
317
|
/**
|
|
304
|
-
* Seed lastTradeTs from
|
|
305
|
-
* Prevents "Last Trade: Never" after every restart
|
|
318
|
+
* Seed lastTradeTs from the webapp's exchange-keyed fills ledger on startup.
|
|
319
|
+
* One-shot, best-effort. Prevents "Last Trade: Never" after every restart
|
|
320
|
+
* when the agent is flat.
|
|
321
|
+
*
|
|
322
|
+
* ★ Issue #194: the previous seed read intel's `trade_results` (closed
|
|
323
|
+
* round-trips only, single-symbol), which showed "last trade 365h ago"
|
|
324
|
+
* while the fills ledger had fills from the previous evening. The ledger
|
|
325
|
+
* (`GET /api/internal/trades`) is the source of truth for fills — seed from
|
|
326
|
+
* it, filtered to the current trading book. On any failure leave null:
|
|
327
|
+
* truthful-unknown beats confidently-wrong.
|
|
306
328
|
*/
|
|
307
329
|
private seedLastTradeTs;
|
|
308
330
|
/** Symbol formatted for intelligence API (BTC/USDT → BTCUSDT). */
|
|
@@ -11,16 +11,26 @@ import { GatewayWsClient } from '../gateway/gateway-ws-client.js';
|
|
|
11
11
|
import { discoverTools } from '../gateway/tool-discovery.js';
|
|
12
12
|
import { EventParser, mapCcxtBalance, mapCcxtOrder, extractLiquidationFields, extractBracketField, } from '../gateway/event-parser.js';
|
|
13
13
|
import { Poller } from '../gateway/poller.js';
|
|
14
|
+
import { ensureHeartbeatCron } from '../gateway/heartbeat-cron.js';
|
|
14
15
|
import { computeEquity as _computeEquity, computePositionNotional as _computePositionNotional, computeRiskMetrics as _computeRiskMetrics, DEFAULT_RISK_LIMITS, } from './risk-calculator.js';
|
|
15
16
|
import { executeKill as _executeKill, executeFlatten as _executeFlatten, executePause as _executePause, executeResume as _executeResume, } from './emergency-commands.js';
|
|
16
17
|
import { executeSetTradingMode, executeGetBracketConfig, executeSetBracketRequirement, executeSetExchangeCredentials, executeTestExchangeCredentials, executeClearExchangeCredentials, } from './onboarding-commands.js';
|
|
17
18
|
const TAG = 'gateway';
|
|
18
|
-
// ----
|
|
19
|
-
// Persists sessionStartNav per date so Day P&L
|
|
20
|
-
|
|
19
|
+
// ---- Day-start NAV persistence ----
|
|
20
|
+
// Persists sessionStartNav (the UTC-day P&L anchor) per date so Day P&L
|
|
21
|
+
// survives skill restarts. The file was historically named session-nav.json;
|
|
22
|
+
// renamed to day-start-nav.json 2026-07-22 — "session" was a misnomer (the
|
|
23
|
+
// value anchors the trading DAY, not any auth/session state) and tripped
|
|
24
|
+
// ClawHub's sensitive-file-read heuristic. Reads fall back to the legacy name
|
|
25
|
+
// once, writes go to the new name only.
|
|
26
|
+
const DAY_NAV_FILENAME = 'day-start-nav.json';
|
|
27
|
+
const LEGACY_DAY_NAV_FILENAME = 'session-nav.json';
|
|
21
28
|
const TRADING_MODE_FILENAME = 'trading-mode.json';
|
|
22
|
-
function
|
|
23
|
-
return join(homedir(), '.openclaw', 'workspace',
|
|
29
|
+
function getDayNavPath() {
|
|
30
|
+
return join(homedir(), '.openclaw', 'workspace', DAY_NAV_FILENAME);
|
|
31
|
+
}
|
|
32
|
+
function getLegacyDayNavPath() {
|
|
33
|
+
return join(homedir(), '.openclaw', 'workspace', LEGACY_DAY_NAV_FILENAME);
|
|
24
34
|
}
|
|
25
35
|
function getTradingModePath() {
|
|
26
36
|
return join(homedir(), '.openclaw', 'workspace', TRADING_MODE_FILENAME);
|
|
@@ -40,17 +50,20 @@ export function shouldAnchorSessionNav(args) {
|
|
|
40
50
|
return args.mode === 'PAPER' && args.sessionDate !== args.today; // paper midnight rollover
|
|
41
51
|
}
|
|
42
52
|
function loadSessionStartNav() {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
53
|
+
for (const path of [getDayNavPath(), getLegacyDayNavPath()]) {
|
|
54
|
+
try {
|
|
55
|
+
const raw = readFileSync(path, 'utf-8');
|
|
56
|
+
const data = JSON.parse(raw);
|
|
57
|
+
if (data.date === todayDateStr() && typeof data.sessionStartNav === 'number' && data.sessionStartNav > 0) {
|
|
58
|
+
return data.sessionStartNav;
|
|
59
|
+
}
|
|
60
|
+
return null; // Different day or invalid — don't let a stale legacy file shadow it
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
/* missing or corrupt — try the legacy name */
|
|
48
64
|
}
|
|
49
|
-
return null; // Different day or invalid
|
|
50
|
-
}
|
|
51
|
-
catch {
|
|
52
|
-
return null; // File doesn't exist or is corrupt
|
|
53
65
|
}
|
|
66
|
+
return null;
|
|
54
67
|
}
|
|
55
68
|
/**
|
|
56
69
|
* Persisted across skill restarts so the FIRST snapshot the gateway emits
|
|
@@ -90,7 +103,11 @@ function saveSessionStartNav(nav) {
|
|
|
90
103
|
const dir = join(homedir(), '.openclaw', 'workspace');
|
|
91
104
|
mkdirSync(dir, { recursive: true });
|
|
92
105
|
const data = { date: todayDateStr(), sessionStartNav: nav };
|
|
93
|
-
writeFileSync(
|
|
106
|
+
writeFileSync(getDayNavPath(), JSON.stringify(data, null, 2), 'utf-8');
|
|
107
|
+
try {
|
|
108
|
+
unlinkSync(getLegacyDayNavPath());
|
|
109
|
+
}
|
|
110
|
+
catch { /* legacy file already gone */ }
|
|
94
111
|
}
|
|
95
112
|
catch (err) {
|
|
96
113
|
logger.warn(TAG, `Failed to save session NAV: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -122,6 +139,8 @@ export class GatewayProvider {
|
|
|
122
139
|
agentIdentity = {};
|
|
123
140
|
/** Emit the one-time rollout probe (gateway response shape) only on the first attempt. */
|
|
124
141
|
loggedAgentIdentityProbe = false;
|
|
142
|
+
/** One-shot latch for the boot-time heartbeat-cron ensure (re-armed on failure). */
|
|
143
|
+
heartbeatCronEnsureStarted = false;
|
|
125
144
|
/** Live heartbeat cadence (seconds), read from the OpenClaw cron store; cached 60s. */
|
|
126
145
|
heartbeatSeconds;
|
|
127
146
|
heartbeatReadAtMs = 0;
|
|
@@ -154,6 +173,18 @@ export class GatewayProvider {
|
|
|
154
173
|
/** Track whether we've received at least one balance poll (needed for equity calculation). */
|
|
155
174
|
hasReceivedBalance = false;
|
|
156
175
|
quoteCurrency;
|
|
176
|
+
/** issue #213 RED-zone debounce: consecutive RED evaluations + when the
|
|
177
|
+
* streak began + when the position snapshot last refreshed. A RED verdict
|
|
178
|
+
* must PERSIST and SURVIVE a positions refresh before auto-flatten fires —
|
|
179
|
+
* in paper mode the wallet drops by FULL NOTIONAL at open, so a balance
|
|
180
|
+
* poll landing before the new position reaches the snapshot reads the
|
|
181
|
+
* entry's own notional as a phantom drawdown (observed live: a 38%-of-NAV
|
|
182
|
+
* entry reported as a -38.41% RED zone 2s after its fill and was
|
|
183
|
+
* auto-flattened). A race artifact cannot outlive one positions poll; a
|
|
184
|
+
* real drawdown easily persists. */
|
|
185
|
+
redZoneStreak = 0;
|
|
186
|
+
redZoneSince = 0;
|
|
187
|
+
positionsUpdatedAt = 0;
|
|
157
188
|
// ---- Rate tracking ----
|
|
158
189
|
orderTimestamps = [];
|
|
159
190
|
cancelTimestamps = [];
|
|
@@ -658,6 +689,7 @@ export class GatewayProvider {
|
|
|
658
689
|
}
|
|
659
690
|
// Update internal state with fresh data (poller may be paused during reconnect)
|
|
660
691
|
this.positions = positions;
|
|
692
|
+
this.positionsUpdatedAt = Date.now();
|
|
661
693
|
this.balance = balance;
|
|
662
694
|
this.openOrders = openOrders;
|
|
663
695
|
// Compute current NAV for portfolio percent calculation (consistent with computeRiskMetrics)
|
|
@@ -1057,6 +1089,24 @@ export class GatewayProvider {
|
|
|
1057
1089
|
// every (re)connect so a model swap — which restarts the gateway and drops
|
|
1058
1090
|
// this socket — is reflected on the next handshake.
|
|
1059
1091
|
void this.refreshAgentIdentity();
|
|
1092
|
+
// Ensure the heartbeat cron exists — via gateway RPC, once per install
|
|
1093
|
+
// (marker-file guarded; a deliberate operator delete is never resurrected).
|
|
1094
|
+
// Lives here instead of setup because setup runs before the gateway is up.
|
|
1095
|
+
if (!this.heartbeatCronEnsureStarted) {
|
|
1096
|
+
this.heartbeatCronEnsureStarted = true;
|
|
1097
|
+
const ws = this.wsClient;
|
|
1098
|
+
if (ws) {
|
|
1099
|
+
void ensureHeartbeatCron({
|
|
1100
|
+
rpc: ws,
|
|
1101
|
+
markerPath: join(homedir(), '.openclaw', 'workspace', 'heartbeat-cron-ensured.json'),
|
|
1102
|
+
log: (msg) => logger.info(TAG, msg),
|
|
1103
|
+
}).then((outcome) => {
|
|
1104
|
+
// A transient failure retries on the next (re)connect, not just next boot.
|
|
1105
|
+
if (outcome === 'failed')
|
|
1106
|
+
this.heartbeatCronEnsureStarted = false;
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1060
1110
|
// Start periodic agent state emission (every 5s)
|
|
1061
1111
|
if (!this.agentStateInterval) {
|
|
1062
1112
|
this.agentStateInterval = setInterval(() => {
|
|
@@ -1201,6 +1251,7 @@ export class GatewayProvider {
|
|
|
1201
1251
|
}
|
|
1202
1252
|
}
|
|
1203
1253
|
this.positions = positions;
|
|
1254
|
+
this.positionsUpdatedAt = Date.now();
|
|
1204
1255
|
this.hasReceivedPositions = true;
|
|
1205
1256
|
this.trySetSessionStartNav();
|
|
1206
1257
|
this.emitRiskUpdate();
|
|
@@ -1575,7 +1626,11 @@ export class GatewayProvider {
|
|
|
1575
1626
|
this.hasReceivedPositions = false;
|
|
1576
1627
|
this.pendingEmptyPoll = false;
|
|
1577
1628
|
try {
|
|
1578
|
-
unlinkSync(
|
|
1629
|
+
unlinkSync(getDayNavPath());
|
|
1630
|
+
}
|
|
1631
|
+
catch { /* ok if missing */ }
|
|
1632
|
+
try {
|
|
1633
|
+
unlinkSync(getLegacyDayNavPath());
|
|
1579
1634
|
}
|
|
1580
1635
|
catch { /* ok if missing */ }
|
|
1581
1636
|
logger.info(TAG, `Session start NAV reset on mode change (${prevMode} → ${this.tradingMode})`);
|
|
@@ -1890,10 +1945,32 @@ export class GatewayProvider {
|
|
|
1890
1945
|
// physically impossible under normal market conditions on a bracketed
|
|
1891
1946
|
// account. If the math says worse than that, it's bad data — log loudly
|
|
1892
1947
|
// and skip instead of closing real positions on a calculation error.
|
|
1948
|
+
// 4. Persistence debounce (issue #213): the balance poll and the position
|
|
1949
|
+
// snapshot are not atomic. In PAPER mode the simulator deducts FULL
|
|
1950
|
+
// NOTIONAL from the wallet at open, so in the seconds after a fill the
|
|
1951
|
+
// wallet already reflects the deduction while `this.positions` does not
|
|
1952
|
+
// yet contain the new position — equity spuriously drops by exactly the
|
|
1953
|
+
// entry's notional and any entry >2.5% of NAV reads as a RED drawdown
|
|
1954
|
+
// (observed live: -38.41% reported 2s after a 38%-of-NAV entry; the
|
|
1955
|
+
// just-opened position was auto-flattened). A RED verdict therefore
|
|
1956
|
+
// only licenses the flatten once it (a) persists across REQUIRED_STREAK
|
|
1957
|
+
// consecutive evaluations, (b) has been standing MIN_RED_PERSISTENCE_MS,
|
|
1958
|
+
// and (c) has SURVIVED at least one positions refresh since it began —
|
|
1959
|
+
// the race artifact cannot outlive one positions poll (~10s), while a
|
|
1960
|
+
// real -2.5% drawdown trivially persists 25s. Cost on a real event:
|
|
1961
|
+
// the flatten fires ~25-35s later. Cost of a false one: a closed
|
|
1962
|
+
// position, a rejected-orders window, and a corrupted trading record.
|
|
1893
1963
|
const uptimeMs = Date.now() - this.startedAt;
|
|
1894
1964
|
const STARTUP_GRACE_PERIOD_MS = 30_000;
|
|
1895
1965
|
const IMPOSSIBLE_DRAWDOWN = -0.5;
|
|
1966
|
+
const REQUIRED_RED_STREAK = 3;
|
|
1967
|
+
const MIN_RED_PERSISTENCE_MS = 25_000;
|
|
1896
1968
|
if (metrics.drawdownZone === 'RED' && this.agentMode === 'ACTIVE') {
|
|
1969
|
+
if (this.redZoneStreak === 0)
|
|
1970
|
+
this.redZoneSince = Date.now();
|
|
1971
|
+
this.redZoneStreak++;
|
|
1972
|
+
const redForMs = Date.now() - this.redZoneSince;
|
|
1973
|
+
const survivedPositionsRefresh = this.positionsUpdatedAt > this.redZoneSince;
|
|
1897
1974
|
if (uptimeMs < STARTUP_GRACE_PERIOD_MS) {
|
|
1898
1975
|
logger.warn(TAG, `RED zone drawdown detected (${metrics.drawdownZoneMessage}) but within startup grace period (${Math.round(uptimeMs / 1000)}s) — skipping auto-flatten`);
|
|
1899
1976
|
}
|
|
@@ -1903,6 +1980,11 @@ export class GatewayProvider {
|
|
|
1903
1980
|
else if (metrics.utilization.dailyDrawdown < IMPOSSIBLE_DRAWDOWN) {
|
|
1904
1981
|
logger.error(TAG, `RED zone drawdown ${(metrics.utilization.dailyDrawdown * 100).toFixed(1)}% exceeds sanity floor ${IMPOSSIBLE_DRAWDOWN * 100}% — refusing auto-flatten, likely equity calculation error (balance.total=${this.balance.total}, sessionStartNav=${this.sessionStartNav}, positions=${this.positions.length})`);
|
|
1905
1982
|
}
|
|
1983
|
+
else if (this.redZoneStreak < REQUIRED_RED_STREAK ||
|
|
1984
|
+
redForMs < MIN_RED_PERSISTENCE_MS ||
|
|
1985
|
+
!survivedPositionsRefresh) {
|
|
1986
|
+
logger.warn(TAG, `RED zone drawdown detected (${metrics.drawdownZoneMessage}) — deferring auto-flatten until the verdict persists (streak ${this.redZoneStreak}/${REQUIRED_RED_STREAK}, ${Math.round(redForMs / 1000)}s/${MIN_RED_PERSISTENCE_MS / 1000}s, survivedPositionsRefresh=${survivedPositionsRefresh}). A fresh entry's notional reads as phantom drawdown until the position snapshot catches up (issue #213); a real drawdown will persist and flatten on a later evaluation.`);
|
|
1987
|
+
}
|
|
1906
1988
|
else {
|
|
1907
1989
|
logger.warn(TAG, `RED zone drawdown detected (${metrics.drawdownZoneMessage}) — auto-flattening all positions`);
|
|
1908
1990
|
// Route through executeEmergency (NOT executeFlatten directly) so the
|
|
@@ -1917,6 +1999,11 @@ export class GatewayProvider {
|
|
|
1917
1999
|
});
|
|
1918
2000
|
}
|
|
1919
2001
|
}
|
|
2002
|
+
else {
|
|
2003
|
+
// Any non-RED evaluation clears the streak — the race artifact resolves
|
|
2004
|
+
// the moment the positions snapshot includes the new position.
|
|
2005
|
+
this.redZoneStreak = 0;
|
|
2006
|
+
}
|
|
1920
2007
|
// Include position snapshots + balance in risk_update so the webapp can
|
|
1921
2008
|
// update KPI/PnL without depending on market_data ticker events.
|
|
1922
2009
|
const equity = this.computeEquity();
|
|
@@ -2097,27 +2184,39 @@ export class GatewayProvider {
|
|
|
2097
2184
|
this.inFlightReports.push(report);
|
|
2098
2185
|
}
|
|
2099
2186
|
/**
|
|
2100
|
-
* Seed lastTradeTs from
|
|
2101
|
-
* Prevents "Last Trade: Never" after every restart
|
|
2187
|
+
* Seed lastTradeTs from the webapp's exchange-keyed fills ledger on startup.
|
|
2188
|
+
* One-shot, best-effort. Prevents "Last Trade: Never" after every restart
|
|
2189
|
+
* when the agent is flat.
|
|
2190
|
+
*
|
|
2191
|
+
* ★ Issue #194: the previous seed read intel's `trade_results` (closed
|
|
2192
|
+
* round-trips only, single-symbol), which showed "last trade 365h ago"
|
|
2193
|
+
* while the fills ledger had fills from the previous evening. The ledger
|
|
2194
|
+
* (`GET /api/internal/trades`) is the source of truth for fills — seed from
|
|
2195
|
+
* it, filtered to the current trading book. On any failure leave null:
|
|
2196
|
+
* truthful-unknown beats confidently-wrong.
|
|
2102
2197
|
*/
|
|
2103
2198
|
async seedLastTradeTs() {
|
|
2104
2199
|
if (this.lastTradeTs)
|
|
2105
2200
|
return; // Already set (e.g. from WS event during init)
|
|
2106
|
-
const url = this.config.intelligenceUrl;
|
|
2107
2201
|
const token = this.config.connectionToken;
|
|
2108
|
-
if (!
|
|
2202
|
+
if (!token)
|
|
2109
2203
|
return;
|
|
2204
|
+
// www is load-bearing: reefclaw.com 307-redirects and Node fetch strips
|
|
2205
|
+
// the Authorization header on cross-origin redirect (same as bridge.ts).
|
|
2206
|
+
const base = (process.env.REEFCLAW_API_URL || 'https://www.reefclaw.com').replace(/\/$/, '');
|
|
2207
|
+
const mode = this.tradingMode === 'PAPER' ? 'paper' : 'live';
|
|
2110
2208
|
try {
|
|
2111
|
-
const res = await fetch(`${
|
|
2209
|
+
const res = await fetch(`${base}/api/internal/trades?limit=1&mode=${mode}`, {
|
|
2112
2210
|
headers: { Authorization: `Bearer ${token}` },
|
|
2113
2211
|
signal: AbortSignal.timeout(5_000),
|
|
2114
2212
|
});
|
|
2115
2213
|
if (!res.ok)
|
|
2116
2214
|
return;
|
|
2117
|
-
const
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2215
|
+
const body = (await res.json());
|
|
2216
|
+
const ts = body.trades?.[0]?.fillTimestamp;
|
|
2217
|
+
if (ts) {
|
|
2218
|
+
this.lastTradeTs = ts;
|
|
2219
|
+
logger.info(TAG, `Seeded lastTradeTs from trades ledger (${mode}): ${this.lastTradeTs}`);
|
|
2121
2220
|
this.emitAgentState(); // Re-emit with updated timestamp
|
|
2122
2221
|
}
|
|
2123
2222
|
}
|
package/assets/bridge/setup.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// Interactive setup helper for the ReefClaw skill.
|
|
2
2
|
// Validates token format, tests relay connection, saves to OpenClaw config.
|
|
3
3
|
import WebSocket from 'ws';
|
|
4
|
-
import { execSync } from 'node:child_process';
|
|
5
4
|
import { writeOpenClawConfig } from './config.js';
|
|
6
5
|
import { logger } from './logger.js';
|
|
7
6
|
const TAG = 'setup';
|
|
@@ -149,8 +148,12 @@ export async function runSetup(tokenOrBundle, userId, relayUrl) {
|
|
|
149
148
|
}
|
|
150
149
|
// Save to config
|
|
151
150
|
writeOpenClawConfig(token, resolvedUserId, resolvedRelayUrl);
|
|
152
|
-
//
|
|
153
|
-
|
|
151
|
+
// Heartbeat cron is ensured by the bridge at first gateway connect (via
|
|
152
|
+
// cron.list/cron.add RPC — see gateway/heartbeat-cron.ts). Setup can't do it:
|
|
153
|
+
// the gateway isn't running yet at this point, which is also why the old
|
|
154
|
+
// setup-time shell-out to the openclaw CLI silently no-op'd on fresh
|
|
155
|
+
// installs (the CLI's cron commands are gateway RPC clients too).
|
|
156
|
+
console.log(' Heartbeat cron: created automatically when the agent first connects (every 15m)');
|
|
154
157
|
console.log('');
|
|
155
158
|
console.log(' Setup complete! Token saved to ~/.openclaw/config.json');
|
|
156
159
|
console.log('');
|
|
@@ -161,54 +164,6 @@ export async function runSetup(tokenOrBundle, userId, relayUrl) {
|
|
|
161
164
|
console.log(' 4. Your agent checks the market every 15 minutes (adjustable via chat)');
|
|
162
165
|
console.log('');
|
|
163
166
|
}
|
|
164
|
-
// ---- Heartbeat cron ----
|
|
165
|
-
/**
|
|
166
|
-
* Ensures a heartbeat cron job exists for ReefClaw.
|
|
167
|
-
* Checks `openclaw cron list` for an existing job with "reefclaw" in the name.
|
|
168
|
-
* If none found, creates one with 15m default interval.
|
|
169
|
-
* Non-fatal — if openclaw CLI isn't available or cron fails, setup still succeeds.
|
|
170
|
-
*/
|
|
171
|
-
function ensureHeartbeatCron() {
|
|
172
|
-
try {
|
|
173
|
-
// Check if a reefclaw cron already exists
|
|
174
|
-
const listOutput = execSync('openclaw cron list --json 2>/dev/null', {
|
|
175
|
-
encoding: 'utf-8',
|
|
176
|
-
timeout: 15_000,
|
|
177
|
-
});
|
|
178
|
-
// Look for any job with "reefclaw" in the name
|
|
179
|
-
try {
|
|
180
|
-
const jobs = JSON.parse(listOutput);
|
|
181
|
-
const existing = (Array.isArray(jobs) ? jobs : []).find((j) => j.name?.toLowerCase().includes('reefclaw'));
|
|
182
|
-
if (existing) {
|
|
183
|
-
console.log(` Heartbeat cron: already exists (${existing.name})`);
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
catch {
|
|
188
|
-
// JSON parse failed — maybe not JSON output, check raw text
|
|
189
|
-
if (listOutput.toLowerCase().includes('reefclaw')) {
|
|
190
|
-
console.log(' Heartbeat cron: already exists');
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
// No existing job — create one
|
|
195
|
-
console.log(' Creating heartbeat cron (every 15m)...');
|
|
196
|
-
execSync('openclaw cron add --name reefclaw-heartbeat --every 15m --session isolated ' +
|
|
197
|
-
"--message 'Heartbeat. Run SESSION START mandatory checks, then the full Decision Loop (Steps 0-9) from SKILL.md. Check tradingMode from fetch_balance — it is your source of truth for paper vs live. Use tools in parallel where possible.' 2>&1", { encoding: 'utf-8', timeout: 15_000 });
|
|
198
|
-
console.log(' Heartbeat cron: created (every 15 minutes)');
|
|
199
|
-
console.log(' Tip: Ask your agent "change heartbeat to 10 minutes" to adjust');
|
|
200
|
-
}
|
|
201
|
-
catch (err) {
|
|
202
|
-
// Non-fatal — user can create cron manually or agent can create it on first session
|
|
203
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
204
|
-
if (msg.includes('not found') || msg.includes('ENOENT')) {
|
|
205
|
-
console.log(' Heartbeat cron: skipped (openclaw CLI not in PATH)');
|
|
206
|
-
}
|
|
207
|
-
else {
|
|
208
|
-
console.log(` Heartbeat cron: skipped (${msg.split('\n')[0]})`);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
167
|
function printSetupInstructions() {
|
|
213
168
|
console.log(' To connect your OpenClaw agent to ReefClaw:');
|
|
214
169
|
console.log('');
|
|
@@ -153,11 +153,20 @@ register('price_sweep', (ctx, params, _dir, condCtx) => {
|
|
|
153
153
|
sweepLevel = nearestHigh;
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
|
-
// Store in shared context for entry/stop rules and direction
|
|
156
|
+
// Store in shared context for entry/stop rules and direction.
|
|
157
|
+
// sweptDirection is written non-destructively, like the funding_extreme /
|
|
158
|
+
// cvd_divergence setters: only when a sweep actually resolved a side. An
|
|
159
|
+
// unconditional write (including null on a no-sweep bar) clobbered a
|
|
160
|
+
// direction set by an earlier condition in the same evaluation, so a
|
|
161
|
+
// from_sweep/from_funding strategy listing price_sweep AFTER another
|
|
162
|
+
// setter could never fire.
|
|
157
163
|
condCtx.sweepLevel = sweepLevel;
|
|
158
164
|
condCtx.recentLow = recentLow;
|
|
159
165
|
condCtx.recentHigh = recentHigh;
|
|
160
|
-
|
|
166
|
+
if (sweptLow)
|
|
167
|
+
condCtx.sweptDirection = 'LONG';
|
|
168
|
+
else if (sweptHigh)
|
|
169
|
+
condCtx.sweptDirection = 'SHORT';
|
|
161
170
|
const met = sweptLow || sweptHigh;
|
|
162
171
|
return {
|
|
163
172
|
met,
|