@reefclaw/openclaw-plugin 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/bridge/gateway/event-parser.d.ts +6 -1
  2. package/bridge/gateway/event-parser.js +19 -2
  3. package/bridge/gateway/poller.d.ts +1 -0
  4. package/bridge/gateway/poller.js +14 -2
  5. package/bridge/providers/gateway.d.ts +22 -2
  6. package/bridge/providers/gateway.js +67 -9
  7. package/ccxt/binance-private.d.ts +21 -0
  8. package/ccxt/binance-private.js +132 -22
  9. package/ccxt/public-market-data-api.d.ts +14 -0
  10. package/ccxt/public-market-data-api.js +15 -1
  11. package/config/plugin-config-io.d.ts +13 -0
  12. package/config/plugin-config-io.js +15 -0
  13. package/config/tool-gate.js +3 -0
  14. package/exchange-adapter.d.ts +16 -0
  15. package/index.js +658 -83
  16. package/ingest/position-auto-capture.d.ts +68 -0
  17. package/ingest/position-auto-capture.js +321 -23
  18. package/ingest/position-decisions-client.d.ts +7 -2
  19. package/ingest/position-decisions-client.js +13 -3
  20. package/ingest/reconcile-db-vs-exchange.d.ts +39 -1
  21. package/ingest/reconcile-db-vs-exchange.js +66 -10
  22. package/lifecycle/trading-operation-lock.d.ts +17 -0
  23. package/lifecycle/trading-operation-lock.js +14 -0
  24. package/live/bracket-id.d.ts +2 -3
  25. package/live/bracket-id.js +22 -9
  26. package/live/fill-price.d.ts +13 -0
  27. package/live/fill-price.js +37 -0
  28. package/live/live-adapter.d.ts +57 -2
  29. package/live/live-adapter.js +290 -49
  30. package/live/local-signal-service.js +11 -6
  31. package/live/local-strategy-evaluator.js +4 -0
  32. package/live/position-state-store.d.ts +4 -0
  33. package/live/proposal-decision-listener.d.ts +6 -0
  34. package/live/proposal-decision-listener.js +4 -0
  35. package/live/stop-watcher.d.ts +35 -2
  36. package/live/stop-watcher.js +63 -3
  37. package/onboarding/runtime.d.ts +19 -0
  38. package/onboarding/runtime.js +34 -3
  39. package/openclaw.plugin.json +1 -0
  40. package/package.json +2 -2
  41. package/portfolio/reentry-tracker.d.ts +36 -0
  42. package/portfolio/reentry-tracker.js +127 -0
  43. package/portfolio/wave9-admission.d.ts +67 -0
  44. package/portfolio/wave9-admission.js +262 -0
  45. package/portfolio/wave9-policy.d.ts +36 -0
  46. package/portfolio/wave9-policy.js +183 -0
  47. package/signals/conditions/registry.js +61 -2
  48. package/signals/strategy-adapter.js +17 -7
  49. package/simulator/exchange-simulator.d.ts +12 -0
  50. package/simulator/exchange-simulator.js +78 -3
  51. package/simulator/fill-engine.js +5 -1
  52. package/simulator/types.d.ts +10 -1
  53. package/skills/reefclaw/SKILL.md +2 -0
  54. package/strategy/evaluator.d.ts +3 -0
  55. package/strategy/evaluator.js +5 -0
  56. package/tools/assessment-validation.d.ts +23 -0
  57. package/tools/assessment-validation.js +58 -0
  58. package/tools/attach-brackets.d.ts +7 -2
  59. package/tools/attach-brackets.js +201 -0
  60. package/tools/audit-bracket-protection.js +157 -1
  61. package/tools/bracket-control.d.ts +12 -0
  62. package/tools/bracket-control.js +35 -0
  63. package/tools/cancel-all-orders.d.ts +2 -0
  64. package/tools/cancel-all-orders.js +4 -1
  65. package/tools/cancel-order.d.ts +4 -0
  66. package/tools/cancel-order.js +49 -3
  67. package/tools/close-position.d.ts +23 -0
  68. package/tools/close-position.js +286 -13
  69. package/tools/create-order.d.ts +28 -0
  70. package/tools/create-order.js +1390 -190
  71. package/tools/get-analytics.js +2 -2
  72. package/tools/get-basis.js +2 -2
  73. package/tools/get-cascade-risk.js +2 -2
  74. package/tools/get-crypto-metrics.js +14 -4
  75. package/tools/get-cvd.js +2 -2
  76. package/tools/get-divergences.js +2 -2
  77. package/tools/get-funding-context.js +2 -2
  78. package/tools/get-liquidation-levels.js +2 -2
  79. package/tools/get-liquidation-pulse.js +2 -2
  80. package/tools/get-pattern-scan.js +2 -2
  81. package/tools/get-regime.js +2 -2
  82. package/tools/get-resting-liquidity.js +2 -2
  83. package/tools/get-risk-scenario.js +2 -2
  84. package/tools/get-session-review.js +2 -2
  85. package/tools/get-setup-detail.js +21 -2
  86. package/tools/get-signals.js +2 -2
  87. package/tools/get-sizing.js +2 -2
  88. package/tools/get-trade-feedback.js +2 -2
  89. package/tools/get-trade-flow.js +2 -2
  90. package/tools/get-volume-profile.js +2 -2
  91. package/tools/get-wave9-status.d.ts +127 -0
  92. package/tools/get-wave9-status.js +796 -0
  93. package/tools/intel-api.d.ts +20 -0
  94. package/tools/intel-api.js +67 -0
  95. package/tools/intel-cache.d.ts +1 -1
  96. package/tools/intel-cache.js +20 -5
  97. package/tools/list-strategies.d.ts +11 -1
  98. package/tools/list-strategies.js +17 -0
  99. package/tools/modify-stop.d.ts +4 -0
  100. package/tools/modify-stop.js +63 -24
  101. package/tools/modify-target.d.ts +4 -0
  102. package/tools/modify-target.js +62 -23
  103. package/tools/scan-pairs.d.ts +4 -0
  104. package/tools/scan-pairs.js +22 -8
  105. package/tools/toggle-strategy.js +7 -0
  106. package/types.d.ts +5 -0
  107. package/venues/hyperliquid/hl-balance.d.ts +116 -0
  108. package/venues/hyperliquid/hl-balance.js +145 -0
  109. package/venues/hyperliquid/hl-bracket-coordinator.d.ts +123 -0
  110. package/venues/hyperliquid/hl-bracket-coordinator.js +533 -0
  111. package/venues/hyperliquid/hl-brackets.d.ts +102 -0
  112. package/venues/hyperliquid/hl-brackets.js +172 -0
  113. package/venues/hyperliquid/hl-cloid.d.ts +22 -0
  114. package/venues/hyperliquid/hl-cloid.js +82 -0
  115. package/venues/hyperliquid/hl-info-cache.d.ts +46 -0
  116. package/venues/hyperliquid/hl-info-cache.js +125 -0
  117. package/venues/hyperliquid/hl-live-adapter.d.ts +146 -0
  118. package/venues/hyperliquid/hl-live-adapter.js +728 -0
  119. package/venues/hyperliquid/hl-precision.d.ts +61 -0
  120. package/venues/hyperliquid/hl-precision.js +176 -0
  121. package/venues/hyperliquid/hl-private.d.ts +88 -0
  122. package/venues/hyperliquid/hl-private.js +357 -0
  123. package/venues/hyperliquid/hl-public.d.ts +31 -4
  124. package/venues/hyperliquid/hl-public.js +163 -12
  125. package/venues/hyperliquid/hl-rate-gate.d.ts +57 -0
  126. package/venues/hyperliquid/hl-rate-gate.js +220 -0
  127. package/venues/hyperliquid/hl-user-stream.d.ts +90 -0
  128. package/venues/hyperliquid/hl-user-stream.js +220 -0
  129. package/venues/registry.d.ts +23 -9
  130. package/venues/registry.js +12 -13
  131. package/venues/symbols.d.ts +43 -0
  132. package/venues/symbols.js +107 -0
  133. package/wave9/live-account-capture.d.ts +67 -0
  134. package/wave9/live-account-capture.js +435 -0
  135. package/wave9/live-autonomous-protection.d.ts +39 -0
  136. package/wave9/live-autonomous-protection.js +112 -0
  137. package/wave9/live-durable-reconciliation-scheduler.d.ts +33 -0
  138. package/wave9/live-durable-reconciliation-scheduler.js +115 -0
  139. package/wave9/live-execution-ledger.d.ts +107 -0
  140. package/wave9/live-execution-ledger.js +498 -0
  141. package/wave9/live-position-confirmation.d.ts +18 -0
  142. package/wave9/live-position-confirmation.js +111 -0
  143. package/wave9/live-residual-protection.d.ts +18 -0
  144. package/wave9/live-residual-protection.js +250 -0
  145. package/wave9/live-startup-reconciliation.d.ts +38 -0
  146. package/wave9/live-startup-reconciliation.js +454 -0
  147. package/wave9/live-symbol-ownership.d.ts +20 -0
  148. package/wave9/live-symbol-ownership.js +132 -0
  149. package/wave9/paper-admission-guard.d.ts +199 -0
  150. package/wave9/paper-admission-guard.js +650 -0
  151. package/wave9/usdm-evidence-provider.d.ts +42 -0
  152. package/wave9/usdm-evidence-provider.js +133 -0
