@reefclaw/openclaw-plugin 0.1.0
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/.gitignore +8 -0
- package/audit/mode-transition-audit.d.ts +11 -0
- package/audit/mode-transition-audit.js +29 -0
- package/balance-utils.d.ts +36 -0
- package/balance-utils.js +98 -0
- package/bridge/bridge.d.ts +109 -0
- package/bridge/bridge.js +1036 -0
- package/bridge/config.d.ts +43 -0
- package/bridge/config.js +176 -0
- package/bridge/connector.d.ts +52 -0
- package/bridge/connector.js +293 -0
- package/bridge/event-replay-buffer.d.ts +43 -0
- package/bridge/event-replay-buffer.js +109 -0
- package/bridge/gateway/event-parser.d.ts +209 -0
- package/bridge/gateway/event-parser.js +793 -0
- package/bridge/gateway/gateway-config.d.ts +39 -0
- package/bridge/gateway/gateway-config.js +86 -0
- package/bridge/gateway/gateway-http-client.d.ts +50 -0
- package/bridge/gateway/gateway-http-client.js +165 -0
- package/bridge/gateway/gateway-ws-client.d.ts +116 -0
- package/bridge/gateway/gateway-ws-client.js +417 -0
- package/bridge/gateway/poller.d.ts +146 -0
- package/bridge/gateway/poller.js +505 -0
- package/bridge/gateway/tool-discovery.d.ts +25 -0
- package/bridge/gateway/tool-discovery.js +198 -0
- package/bridge/index.d.ts +2 -0
- package/bridge/index.js +253 -0
- package/bridge/logger.d.ts +2 -0
- package/bridge/logger.js +2 -0
- package/bridge/provider.d.ts +156 -0
- package/bridge/provider.js +2 -0
- package/bridge/providers/emergency-commands.d.ts +54 -0
- package/bridge/providers/emergency-commands.js +235 -0
- package/bridge/providers/gateway.d.ts +322 -0
- package/bridge/providers/gateway.js +2302 -0
- package/bridge/providers/mock.d.ts +37 -0
- package/bridge/providers/mock.js +385 -0
- package/bridge/providers/onboarding-commands.d.ts +83 -0
- package/bridge/providers/onboarding-commands.js +213 -0
- package/bridge/providers/risk-calculator.d.ts +96 -0
- package/bridge/providers/risk-calculator.js +369 -0
- package/bridge/setup.d.ts +32 -0
- package/bridge/setup.js +226 -0
- package/bridge/types.d.ts +584 -0
- package/bridge/types.js +50 -0
- package/bridge/utils/reconnect.d.ts +6 -0
- package/bridge/utils/reconnect.js +6 -0
- package/bridge/utils/skill-signing.d.ts +51 -0
- package/bridge/utils/skill-signing.js +138 -0
- package/bridge/utils/skill-version.d.ts +17 -0
- package/bridge/utils/skill-version.js +74 -0
- package/ccxt/binance-ban-gate.d.ts +47 -0
- package/ccxt/binance-ban-gate.js +409 -0
- package/ccxt/binance-private.d.ts +325 -0
- package/ccxt/binance-private.js +1415 -0
- package/ccxt/binance-public.d.ts +18 -0
- package/ccxt/binance-public.js +147 -0
- package/config/agent-config-client.d.ts +55 -0
- package/config/agent-config-client.js +145 -0
- package/config/agent-config-poller.d.ts +25 -0
- package/config/agent-config-poller.js +100 -0
- package/config/brackets-config.d.ts +22 -0
- package/config/brackets-config.js +58 -0
- package/config/gate-store.d.ts +18 -0
- package/config/gate-store.js +61 -0
- package/config/plugin-config-io.d.ts +181 -0
- package/config/plugin-config-io.js +84 -0
- package/config/position-review-config.d.ts +35 -0
- package/config/position-review-config.js +105 -0
- package/config/tool-gate.d.ts +53 -0
- package/config/tool-gate.js +125 -0
- package/config/user-data-stream-config.d.ts +85 -0
- package/config/user-data-stream-config.js +224 -0
- package/connector-supervisor.d.ts +36 -0
- package/connector-supervisor.js +149 -0
- package/exchange-adapter.d.ts +49 -0
- package/exchange-adapter.js +4 -0
- package/index.d.ts +30 -0
- package/index.js +2030 -0
- package/ingest/pending-entry-metadata.d.ts +52 -0
- package/ingest/pending-entry-metadata.js +182 -0
- package/ingest/position-auto-capture.d.ts +98 -0
- package/ingest/position-auto-capture.js +394 -0
- package/ingest/position-decisions-client.d.ts +318 -0
- package/ingest/position-decisions-client.js +296 -0
- package/ingest/reconcile-db-vs-exchange.d.ts +13 -0
- package/ingest/reconcile-db-vs-exchange.js +114 -0
- package/ingest/reconciler-cleanup.d.ts +37 -0
- package/ingest/reconciler-cleanup.js +147 -0
- package/ingest/rest-gap-filler.d.ts +191 -0
- package/ingest/rest-gap-filler.js +565 -0
- package/ingest/touched-symbols-store.d.ts +25 -0
- package/ingest/touched-symbols-store.js +96 -0
- package/ingest/trade-store-client.d.ts +40 -0
- package/ingest/trade-store-client.js +125 -0
- package/ingest/ws-ingest.d.ts +43 -0
- package/ingest/ws-ingest.js +126 -0
- package/learning/setup-family.d.ts +21 -0
- package/learning/setup-family.js +103 -0
- package/lifecycle/install-signal-handlers.d.ts +33 -0
- package/lifecycle/install-signal-handlers.js +112 -0
- package/lifecycle/shutdown-coordinator.d.ts +43 -0
- package/lifecycle/shutdown-coordinator.js +131 -0
- package/live/bracket-id.d.ts +18 -0
- package/live/bracket-id.js +81 -0
- package/live/bracket-ledger.d.ts +54 -0
- package/live/bracket-ledger.js +267 -0
- package/live/bracket-manager.d.ts +82 -0
- package/live/bracket-manager.js +478 -0
- package/live/bracket-params.d.ts +22 -0
- package/live/bracket-params.js +124 -0
- package/live/bracket-reconciler.d.ts +95 -0
- package/live/bracket-reconciler.js +573 -0
- package/live/bracket-types.d.ts +102 -0
- package/live/bracket-types.js +8 -0
- package/live/deposit-tracker.d.ts +62 -0
- package/live/deposit-tracker.js +97 -0
- package/live/emergency-controls.d.ts +32 -0
- package/live/emergency-controls.js +226 -0
- package/live/exchange-errors.d.ts +12 -0
- package/live/exchange-errors.js +130 -0
- package/live/exchange-info-cache.d.ts +35 -0
- package/live/exchange-info-cache.js +119 -0
- package/live/fact-subscriber.d.ts +78 -0
- package/live/fact-subscriber.js +182 -0
- package/live/intent-journal.d.ts +42 -0
- package/live/intent-journal.js +122 -0
- package/live/listen-key-manager.d.ts +70 -0
- package/live/listen-key-manager.js +169 -0
- package/live/live-adapter.d.ts +264 -0
- package/live/live-adapter.js +1665 -0
- package/live/live-balance-enricher.d.ts +32 -0
- package/live/live-balance-enricher.js +104 -0
- package/live/live-bracket-api.d.ts +13 -0
- package/live/live-bracket-api.js +20 -0
- package/live/live-state-store.d.ts +194 -0
- package/live/live-state-store.js +450 -0
- package/live/local-signal-service.d.ts +57 -0
- package/live/local-signal-service.js +146 -0
- package/live/local-strategy-evaluator.d.ts +62 -0
- package/live/local-strategy-evaluator.js +127 -0
- package/live/microstructure-assembler.d.ts +54 -0
- package/live/microstructure-assembler.js +148 -0
- package/live/order-poller.d.ts +29 -0
- package/live/order-poller.js +125 -0
- package/live/position-state-store.d.ts +83 -0
- package/live/position-state-store.js +237 -0
- package/live/proposal-decision-listener.d.ts +64 -0
- package/live/proposal-decision-listener.js +288 -0
- package/live/proposal-manager.d.ts +76 -0
- package/live/proposal-manager.js +140 -0
- package/live/rate-limiter.d.ts +47 -0
- package/live/rate-limiter.js +159 -0
- package/live/reconciler.d.ts +39 -0
- package/live/reconciler.js +175 -0
- package/live/setup-buckets.d.ts +7 -0
- package/live/setup-buckets.js +33 -0
- package/live/slippage-tracker.d.ts +45 -0
- package/live/slippage-tracker.js +78 -0
- package/live/stop-watcher.d.ts +34 -0
- package/live/stop-watcher.js +158 -0
- package/live/user-data-active-probe.d.ts +54 -0
- package/live/user-data-active-probe.js +180 -0
- package/live/user-data-stream-controller.d.ts +200 -0
- package/live/user-data-stream-controller.js +579 -0
- package/live/user-data-stream-ws.d.ts +22 -0
- package/live/user-data-stream-ws.js +63 -0
- package/live/user-data-stream.d.ts +243 -0
- package/live/user-data-stream.js +704 -0
- package/logger.d.ts +2 -0
- package/logger.js +2 -0
- package/mfe.d.ts +21 -0
- package/mfe.js +68 -0
- package/onboarding/mode-ladder.d.ts +1 -0
- package/onboarding/mode-ladder.js +3 -0
- package/onboarding/runtime.d.ts +71 -0
- package/onboarding/runtime.js +153 -0
- package/openclaw.plugin.json +94 -0
- package/package.json +27 -0
- package/paper-adapter.d.ts +24 -0
- package/paper-adapter.js +91 -0
- package/persistence/state-manager.d.ts +42 -0
- package/persistence/state-manager.js +164 -0
- package/pinned-plan.d.ts +9 -0
- package/pinned-plan.js +23 -0
- package/risk/pre-trade-check.d.ts +38 -0
- package/risk/pre-trade-check.js +345 -0
- package/risk/pre-trade-types.d.ts +60 -0
- package/risk/pre-trade-types.js +3 -0
- package/scripts/assemble.mjs +114 -0
- package/shadow/shadow-tracker.d.ts +36 -0
- package/shadow/shadow-tracker.js +151 -0
- package/shadow/types.d.ts +42 -0
- package/shadow/types.js +20 -0
- package/shared/indicators-extended.d.ts +52 -0
- package/shared/indicators-extended.js +291 -0
- package/shared/indicators.d.ts +15 -0
- package/shared/indicators.js +114 -0
- package/signals/conditions/registry.d.ts +16 -0
- package/signals/conditions/registry.js +1274 -0
- package/signals/conditions/types.d.ts +1 -0
- package/signals/conditions/types.js +4 -0
- package/signals/direction-rules.d.ts +3 -0
- package/signals/direction-rules.js +24 -0
- package/signals/entry-rules.d.ts +6 -0
- package/signals/entry-rules.js +33 -0
- package/signals/serialize-context.d.ts +4 -0
- package/signals/serialize-context.js +39 -0
- package/signals/stop-rules.d.ts +3 -0
- package/signals/stop-rules.js +48 -0
- package/signals/strategy-adapter.d.ts +14 -0
- package/signals/strategy-adapter.js +122 -0
- package/signals/types.d.ts +1 -0
- package/signals/types.js +8 -0
- package/simulator/exchange-simulator.d.ts +93 -0
- package/simulator/exchange-simulator.js +684 -0
- package/simulator/fill-engine.d.ts +53 -0
- package/simulator/fill-engine.js +276 -0
- package/simulator/paper-market-feed.d.ts +26 -0
- package/simulator/paper-market-feed.js +104 -0
- package/simulator/realistic-fills.d.ts +59 -0
- package/simulator/realistic-fills.js +175 -0
- package/simulator/types.d.ts +219 -0
- package/simulator/types.js +43 -0
- package/skills/reefclaw/SKILL.md +97 -0
- package/strategy/builtin-strategies.d.ts +2 -0
- package/strategy/builtin-strategies.js +109 -0
- package/strategy/condition-registry.d.ts +3 -0
- package/strategy/condition-registry.js +153 -0
- package/strategy/evaluator.d.ts +67 -0
- package/strategy/evaluator.js +93 -0
- package/tools/assessment-validation.d.ts +118 -0
- package/tools/assessment-validation.js +415 -0
- package/tools/attach-brackets.d.ts +34 -0
- package/tools/attach-brackets.js +363 -0
- package/tools/audit-bracket-protection.d.ts +49 -0
- package/tools/audit-bracket-protection.js +527 -0
- package/tools/cancel-all-orders.d.ts +7 -0
- package/tools/cancel-all-orders.js +5 -0
- package/tools/cancel-order.d.ts +10 -0
- package/tools/cancel-order.js +14 -0
- package/tools/check-position-health.d.ts +46 -0
- package/tools/check-position-health.js +194 -0
- package/tools/clear-exchange-credentials.d.ts +24 -0
- package/tools/clear-exchange-credentials.js +70 -0
- package/tools/close-position.d.ts +22 -0
- package/tools/close-position.js +449 -0
- package/tools/create-order.d.ts +54 -0
- package/tools/create-order.js +338 -0
- package/tools/exit-gate.d.ts +58 -0
- package/tools/exit-gate.js +162 -0
- package/tools/fetch-balance.d.ts +5 -0
- package/tools/fetch-balance.js +4 -0
- package/tools/fetch-ohlcv.d.ts +11 -0
- package/tools/fetch-ohlcv.js +8 -0
- package/tools/fetch-open-orders.d.ts +7 -0
- package/tools/fetch-open-orders.js +4 -0
- package/tools/fetch-positions.d.ts +7 -0
- package/tools/fetch-positions.js +4 -0
- package/tools/fetch-ticker.d.ts +11 -0
- package/tools/fetch-ticker.js +5 -0
- package/tools/get-agent-profile.d.ts +4 -0
- package/tools/get-agent-profile.js +6 -0
- package/tools/get-analytics.d.ts +6 -0
- package/tools/get-analytics.js +7 -0
- package/tools/get-backtest.d.ts +12 -0
- package/tools/get-backtest.js +91 -0
- package/tools/get-basis.d.ts +7 -0
- package/tools/get-basis.js +7 -0
- package/tools/get-bracket-config.d.ts +11 -0
- package/tools/get-bracket-config.js +24 -0
- package/tools/get-cascade-risk.d.ts +7 -0
- package/tools/get-cascade-risk.js +8 -0
- package/tools/get-crypto-metrics.d.ts +18 -0
- package/tools/get-crypto-metrics.js +45 -0
- package/tools/get-cvd.d.ts +6 -0
- package/tools/get-cvd.js +6 -0
- package/tools/get-divergences.d.ts +6 -0
- package/tools/get-divergences.js +6 -0
- package/tools/get-funding-context.d.ts +6 -0
- package/tools/get-funding-context.js +16 -0
- package/tools/get-liquidation-levels.d.ts +7 -0
- package/tools/get-liquidation-levels.js +7 -0
- package/tools/get-liquidation-pulse.d.ts +9 -0
- package/tools/get-liquidation-pulse.js +22 -0
- package/tools/get-market-breadth.d.ts +6 -0
- package/tools/get-market-breadth.js +8 -0
- package/tools/get-market-intel.d.ts +19 -0
- package/tools/get-market-intel.js +116 -0
- package/tools/get-market-structure.d.ts +47 -0
- package/tools/get-market-structure.js +198 -0
- package/tools/get-my-mined-patterns.d.ts +20 -0
- package/tools/get-my-mined-patterns.js +61 -0
- package/tools/get-my-proposed-learnings.d.ts +20 -0
- package/tools/get-my-proposed-learnings.js +55 -0
- package/tools/get-my-recent-reviews.d.ts +22 -0
- package/tools/get-my-recent-reviews.js +66 -0
- package/tools/get-orderbook.d.ts +21 -0
- package/tools/get-orderbook.js +32 -0
- package/tools/get-pattern-scan.d.ts +7 -0
- package/tools/get-pattern-scan.js +8 -0
- package/tools/get-regime.d.ts +6 -0
- package/tools/get-regime.js +7 -0
- package/tools/get-relevant-learnings.d.ts +21 -0
- package/tools/get-relevant-learnings.js +65 -0
- package/tools/get-resting-liquidity.d.ts +6 -0
- package/tools/get-resting-liquidity.js +11 -0
- package/tools/get-risk-scenario.d.ts +29 -0
- package/tools/get-risk-scenario.js +47 -0
- package/tools/get-risk-summary.d.ts +51 -0
- package/tools/get-risk-summary.js +118 -0
- package/tools/get-sentiment.d.ts +4 -0
- package/tools/get-sentiment.js +6 -0
- package/tools/get-session-review.d.ts +7 -0
- package/tools/get-session-review.js +8 -0
- package/tools/get-setup-detail.d.ts +7 -0
- package/tools/get-setup-detail.js +303 -0
- package/tools/get-signals.d.ts +15 -0
- package/tools/get-signals.js +54 -0
- package/tools/get-sizing.d.ts +6 -0
- package/tools/get-sizing.js +6 -0
- package/tools/get-trade-feedback.d.ts +7 -0
- package/tools/get-trade-feedback.js +8 -0
- package/tools/get-trade-flow.d.ts +7 -0
- package/tools/get-trade-flow.js +7 -0
- package/tools/get-volume-analysis.d.ts +21 -0
- package/tools/get-volume-analysis.js +74 -0
- package/tools/get-volume-profile.d.ts +7 -0
- package/tools/get-volume-profile.js +7 -0
- package/tools/helpers.d.ts +25 -0
- package/tools/helpers.js +38 -0
- package/tools/intel-api.d.ts +14 -0
- package/tools/intel-api.js +52 -0
- package/tools/intel-cache.d.ts +25 -0
- package/tools/intel-cache.js +133 -0
- package/tools/list-strategies.d.ts +7 -0
- package/tools/list-strategies.js +6 -0
- package/tools/modify-stop.d.ts +17 -0
- package/tools/modify-stop.js +81 -0
- package/tools/modify-target.d.ts +17 -0
- package/tools/modify-target.js +71 -0
- package/tools/propose-learning.d.ts +22 -0
- package/tools/propose-learning.js +65 -0
- package/tools/query-review-outcomes.d.ts +30 -0
- package/tools/query-review-outcomes.js +64 -0
- package/tools/query-trades.d.ts +21 -0
- package/tools/query-trades.js +37 -0
- package/tools/record-position-reviews.d.ts +38 -0
- package/tools/record-position-reviews.js +147 -0
- package/tools/save-strategy.d.ts +16 -0
- package/tools/save-strategy.js +46 -0
- package/tools/scan-pairs.d.ts +18 -0
- package/tools/scan-pairs.js +220 -0
- package/tools/score-setup.d.ts +31 -0
- package/tools/score-setup.js +268 -0
- package/tools/set-bracket-requirement.d.ts +18 -0
- package/tools/set-bracket-requirement.js +81 -0
- package/tools/set-exchange-credentials.d.ts +25 -0
- package/tools/set-exchange-credentials.js +80 -0
- package/tools/set-trading-mode.d.ts +26 -0
- package/tools/set-trading-mode.js +135 -0
- package/tools/test-exchange-credentials.d.ts +16 -0
- package/tools/test-exchange-credentials.js +100 -0
- package/tools/toggle-strategy.d.ts +8 -0
- package/tools/toggle-strategy.js +8 -0
- package/trading-params-cache.d.ts +26 -0
- package/trading-params-cache.js +52 -0
- package/types.d.ts +110 -0
- package/types.js +7 -0
- package/util/plugin-paths.d.ts +3 -0
- package/util/plugin-paths.js +15 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// ListenKeyManager — owns the Binance Futures user-data listenKey lifecycle.
|
|
2
|
+
//
|
|
3
|
+
// Flow:
|
|
4
|
+
// 1. `start()` — POST /fapi/v1/listenKey → emit 'keyMinted' with the listenKey.
|
|
5
|
+
// 2. Schedule PUT /fapi/v1/listenKey every `refreshIntervalMs` (default 25 min).
|
|
6
|
+
// Binance expires idle keys at 60 min; 25 min gives a 2x safety margin.
|
|
7
|
+
// 3. On failed keep-alive, re-mint (POST) a fresh key and emit 'keyRotated'.
|
|
8
|
+
// Binance returns the SAME listenKey for repeat POSTs from the same API
|
|
9
|
+
// key, so "re-mint" is effectively a probe that the key is still valid.
|
|
10
|
+
// If the probe succeeds, we accept its answer; if it fails, we emit
|
|
11
|
+
// 'keyKeepAliveFailed' and stop — the parent UserDataStream schedules
|
|
12
|
+
// a reconnect that re-enters `start()`.
|
|
13
|
+
// 4. `stop()` — clear timer + DELETE /fapi/v1/listenKey (best-effort).
|
|
14
|
+
//
|
|
15
|
+
// Why this is a separate component:
|
|
16
|
+
// - Testable in isolation with fake timers + a mock API.
|
|
17
|
+
// - UserDataStream can stay focused on frame parsing + reconnect logic.
|
|
18
|
+
// - Graduated alert thresholds live here (3 failed refreshes = WARN,
|
|
19
|
+
// 10 = ERROR) rather than being spread through the WS state machine.
|
|
20
|
+
import { EventEmitter } from 'node:events';
|
|
21
|
+
import { logger, formatError } from '../logger.js';
|
|
22
|
+
const TAG = 'listen-key-manager';
|
|
23
|
+
const REAL_TIMER_DEPS = {
|
|
24
|
+
setTimeout: (fn, ms) => setTimeout(fn, ms),
|
|
25
|
+
clearTimeout: (h) => clearTimeout(h),
|
|
26
|
+
now: () => Date.now(),
|
|
27
|
+
};
|
|
28
|
+
/** Lightweight typed emitter — EventEmitter with a phantom type. */
|
|
29
|
+
export class ListenKeyManager extends EventEmitter {
|
|
30
|
+
api;
|
|
31
|
+
refreshIntervalMs;
|
|
32
|
+
maxConsecutiveFailures;
|
|
33
|
+
timers;
|
|
34
|
+
currentKey = null;
|
|
35
|
+
keyMintedAt = null;
|
|
36
|
+
refreshTimer = null;
|
|
37
|
+
consecutiveFailures = 0;
|
|
38
|
+
running = false;
|
|
39
|
+
constructor(api, options = {}) {
|
|
40
|
+
super();
|
|
41
|
+
this.api = api;
|
|
42
|
+
this.refreshIntervalMs = options.refreshIntervalMs ?? 25 * 60_000;
|
|
43
|
+
this.maxConsecutiveFailures = options.maxConsecutiveFailures ?? 3;
|
|
44
|
+
this.timers = {
|
|
45
|
+
setTimeout: options.timers?.setTimeout ?? REAL_TIMER_DEPS.setTimeout,
|
|
46
|
+
clearTimeout: options.timers?.clearTimeout ?? REAL_TIMER_DEPS.clearTimeout,
|
|
47
|
+
now: options.timers?.now ?? REAL_TIMER_DEPS.now,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/** Mint a listenKey and start the refresh loop. Returns the minted key.
|
|
51
|
+
* Throws if the first POST fails — caller decides how to back off. */
|
|
52
|
+
async start() {
|
|
53
|
+
if (this.running) {
|
|
54
|
+
throw new Error('ListenKeyManager already started');
|
|
55
|
+
}
|
|
56
|
+
const key = await this.api.createListenKey();
|
|
57
|
+
this.currentKey = key;
|
|
58
|
+
this.keyMintedAt = this.timers.now();
|
|
59
|
+
this.consecutiveFailures = 0;
|
|
60
|
+
this.running = true;
|
|
61
|
+
this.emit('keyMinted', key);
|
|
62
|
+
this.scheduleRefresh();
|
|
63
|
+
logger.info(TAG, `listenKey minted (hash=${hashKey(key)}), refresh every ${this.refreshIntervalMs / 1000}s`);
|
|
64
|
+
return key;
|
|
65
|
+
}
|
|
66
|
+
/** Stop the refresh loop and best-effort close the key. Idempotent.
|
|
67
|
+
* For GRACEFUL shutdown only — a reconnect-driven teardown must use
|
|
68
|
+
* `stopKeepAlive()` instead (see below). */
|
|
69
|
+
async stop() {
|
|
70
|
+
if (!this.running)
|
|
71
|
+
return;
|
|
72
|
+
this.running = false;
|
|
73
|
+
if (this.refreshTimer) {
|
|
74
|
+
this.timers.clearTimeout(this.refreshTimer);
|
|
75
|
+
this.refreshTimer = null;
|
|
76
|
+
}
|
|
77
|
+
if (this.currentKey) {
|
|
78
|
+
try {
|
|
79
|
+
await this.api.closeListenKey();
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
// Not worth retrying on shutdown — Binance expires idle keys anyway.
|
|
83
|
+
logger.warn(TAG, `closeListenKey failed on stop (non-fatal): ${formatError(err)}`);
|
|
84
|
+
}
|
|
85
|
+
this.currentKey = null;
|
|
86
|
+
this.keyMintedAt = null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** Stop the refresh loop WITHOUT the DELETE — for reconnect-driven closes.
|
|
90
|
+
* Binance returns the SAME active listenKey on a re-POST and merely
|
|
91
|
+
* extends its validity (doc-verified 2026-07-02: "Doing a POST on an
|
|
92
|
+
* account with an active listenKey will return the currently active
|
|
93
|
+
* listenKey and extend its validity for 60 minutes"), so an in-flight
|
|
94
|
+
* DELETE racing the reconnect's POST can land AFTER it and invalidate the
|
|
95
|
+
* key the fresh socket just authenticated with — a silent dead stream.
|
|
96
|
+
* Skipping the DELETE is safe: an unused key expires on its own after
|
|
97
|
+
* 60 min of no keep-alive. Synchronous + idempotent. */
|
|
98
|
+
stopKeepAlive() {
|
|
99
|
+
if (!this.running)
|
|
100
|
+
return;
|
|
101
|
+
this.running = false;
|
|
102
|
+
if (this.refreshTimer) {
|
|
103
|
+
this.timers.clearTimeout(this.refreshTimer);
|
|
104
|
+
this.refreshTimer = null;
|
|
105
|
+
}
|
|
106
|
+
this.currentKey = null;
|
|
107
|
+
this.keyMintedAt = null;
|
|
108
|
+
}
|
|
109
|
+
/** Current listenKey, or null if stopped. */
|
|
110
|
+
getKey() {
|
|
111
|
+
return this.currentKey;
|
|
112
|
+
}
|
|
113
|
+
/** Age in ms since the key was last minted. Null if stopped. Useful for
|
|
114
|
+
* observability dashboards — a key far beyond refreshIntervalMs but still
|
|
115
|
+
* alive means Binance is tolerating us past the nominal window. */
|
|
116
|
+
getKeyAge() {
|
|
117
|
+
if (this.keyMintedAt == null)
|
|
118
|
+
return null;
|
|
119
|
+
return this.timers.now() - this.keyMintedAt;
|
|
120
|
+
}
|
|
121
|
+
/** Number of consecutive failed keep-alive probes. Exposed for diagnostics. */
|
|
122
|
+
getConsecutiveFailures() {
|
|
123
|
+
return this.consecutiveFailures;
|
|
124
|
+
}
|
|
125
|
+
// ---- Internal ----
|
|
126
|
+
scheduleRefresh() {
|
|
127
|
+
if (!this.running)
|
|
128
|
+
return;
|
|
129
|
+
this.refreshTimer = this.timers.setTimeout(() => {
|
|
130
|
+
this.refreshTimer = null;
|
|
131
|
+
void this.refresh();
|
|
132
|
+
}, this.refreshIntervalMs);
|
|
133
|
+
}
|
|
134
|
+
async refresh() {
|
|
135
|
+
if (!this.running)
|
|
136
|
+
return;
|
|
137
|
+
try {
|
|
138
|
+
await this.api.keepAliveListenKey();
|
|
139
|
+
this.consecutiveFailures = 0;
|
|
140
|
+
this.emit('keyRefreshed');
|
|
141
|
+
logger.info(TAG, `listenKey refreshed (age=${Math.round((this.getKeyAge() ?? 0) / 1000)}s)`);
|
|
142
|
+
this.scheduleRefresh();
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
this.consecutiveFailures += 1;
|
|
146
|
+
const reason = formatError(err);
|
|
147
|
+
if (this.consecutiveFailures >= this.maxConsecutiveFailures) {
|
|
148
|
+
// Stream is dead. Don't reschedule — parent will restart us.
|
|
149
|
+
logger.error(TAG, `listenKey keep-alive failed ${this.consecutiveFailures} times (last: ${reason}) — giving up`);
|
|
150
|
+
this.running = false;
|
|
151
|
+
if (this.refreshTimer) {
|
|
152
|
+
this.timers.clearTimeout(this.refreshTimer);
|
|
153
|
+
this.refreshTimer = null;
|
|
154
|
+
}
|
|
155
|
+
this.emit('keyKeepAliveFailed', reason);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
// Transient — log and retry on the normal cadence. We deliberately do
|
|
159
|
+
// NOT shrink the interval on failure; the keep-alive window is 60 min
|
|
160
|
+
// so we can afford up to 2 more tries before the key expires.
|
|
161
|
+
logger.warn(TAG, `listenKey keep-alive failed (${this.consecutiveFailures}/${this.maxConsecutiveFailures}): ${reason}`);
|
|
162
|
+
this.scheduleRefresh();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/** First 8 chars of a listenKey for log correlation without leaking the key. */
|
|
167
|
+
function hashKey(key) {
|
|
168
|
+
return key.length > 8 ? key.slice(0, 8) : '(short)';
|
|
169
|
+
}
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import type { IExchangeAdapter, AdapterReadiness, OrderOptions } from '../exchange-adapter.js';
|
|
3
|
+
import { BinancePrivateApi } from '../ccxt/binance-private.js';
|
|
4
|
+
import type { CcxtOrder, CcxtBalance, CcxtPosition, TradingMode, ExchangeConfig } from '../types.js';
|
|
5
|
+
import type { PositionMetadata, CloseReason } from '../simulator/types.js';
|
|
6
|
+
import { ExchangeInfoCache } from './exchange-info-cache.js';
|
|
7
|
+
import { BinanceRateLimiter } from './rate-limiter.js';
|
|
8
|
+
import { IntentJournal } from './intent-journal.js';
|
|
9
|
+
import { OrderPoller } from './order-poller.js';
|
|
10
|
+
import { SlippageTracker } from './slippage-tracker.js';
|
|
11
|
+
import { PositionReconciler } from './reconciler.js';
|
|
12
|
+
import { LiveBalanceEnricher } from './live-balance-enricher.js';
|
|
13
|
+
import { DepositTracker } from './deposit-tracker.js';
|
|
14
|
+
import { BracketLedger } from './bracket-ledger.js';
|
|
15
|
+
import { BracketManager } from './bracket-manager.js';
|
|
16
|
+
import { type BracketMode } from '../config/brackets-config.js';
|
|
17
|
+
import { type UserDataStreamMode, type UserDataStreamTunables } from '../config/user-data-stream-config.js';
|
|
18
|
+
import { UserDataStreamController } from './user-data-stream-controller.js';
|
|
19
|
+
import type { AutoCaptureContext } from '../ingest/position-auto-capture.js';
|
|
20
|
+
import type { TradeStoreClient } from '../ingest/trade-store-client.js';
|
|
21
|
+
/** Optional audit-trail wiring (TRADE_AUDIT_TRAIL_PLAN Phase 1). Caller
|
|
22
|
+
* passes this only when userDataStream.dbWrite='on' AND the WEBAPP_INGEST_TOKEN
|
|
23
|
+
* + REEFCLAW_USER_ID env vars are present. Forwarded into the controller
|
|
24
|
+
* which spins up a WsIngest alongside the existing read path. */
|
|
25
|
+
export interface TradeIngestWiring {
|
|
26
|
+
client: TradeStoreClient;
|
|
27
|
+
userId: string;
|
|
28
|
+
exchange?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Backfill `balance.free[cur] = total[cur]` for currencies where Binance's CCXT
|
|
32
|
+
* response left the per-currency `free` and `used` at zero despite a non-zero
|
|
33
|
+
* total. Only safe when `used` is zero — otherwise the exchange really is
|
|
34
|
+
* reserving margin and we must not inflate availability.
|
|
35
|
+
*/
|
|
36
|
+
export declare function repairFreeFromTotal(balance: CcxtBalance): void;
|
|
37
|
+
export declare class LiveAdapter extends EventEmitter implements IExchangeAdapter {
|
|
38
|
+
readonly mode: TradingMode;
|
|
39
|
+
readonly isLive = true;
|
|
40
|
+
private api;
|
|
41
|
+
private sizeCapMultiplier;
|
|
42
|
+
private maxPositionUSDT;
|
|
43
|
+
private exchangeInfo;
|
|
44
|
+
private isHedgeMode;
|
|
45
|
+
private getOpenOrdersUnavailableUntil;
|
|
46
|
+
private static readonly OPEN_ORDERS_RL_COOLDOWN_MS;
|
|
47
|
+
private rateLimiter;
|
|
48
|
+
private intentJournal;
|
|
49
|
+
private orderPoller;
|
|
50
|
+
private slippageTracker;
|
|
51
|
+
private reconciler;
|
|
52
|
+
private enricher;
|
|
53
|
+
private depositTracker;
|
|
54
|
+
private readonly bracketMode;
|
|
55
|
+
private bracketLedger;
|
|
56
|
+
private bracketManager;
|
|
57
|
+
private bracketReconciler;
|
|
58
|
+
private readonly userDataStreamMode;
|
|
59
|
+
private userDataStream;
|
|
60
|
+
private readonly wsAlgoStatusByCid;
|
|
61
|
+
private static readonly WS_ALGO_STATUS_CAP;
|
|
62
|
+
private static readonly WS_LIVE_LEG_MAX_AGE_MS;
|
|
63
|
+
private _sessionStartNav;
|
|
64
|
+
private lastIncomeRefreshMs;
|
|
65
|
+
private incomeAnchorUtcDay;
|
|
66
|
+
private liveMetadata;
|
|
67
|
+
private _readiness;
|
|
68
|
+
get readiness(): AdapterReadiness;
|
|
69
|
+
/** Session-start NAV, captured once at initialization. Used for drawdown calculation. */
|
|
70
|
+
getSessionStartNav(): number | null;
|
|
71
|
+
constructor(config: ExchangeConfig, mode: 'MICRO_LIVE' | 'LIVE', microLiveConfig?: {
|
|
72
|
+
sizeCapPercent?: number;
|
|
73
|
+
maxPositionUSDT?: number;
|
|
74
|
+
}, bracketMode?: BracketMode, userDataStreamMode?: UserDataStreamMode, userDataStreamTunables?: UserDataStreamTunables,
|
|
75
|
+
/** TRADE_AUDIT_TRAIL_PLAN Phase 1 — optional audit-trail wiring. Wired
|
|
76
|
+
* through to UserDataStreamController. Absent today on every existing
|
|
77
|
+
* call site (default off); operator-driven once activation is approved. */
|
|
78
|
+
tradeIngest?: TradeIngestWiring,
|
|
79
|
+
/** Position-decision auto-capture wiring. When provided alongside
|
|
80
|
+
* tradeIngest, ws-ingest also routes every TRADE event through
|
|
81
|
+
* `onWsFillObserved` to capture limit-order entries + scale-ins
|
|
82
|
+
* (PR1 deferral resolution, 2026-05-03). Optional for back-compat. */
|
|
83
|
+
autoCapture?: AutoCaptureContext);
|
|
84
|
+
/** Get the underlying BinancePrivateApi (for advanced queries like fetchTicker). */
|
|
85
|
+
getApi(): BinancePrivateApi;
|
|
86
|
+
/** Get the exchange info cache (for symbol rules). */
|
|
87
|
+
getExchangeInfo(): ExchangeInfoCache;
|
|
88
|
+
/** Whether the account is in hedge mode. */
|
|
89
|
+
getIsHedgeMode(): boolean;
|
|
90
|
+
/** Get safety modules for external access (dashboard, tools, etc.). */
|
|
91
|
+
getRateLimiter(): BinanceRateLimiter;
|
|
92
|
+
getIntentJournal(): IntentJournal;
|
|
93
|
+
getOrderPoller(): OrderPoller;
|
|
94
|
+
getSlippageTracker(): SlippageTracker;
|
|
95
|
+
getReconciler(): PositionReconciler;
|
|
96
|
+
getEnricher(): LiveBalanceEnricher;
|
|
97
|
+
getDepositTracker(): DepositTracker;
|
|
98
|
+
/** Active user-data-stream mode. `'off'` when the feature flag is disabled. */
|
|
99
|
+
getUserDataStreamMode(): UserDataStreamMode;
|
|
100
|
+
/** User-data stream controller, or null if mode='off'. Used by dashboards
|
|
101
|
+
* and diagnostic tools to read the live-state store + health. */
|
|
102
|
+
getUserDataStream(): UserDataStreamController | null;
|
|
103
|
+
/**
|
|
104
|
+
* Post-registration async initialization.
|
|
105
|
+
* Must complete before create_order is allowed (readiness gate).
|
|
106
|
+
* Emergency controls (cancel, close) work regardless of readiness.
|
|
107
|
+
*/
|
|
108
|
+
initialize(): Promise<void>;
|
|
109
|
+
/**
|
|
110
|
+
* Acknowledge existing positions on startup.
|
|
111
|
+
* Transitions DEGRADED → READY. Exchange info + position mode are already loaded
|
|
112
|
+
* (they're loaded before the position check in initialize()).
|
|
113
|
+
*/
|
|
114
|
+
acknowledgePositions(): Promise<void>;
|
|
115
|
+
/**
|
|
116
|
+
* Tear down background loops so the adapter can be replaced at runtime
|
|
117
|
+
* (e.g. when the operator changes credentials or trading mode from the
|
|
118
|
+
* dashboard). Must be called before discarding the LiveAdapter reference
|
|
119
|
+
* or the poller + reconciler timers will keep firing against stale state.
|
|
120
|
+
*
|
|
121
|
+
* Idempotent — safe to call multiple times.
|
|
122
|
+
*/
|
|
123
|
+
shutdown(): void;
|
|
124
|
+
createOrder(symbol: string, side: 'buy' | 'sell', type: 'market' | 'limit', amount: number, price?: number, metadata?: PositionMetadata, options?: OrderOptions): Promise<CcxtOrder>;
|
|
125
|
+
/**
|
|
126
|
+
* Attach brackets in the background. Auto-flattens on failure per locked
|
|
127
|
+
* decision #2. Never throws — errors are surfaced via emitted events and
|
|
128
|
+
* the subsequent flatten.
|
|
129
|
+
*/
|
|
130
|
+
private attachBracketsAsync;
|
|
131
|
+
/**
|
|
132
|
+
* AUTHORITATIVE bracket-lifecycle handler — Binance's ALGO_UPDATE push.
|
|
133
|
+
*
|
|
134
|
+
* Why this exists (2026-05-15 RCA, doc-verified): pre-fix the plugin
|
|
135
|
+
* learned bracket state by REST-polling `audit_bracket_protection` /
|
|
136
|
+
* `fetchOpenOrders` and *guessing* — under a 429 storm that produced the
|
|
137
|
+
* audit→re-attach→cancel spiral that flushed live positions. Binance
|
|
138
|
+
* already PUSHES authoritative conditional-order lifecycle. Doc-exact
|
|
139
|
+
* status semantics (developers.binance.com → Event Algo Order Update):
|
|
140
|
+
*
|
|
141
|
+
* EXPIRED = SYSTEM cancel. The canonical trigger is "GTE_GTC
|
|
142
|
+
* conditional + position closed → Binance auto-cancels the
|
|
143
|
+
* surviving sibling". So EXPIRED on our bracket cid ⇒ the
|
|
144
|
+
* position just closed by a non-close_position path (bracket
|
|
145
|
+
* fill, manual, opposite-side). EXPECTED — not a fault.
|
|
146
|
+
* TRIGGERED / FINISHED = the bracket fired (SL/TP hit) → position closed.
|
|
147
|
+
* CANCELED = MANUAL cancel (an explicit cancelOrder from us). Post the
|
|
148
|
+
* bracket-reconciler fix we should NOT be doing this while a
|
|
149
|
+
* position is open; if we see it, it's the canary that some
|
|
150
|
+
* *other* path still strips protection — WARN loudly.
|
|
151
|
+
*
|
|
152
|
+
* For EXPIRED/TRIGGERED/FINISHED we (a) mark the ledger terminal so the
|
|
153
|
+
* attach-brackets re-attach loop STOPS chasing a bracket Binance already
|
|
154
|
+
* removed, and (b) emit the SAME `drift_detected` shape the position
|
|
155
|
+
* reconciler emits, so the existing, tested close-bypass cleanup
|
|
156
|
+
* (`onReconcilerObservedClose` in index.ts) runs immediately instead of
|
|
157
|
+
* up to 60 s later — which is what clears the stale state-store entry and
|
|
158
|
+
* stops the NEXT entry on the symbol being mis-classified as a scale-in
|
|
159
|
+
* (the bug that left fresh positions naked). No auto-flatten here: that
|
|
160
|
+
* stays deferred until this signal has soaked.
|
|
161
|
+
*/
|
|
162
|
+
private onAlgoUpdate;
|
|
163
|
+
/** Expose the bracket manager for agent-facing tools (modify_stop, etc.).
|
|
164
|
+
* Returns null when bracket mode is 'off'. */
|
|
165
|
+
getBracketManager(): BracketManager | null;
|
|
166
|
+
/** Expose the bracket ledger for reconciliation + admin queries. */
|
|
167
|
+
getBracketLedger(): BracketLedger | null;
|
|
168
|
+
/** Is the user-data WS store currently trusted (seeded + fresh + no gap)?
|
|
169
|
+
* The Tier-1 gate for resolveBracketLegLiveness — when false the WS
|
|
170
|
+
* per-cid signal is NOT consulted (a stale/gapped stream that missed a
|
|
171
|
+
* CANCELED would otherwise yield a false 'live' on a naked leg — the exact
|
|
172
|
+
* flaw the layered design exists to prevent). Null stream (mode=off) ⇒
|
|
173
|
+
* never trusted ⇒ always the REST authority. */
|
|
174
|
+
isUserDataStoreTrusted(): boolean;
|
|
175
|
+
/** Authoritative per-bracket-leg liveness — the Phase 2 disambiguator that
|
|
176
|
+
* replaces inferring presence/absence from a broad openOrders snapshot
|
|
177
|
+
* (the SOL/INJ spiral root: a *successful* empty /fapi/v1/openAlgoOrders
|
|
178
|
+
* is NOT proof a leg is gone).
|
|
179
|
+
*
|
|
180
|
+
* Precedence (the agreed layering):
|
|
181
|
+
* 1. WS fast-path — ONLY behind isUserDataStoreTrusted(): the real
|
|
182
|
+
* per-cid ALGO_UPDATE status (incl. CANCELED, which the ledger does
|
|
183
|
+
* NOT record). Zero weight, sub-second. No record for the cid ⇒ no
|
|
184
|
+
* WS opinion ⇒ fall through (never infer from absence).
|
|
185
|
+
* 2. REST authority — queryAlgoOrderStatus(cid): a DIRECT weight-1
|
|
186
|
+
* question about that exact order id. Used when WS is untrusted or
|
|
187
|
+
* silent on the cid.
|
|
188
|
+
* 3. 'unknown' — both unavailable. The d59e51b safe floor: callers MUST
|
|
189
|
+
* refuse destructive action and retry; NEVER treat 'unknown' as
|
|
190
|
+
* 'terminal'/'stale'.
|
|
191
|
+
*
|
|
192
|
+
* 'live' = leg is on the exchange (do NOT reattach/clobber).
|
|
193
|
+
* 'terminal' = positively confirmed gone (CANCELED/EXPIRED/REJECTED) or
|
|
194
|
+
* fired (TRIGGERED/FINISHED) — only this licenses repair.
|
|
195
|
+
* 'unknown' = could not get an answer — safe-wait. */
|
|
196
|
+
resolveBracketLegLiveness(cid: string): Promise<'live' | 'terminal' | 'unknown'>;
|
|
197
|
+
/** Symbol-scoped generalization of the trusted-WS fast-path — the
|
|
198
|
+
* authoritative action-layer guard for the 2026-05-16 INJ bracket spiral.
|
|
199
|
+
*
|
|
200
|
+
* `resolveBracketLegLiveness(cid)` answers about ONE cid. The spiral is:
|
|
201
|
+
* a prior `attach_brackets` reattach placed a FRESH bracket that is live
|
|
202
|
+
* on the exchange under a NEW cid, while the ledger row still holds the
|
|
203
|
+
* PREVIOUS, genuinely-terminal cids. Classifying only the ledger's cids
|
|
204
|
+
* yields a false 'stale' → clear+reattach cancels the live fresh bracket
|
|
205
|
+
* → naked → audit unprotected → attach → spiral (prod: INJ/USDT cancelled
|
|
206
|
+
* every ~15-40s for hours). This asks the question the ledger cids can't:
|
|
207
|
+
* "is ANY rc-* bracket leg for this symbol live RIGHT NOW, under any cid?"
|
|
208
|
+
*
|
|
209
|
+
* Trust model (identical to resolveBracketLegLiveness Tier-1): the WS map
|
|
210
|
+
* is consulted ONLY when `isUserDataStoreTrusted()` (seeded + fresh +
|
|
211
|
+
* no-gap — the property that guarantees no missed CANCELED, so a record
|
|
212
|
+
* reading 'live' really is live). When the store is NOT trusted this
|
|
213
|
+
* returns `{ trusted:false, liveCids:[] }` and the caller must NOT infer
|
|
214
|
+
* "no live leg" from it — it falls back to the per-leg REST authority and,
|
|
215
|
+
* failing that, refuses the destructive action (the d59e51b safe floor).
|
|
216
|
+
* A record older than WS_LIVE_LEG_MAX_AGE_MS is ignored (caller falls back
|
|
217
|
+
* too) so a stale 'live' can never suppress a genuine repair forever. */
|
|
218
|
+
findTrustedLiveBracketCidsForSymbol(symbol: string): {
|
|
219
|
+
trusted: boolean;
|
|
220
|
+
liveCids: string[];
|
|
221
|
+
};
|
|
222
|
+
/** Cancel every bracket-tagged (SL or TP) open order for a symbol. Used by
|
|
223
|
+
* the `attach_brackets` recovery tool to clear stale bracket orders before
|
|
224
|
+
* re-attaching a fresh pair. Does not touch non-bracket orders. Returns
|
|
225
|
+
* the number successfully cancelled. Errors are logged + swallowed —
|
|
226
|
+
* "already gone" is treated as success by the underlying cancel path. */
|
|
227
|
+
cancelSymbolBracketOrders(symbol: string): Promise<number>;
|
|
228
|
+
cancelOrder(orderId: string, symbol?: string): Promise<CcxtOrder>;
|
|
229
|
+
cancelAllOrders(symbol?: string): Promise<CcxtOrder[]>;
|
|
230
|
+
closePosition(symbol: string, closeReason?: CloseReason): Promise<CcxtOrder>;
|
|
231
|
+
/** Re-arm protection on a position whose closePosition flow cancelled the
|
|
232
|
+
* brackets and then failed every market-close attempt. Reuses the normal
|
|
233
|
+
* attach machinery: re-register the ledger row (terminal row → fresh
|
|
234
|
+
* pending_entry with the SAME stop/target levels) and run the standard
|
|
235
|
+
* 3-retry attach. Never throws — this runs on the already-failing close
|
|
236
|
+
* path; on any failure it emits the reconciler's `position_unprotected`
|
|
237
|
+
* drift shape (re-emitted upstream as `bracket_drift`) plus a loud log so
|
|
238
|
+
* the operator knows re-protection is required. */
|
|
239
|
+
private reattachBracketsAfterFailedClose;
|
|
240
|
+
getBalance(): Promise<CcxtBalance>;
|
|
241
|
+
/** Re-anchor the realized-today seed + sessionStartNav from /fapi/v1/income.
|
|
242
|
+
* Throttled to {@link INCOME_REFRESH_MIN_INTERVAL_MS}; UTC date rollover
|
|
243
|
+
* forces an immediate refresh. Best-effort — failures are logged and
|
|
244
|
+
* swallowed so a transient income-endpoint blip never blocks a balance
|
|
245
|
+
* read. Called from getBalance() with the fresh quote wallet so we don't
|
|
246
|
+
* fetch balance twice.
|
|
247
|
+
*/
|
|
248
|
+
private refreshIncomeAnchor;
|
|
249
|
+
getPositions(symbol?: string): Promise<CcxtPosition[]>;
|
|
250
|
+
getPositionsOrNull(symbol?: string): Promise<CcxtPosition[] | null>;
|
|
251
|
+
/** Merge agent-supplied entry metadata + ratchet MFE state into the raw
|
|
252
|
+
* CCXT position list. Side effect: drops metadata for symbols no longer
|
|
253
|
+
* in the open-positions snapshot (only when called without a symbol filter
|
|
254
|
+
* — symbol-scoped calls skip cleanup so we don't lose context for other
|
|
255
|
+
* open positions). */
|
|
256
|
+
private decoratePositionsWithMetadata;
|
|
257
|
+
getOpenOrders(symbol?: string): Promise<CcxtOrder[]>;
|
|
258
|
+
fetchOrder(orderId: string, symbol?: string): Promise<CcxtOrder | null>;
|
|
259
|
+
getLastPrice(symbol: string): Promise<number | null>;
|
|
260
|
+
/** Sync rate limiter from exchange response headers after every private API call. */
|
|
261
|
+
private syncRateLimits;
|
|
262
|
+
private loadExchangeInfo;
|
|
263
|
+
private detectPositionMode;
|
|
264
|
+
}
|