@@ -0,0 +1,116 @@
1
+ import type { CcxtBalance } from '../../types.js';
2
+ import type { CloseReason } from '../../simulator/types.js';
3
+ export interface HlClearinghouseState {
4
+ marginSummary?: {
5
+ accountValue?: string | number;
6
+ totalMarginUsed?: string | number;
7
+ totalNtlPos?: string | number;
8
+ };
9
+ withdrawable?: string | number;
10
+ assetPositions?: Array<{
11
+ position?: {
12
+ coin?: string;
13
+ szi?: string | number;
14
+ entryPx?: string | number;
15
+ unrealizedPnl?: string | number;
16
+ positionValue?: string | number;
17
+ liquidationPx?: string | number;
18
+ marginUsed?: string | number;
19
+ };
20
+ }>;
21
+ }
22
+ export interface HlNav {
23
+ /** accountValue — what the HL app's portfolio panel shows. */
24
+ equity: number;
25
+ /** equity − Σ uPnl. The Binance "wallet"/margin-balance analog. */
26
+ wallet: number;
27
+ totalUnrealizedPnl: number;
28
+ /** Free collateral (HL `withdrawable`). */
29
+ available: number;
30
+ }
31
+ /** Derive NAV/wallet from a clearinghouseState payload.
32
+ *
33
+ * ★ Returns null when the payload is UNREADABLE — never a zeroed NAV. A phantom
34
+ * "$0 equity" would trip risk limits and look like a catastrophic loss; null
35
+ * means "unknown", which the caller must refuse to act on (null ≠ empty). */
36
+ export declare function deriveHlNav(state: HlClearinghouseState | null | undefined): HlNav | null;
37
+ /** CcxtBalance shape the rest of the plugin (KPI strip, sizing, LiveBalanceEnricher)
38
+ * already consumes. USDC is HL's settlement asset. */
39
+ export declare function toCcxtBalance(nav: HlNav): CcxtBalance;
40
+ export interface HlFillForAnchor {
41
+ time: number;
42
+ closedPnl?: string | number;
43
+ fee?: string | number;
44
+ builderFee?: string | number;
45
+ }
46
+ export interface HlFundingForAnchor {
47
+ time: number;
48
+ /** HL funding deltas are signed USDC (negative = paid). */
49
+ usdc?: string | number;
50
+ delta?: {
51
+ usdc?: string | number;
52
+ };
53
+ }
54
+ /** Σ(closedPnl − fee − builderFee) + Σ funding, over rows at/after `sinceMs`.
55
+ *
56
+ * This is the exact analog of Binance's `netNonTransfer` (REALIZED_PNL +
57
+ * COMMISSION + FUNDING_FEE), and — critically — it is NET of fees. The Binance
58
+ * lesson (the ledger was systematically gross, causing a visible KPI gap) applies
59
+ * verbatim: a gross anchor WILL disagree with the HL app. */
60
+ export declare function computeNetNonTransfer(args: {
61
+ fills: HlFillForAnchor[];
62
+ fundings: HlFundingForAnchor[];
63
+ sinceMs: number;
64
+ }): {
65
+ netNonTransfer: number;
66
+ realizedPnlGross: number;
67
+ fees: number;
68
+ funding: number;
69
+ };
70
+ /** UTC-midnight epoch ms for a given instant (the Day-P&L boundary). */
71
+ export declare function utcMidnightMs(now?: number): number;
72
+ /** sessionStartNav = wallet_now − netNonTransfer_since_midnight.
73
+ * dayPnl = NAV − sessionStartNav (computed by the caller each tick). */
74
+ export declare function deriveSessionStartNav(args: {
75
+ walletNow: number;
76
+ netNonTransfer: number;
77
+ }): number;
78
+ /** A capital flow (deposit / withdraw / internal transfer) changes the wallet
79
+ * WITHOUT being trading P&L — bump the anchor by the same signed amount so it
80
+ * never shows up as Day-P&L (the DepositTracker rule).
81
+ *
82
+ * T-3 note: the `delta.type` enum is OPEN (docs incomplete; only
83
+ * `internalTransfer` observed so far). We therefore treat any ledger row that
84
+ * carries a usdc delta as a capital flow rather than switch on a closed set — an
85
+ * UNKNOWN type must never be silently dropped, or the anchor drifts. */
86
+ export declare function applyLedgerDelta(args: {
87
+ sessionStartNav: number;
88
+ ledgerRows: Array<{
89
+ time: number;
90
+ delta?: {
91
+ usdc?: string | number;
92
+ type?: string;
93
+ };
94
+ }>;
95
+ sinceMs: number;
96
+ seenHashes?: Set<string>;
97
+ }): {
98
+ sessionStartNav: number;
99
+ applied: number;
100
+ };
101
+ /** ★ Close-bypass mapping (§5.9) — HL signals → journal close reasons.
102
+ *
103
+ * A position can leave our control without our close path running: a bracket
104
+ * triggering, a LIQUIDATION, an ADL, or a delisting. Each must land in the
105
+ * journal honestly (the KPI and the learning loop both read these), never as a
106
+ * silent disappearance. */
107
+ export declare function mapHlCloseReason(signal: {
108
+ /** Fill-level liquidation object (authoritative). */
109
+ liquidation?: {
110
+ method?: string;
111
+ } | null;
112
+ /** Order status from `orderUpdates`. */
113
+ orderStatus?: string;
114
+ /** Our own cloid role, when the closing order was one of our legs. */
115
+ bracketRole?: 'stop' | 'target';
116
+ }): CloseReason | 'liquidated' | 'adl' | 'venue_delisted' | null;
@@ -0,0 +1,145 @@
1
+ // Hyperliquid balance / NAV / Day-P&L anchor (plan §5.8) + close-bypass mapping
2
+ // (§5.9). Pure functions — the adapter feeds them raw HL payloads.
3
+ //
4
+ // ★ THE INVARIANT THIS FILE EXISTS TO KEEP: "KPI must equal the exchange app to
5
+ // the cent." On Binance that meant anchoring Day-P&L to the UTC-midnight income
6
+ // endpoint (a multi-dollar gap there was ALWAYS a bug, never a formula quirk).
7
+ // HL has no income endpoint, so the anchor is RECONSTRUCTED:
8
+ //
9
+ // wallet = accountValue − Σ unrealizedPnl (accountValue INCLUDES uPnl)
10
+ // NAV/equity = accountValue (so equity = wallet + Σ uPnl
11
+ // stays literally true)
12
+ // netNonTransfer(since UTC midnight)
13
+ // = Σ closedPnl − Σ fee − Σ builderFee (fills)
14
+ // + Σ funding (userFunding)
15
+ // sessionStartNav = wallet_now − netNonTransfer
16
+ // dayPnl = NAV − sessionStartNav
17
+ //
18
+ // Deposits/withdrawals/transfers are NOT trading P&L: they bump the anchor
19
+ // instead (the DepositTracker rule), via `applyLedgerDelta`.
20
+ //
21
+ // ★ FILL-HISTORY SHALLOWNESS: only the 10,000 most recent fills exist server-side
22
+ // on HL (deep history is NOT queryable). The anchor must therefore be able to
23
+ // run off WS-captured fills persisted in our own `trades` table — which is why
24
+ // the WS-first audit-trail rule is a hard prerequisite here, not hygiene.
25
+ const num = (v) => {
26
+ const n = typeof v === 'number' ? v : Number(v);
27
+ return Number.isFinite(n) ? n : 0;
28
+ };
29
+ /** Derive NAV/wallet from a clearinghouseState payload.
30
+ *
31
+ * ★ Returns null when the payload is UNREADABLE — never a zeroed NAV. A phantom
32
+ * "$0 equity" would trip risk limits and look like a catastrophic loss; null
33
+ * means "unknown", which the caller must refuse to act on (null ≠ empty). */
34
+ export function deriveHlNav(state) {
35
+ if (!state || typeof state !== 'object')
36
+ return null;
37
+ const accountValueRaw = state.marginSummary?.accountValue;
38
+ if (accountValueRaw === undefined || accountValueRaw === null)
39
+ return null;
40
+ const equity = num(accountValueRaw);
41
+ const totalUnrealizedPnl = (state.assetPositions ?? []).reduce((sum, ap) => sum + num(ap?.position?.unrealizedPnl), 0);
42
+ return {
43
+ equity,
44
+ wallet: equity - totalUnrealizedPnl,
45
+ totalUnrealizedPnl,
46
+ available: num(state.withdrawable),
47
+ };
48
+ }
49
+ /** CcxtBalance shape the rest of the plugin (KPI strip, sizing, LiveBalanceEnricher)
50
+ * already consumes. USDC is HL's settlement asset. */
51
+ export function toCcxtBalance(nav) {
52
+ const free = { USDC: nav.available };
53
+ const used = { USDC: Math.max(0, nav.wallet - nav.available) };
54
+ const total = { USDC: nav.wallet };
55
+ return {
56
+ free,
57
+ used,
58
+ total,
59
+ USDC: { free: nav.available, used: used.USDC, total: nav.wallet },
60
+ };
61
+ }
62
+ /** Σ(closedPnl − fee − builderFee) + Σ funding, over rows at/after `sinceMs`.
63
+ *
64
+ * This is the exact analog of Binance's `netNonTransfer` (REALIZED_PNL +
65
+ * COMMISSION + FUNDING_FEE), and — critically — it is NET of fees. The Binance
66
+ * lesson (the ledger was systematically gross, causing a visible KPI gap) applies
67
+ * verbatim: a gross anchor WILL disagree with the HL app. */
68
+ export function computeNetNonTransfer(args) {
69
+ let realizedPnlGross = 0;
70
+ let fees = 0;
71
+ for (const f of args.fills) {
72
+ if (!Number.isFinite(f.time) || f.time < args.sinceMs)
73
+ continue;
74
+ realizedPnlGross += num(f.closedPnl);
75
+ fees += num(f.fee) + num(f.builderFee);
76
+ }
77
+ let funding = 0;
78
+ for (const f of args.fundings) {
79
+ if (!Number.isFinite(f.time) || f.time < args.sinceMs)
80
+ continue;
81
+ funding += num(f.usdc ?? f.delta?.usdc);
82
+ }
83
+ return {
84
+ netNonTransfer: realizedPnlGross - fees + funding,
85
+ realizedPnlGross,
86
+ fees,
87
+ funding,
88
+ };
89
+ }
90
+ /** UTC-midnight epoch ms for a given instant (the Day-P&L boundary). */
91
+ export function utcMidnightMs(now = Date.now()) {
92
+ const d = new Date(now);
93
+ return Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
94
+ }
95
+ /** sessionStartNav = wallet_now − netNonTransfer_since_midnight.
96
+ * dayPnl = NAV − sessionStartNav (computed by the caller each tick). */
97
+ export function deriveSessionStartNav(args) {
98
+ return args.walletNow - args.netNonTransfer;
99
+ }
100
+ /** A capital flow (deposit / withdraw / internal transfer) changes the wallet
101
+ * WITHOUT being trading P&L — bump the anchor by the same signed amount so it
102
+ * never shows up as Day-P&L (the DepositTracker rule).
103
+ *
104
+ * T-3 note: the `delta.type` enum is OPEN (docs incomplete; only
105
+ * `internalTransfer` observed so far). We therefore treat any ledger row that
106
+ * carries a usdc delta as a capital flow rather than switch on a closed set — an
107
+ * UNKNOWN type must never be silently dropped, or the anchor drifts. */
108
+ export function applyLedgerDelta(args) {
109
+ let bump = 0;
110
+ let applied = 0;
111
+ for (const row of args.ledgerRows) {
112
+ if (!Number.isFinite(row.time) || row.time < args.sinceMs)
113
+ continue;
114
+ const usdc = num(row.delta?.usdc);
115
+ if (usdc === 0)
116
+ continue;
117
+ bump += usdc;
118
+ applied += 1;
119
+ }
120
+ return { sessionStartNav: args.sessionStartNav + bump, applied };
121
+ }
122
+ /** ★ Close-bypass mapping (§5.9) — HL signals → journal close reasons.
123
+ *
124
+ * A position can leave our control without our close path running: a bracket
125
+ * triggering, a LIQUIDATION, an ADL, or a delisting. Each must land in the
126
+ * journal honestly (the KPI and the learning loop both read these), never as a
127
+ * silent disappearance. */
128
+ export function mapHlCloseReason(signal) {
129
+ if (signal.liquidation) {
130
+ // HL marks backstop (HLP vault) liquidations distinctly from market ones; ADL
131
+ // arrives as a liquidation of the OPPOSITE side hitting us.
132
+ const method = (signal.liquidation.method ?? '').toLowerCase();
133
+ return method.includes('adl') ? 'adl' : 'liquidated';
134
+ }
135
+ const status = (signal.orderStatus ?? '').toLowerCase();
136
+ if (status === 'liquidatedcanceled')
137
+ return 'liquidated';
138
+ if (status === 'delistedcanceled')
139
+ return 'venue_delisted';
140
+ if (signal.bracketRole === 'stop')
141
+ return 'exchange_stop';
142
+ if (signal.bracketRole === 'target')
143
+ return 'exchange_target';
144
+ return null;
145
+ }
@@ -0,0 +1,123 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import type { CcxtOrder, CcxtPosition } from '../../types.js';
3
+ import type { CloseReason } from '../../simulator/types.js';
4
+ import type { BracketId, BracketRequest, BracketState } from '../../live/bracket-types.js';
5
+ import type { BracketLedger } from '../../live/bracket-ledger.js';
6
+ import type { HlOrderUpdateEvent } from './hl-user-stream.js';
7
+ /** Narrow execution surface the coordinator needs — the HyperliquidLiveAdapter
8
+ * implements it; tests mock it without a network. */
9
+ export interface HlBracketExecutor {
10
+ attachBrackets(args: {
11
+ bracketId: BracketId;
12
+ symbol: string;
13
+ positionSide: 'long' | 'short';
14
+ positionSize: number;
15
+ stopPrice?: number;
16
+ targetPrice?: number;
17
+ }): Promise<{
18
+ orders: CcxtOrder[];
19
+ slCid?: string;
20
+ tpCid?: string;
21
+ }>;
22
+ resizeBrackets(args: {
23
+ bracketId: BracketId;
24
+ symbol: string;
25
+ positionSide: 'long' | 'short';
26
+ positionSize: number;
27
+ }): Promise<{
28
+ resized: boolean;
29
+ slCid?: string;
30
+ tpCid?: string;
31
+ }>;
32
+ /** Cancel one leg by cloid. Idempotent — "already gone" must not throw. */
33
+ cancelBracketLeg(cloid: string, symbol: string): Promise<void>;
34
+ /** Coverage audit — THROWS when order state is unknown (null ≠ empty). */
35
+ auditBracketCoverage(symbol: string, positionSize: number): Promise<{
36
+ covered: boolean;
37
+ shortfall: {
38
+ stop: number;
39
+ target: number;
40
+ };
41
+ missing: ('stop' | 'target')[];
42
+ }>;
43
+ getPositionsOrNull(symbol?: string): Promise<CcxtPosition[] | null>;
44
+ closePosition(symbol: string, closeReason?: CloseReason): Promise<CcxtOrder>;
45
+ }
46
+ export interface HlAttachResult {
47
+ ok: boolean;
48
+ latencyMs: number;
49
+ slCid?: string;
50
+ tpCid?: string;
51
+ error?: string;
52
+ attempts: number;
53
+ }
54
+ export interface HlCoordinatorOpts {
55
+ maxAttempts?: number;
56
+ retryBackoffMs?: (attempt: number) => number;
57
+ now?: () => number;
58
+ sleep?: (ms: number) => Promise<void>;
59
+ }
60
+ export declare function isTerminalBracketState(state: BracketState): boolean;
61
+ export declare class HlBracketCoordinator extends EventEmitter {
62
+ private readonly executor;
63
+ private readonly ledger;
64
+ private readonly maxAttempts;
65
+ private readonly backoff;
66
+ private readonly now;
67
+ private readonly sleep;
68
+ /** Per-symbol in-flight guard so a WS fill + the createOrder return path
69
+ * can't both run attachOnFill concurrently (double-submit). */
70
+ private readonly inFlight;
71
+ /** Cloids WE deliberately cancelled (resize/modify supersede, retry cleanup,
72
+ * cancelBrackets). Their WS 'canceled' events are OUR OWN and must never
73
+ * trip the stripped-protection canary — the T-8 testnet run proved the WS
74
+ * event can arrive BEFORE the ledger's fresh-cid update lands, so a
75
+ * generation check alone loses the race. Entries pruned after 5 min. */
76
+ private readonly ownCancels;
77
+ constructor(executor: HlBracketExecutor, ledger: BracketLedger, opts?: HlCoordinatorOpts);
78
+ getLedger(): BracketLedger;
79
+ /** Record a leg cancel WE initiated (see `ownCancels`). The adapter calls
80
+ * this for every deliberate leg cancel, including the resize path's direct
81
+ * api cancels, BEFORE the cancel request goes out. */
82
+ noteOwnLegCancel(cloid: string): void;
83
+ /** Same anti-clobber contract as BracketManager.registerEntry: a duplicate
84
+ * fill signal against a non-terminal row is a warned NO-OP, never a fresh
85
+ * bracketId that orphans the live legs' ledger identity. */
86
+ registerEntry(req: BracketRequest, bracketId: BracketId, entryCid: string): void;
87
+ /** Attach both legs (ONE batched signed action) with retries. Idempotent on
88
+ * a non-pending row. On exhaustion: ledger 'failed' + attach_failed event —
89
+ * the ADAPTER escalates to auto-flatten (it owns closePosition). */
90
+ attachOnFill(symbol: string, filledSize: number): Promise<HlAttachResult>;
91
+ /** ★ T-2: bring the legs to the CURRENT position size (scale-in / partial
92
+ * fill growth). Submit-first-then-cancel inside the adapter. Updates the
93
+ * ledger's qty + fresh cids on success. */
94
+ resizeToPosition(symbol: string, newPositionSize: number): Promise<{
95
+ resized: boolean;
96
+ }>;
97
+ /** Move the stop. HL ordering: submit the NEW leg first, then cancel the old
98
+ * one — over-protection for a moment beats a naked window (see header). */
99
+ modifyStop(symbol: string, newStopPrice: number): Promise<void>;
100
+ modifyTarget(symbol: string, newTargetPrice: number): Promise<void>;
101
+ private modifyLeg;
102
+ /** Cancel both legs, mark cancelled. Risk-reducing; best-effort per leg. */
103
+ cancelBrackets(symbol: string, reason: string): Promise<void>;
104
+ /**
105
+ * The HL analog of the Binance ALGO_UPDATE handler — `orderUpdates` is
106
+ * authoritative for bracket-leg lifecycle. Returns the transition applied
107
+ * (for the adapter to emit drift/close-bypass signals on triggers).
108
+ */
109
+ handleOrderUpdate(update: HlOrderUpdateEvent): 'triggered_sl' | 'triggered_tp' | 'forced_close' | null;
110
+ /**
111
+ * ★ T-5 mandate: REST truth-check. Runs after every WS (re)connect AND on the
112
+ * periodic sweep. TRUSTED reads only — a null positions fetch skips the pass
113
+ * (never act on unknown). Self-heals: pending rows whose entry filled while
114
+ * we were blind get their legs attached; undersized legs get resized; flat
115
+ * positions get their rows closed out (T-1 already cancelled the legs).
116
+ * Returns symbols whose rows were closed out (close-bypass signals for the
117
+ * adapter's drift pipeline).
118
+ */
119
+ resyncAgainstExchange(reasonTag: string): Promise<{
120
+ closedSymbols: string[];
121
+ }>;
122
+ private emitEvent;
123
+ }