@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.
- package/bridge/gateway/event-parser.d.ts +6 -1
- package/bridge/gateway/event-parser.js +19 -2
- package/bridge/gateway/poller.d.ts +1 -0
- package/bridge/gateway/poller.js +14 -2
- package/bridge/providers/gateway.d.ts +22 -2
- package/bridge/providers/gateway.js +67 -9
- package/ccxt/binance-private.d.ts +21 -0
- package/ccxt/binance-private.js +132 -22
- package/ccxt/public-market-data-api.d.ts +14 -0
- package/ccxt/public-market-data-api.js +15 -1
- package/config/plugin-config-io.d.ts +13 -0
- package/config/plugin-config-io.js +15 -0
- package/config/tool-gate.js +3 -0
- package/exchange-adapter.d.ts +16 -0
- package/index.js +658 -83
- package/ingest/position-auto-capture.d.ts +68 -0
- package/ingest/position-auto-capture.js +321 -23
- package/ingest/position-decisions-client.d.ts +7 -2
- package/ingest/position-decisions-client.js +13 -3
- package/ingest/reconcile-db-vs-exchange.d.ts +39 -1
- package/ingest/reconcile-db-vs-exchange.js +66 -10
- package/lifecycle/trading-operation-lock.d.ts +17 -0
- package/lifecycle/trading-operation-lock.js +14 -0
- package/live/bracket-id.d.ts +2 -3
- package/live/bracket-id.js +22 -9
- package/live/fill-price.d.ts +13 -0
- package/live/fill-price.js +37 -0
- package/live/live-adapter.d.ts +57 -2
- package/live/live-adapter.js +290 -49
- package/live/local-signal-service.js +11 -6
- package/live/local-strategy-evaluator.js +4 -0
- package/live/position-state-store.d.ts +4 -0
- package/live/proposal-decision-listener.d.ts +6 -0
- package/live/proposal-decision-listener.js +4 -0
- package/live/stop-watcher.d.ts +35 -2
- package/live/stop-watcher.js +63 -3
- package/onboarding/runtime.d.ts +19 -0
- package/onboarding/runtime.js +34 -3
- package/openclaw.plugin.json +1 -0
- package/package.json +2 -2
- package/portfolio/reentry-tracker.d.ts +36 -0
- package/portfolio/reentry-tracker.js +127 -0
- package/portfolio/wave9-admission.d.ts +67 -0
- package/portfolio/wave9-admission.js +262 -0
- package/portfolio/wave9-policy.d.ts +36 -0
- package/portfolio/wave9-policy.js +183 -0
- package/signals/conditions/registry.js +61 -2
- package/signals/strategy-adapter.js +17 -7
- package/simulator/exchange-simulator.d.ts +12 -0
- package/simulator/exchange-simulator.js +78 -3
- package/simulator/fill-engine.js +5 -1
- package/simulator/types.d.ts +10 -1
- package/skills/reefclaw/SKILL.md +2 -0
- package/strategy/evaluator.d.ts +3 -0
- package/strategy/evaluator.js +5 -0
- package/tools/assessment-validation.d.ts +23 -0
- package/tools/assessment-validation.js +58 -0
- package/tools/attach-brackets.d.ts +7 -2
- package/tools/attach-brackets.js +201 -0
- package/tools/audit-bracket-protection.js +157 -1
- package/tools/bracket-control.d.ts +12 -0
- package/tools/bracket-control.js +35 -0
- package/tools/cancel-all-orders.d.ts +2 -0
- package/tools/cancel-all-orders.js +4 -1
- package/tools/cancel-order.d.ts +4 -0
- package/tools/cancel-order.js +49 -3
- package/tools/close-position.d.ts +23 -0
- package/tools/close-position.js +286 -13
- package/tools/create-order.d.ts +28 -0
- package/tools/create-order.js +1390 -190
- package/tools/get-analytics.js +2 -2
- package/tools/get-basis.js +2 -2
- package/tools/get-cascade-risk.js +2 -2
- package/tools/get-crypto-metrics.js +14 -4
- package/tools/get-cvd.js +2 -2
- package/tools/get-divergences.js +2 -2
- package/tools/get-funding-context.js +2 -2
- package/tools/get-liquidation-levels.js +2 -2
- package/tools/get-liquidation-pulse.js +2 -2
- package/tools/get-pattern-scan.js +2 -2
- package/tools/get-regime.js +2 -2
- package/tools/get-resting-liquidity.js +2 -2
- package/tools/get-risk-scenario.js +2 -2
- package/tools/get-session-review.js +2 -2
- package/tools/get-setup-detail.js +21 -2
- package/tools/get-signals.js +2 -2
- package/tools/get-sizing.js +2 -2
- package/tools/get-trade-feedback.js +2 -2
- package/tools/get-trade-flow.js +2 -2
- package/tools/get-volume-profile.js +2 -2
- package/tools/get-wave9-status.d.ts +127 -0
- package/tools/get-wave9-status.js +796 -0
- package/tools/intel-api.d.ts +20 -0
- package/tools/intel-api.js +67 -0
- package/tools/intel-cache.d.ts +1 -1
- package/tools/intel-cache.js +20 -5
- package/tools/list-strategies.d.ts +11 -1
- package/tools/list-strategies.js +17 -0
- package/tools/modify-stop.d.ts +4 -0
- package/tools/modify-stop.js +63 -24
- package/tools/modify-target.d.ts +4 -0
- package/tools/modify-target.js +62 -23
- package/tools/scan-pairs.d.ts +4 -0
- package/tools/scan-pairs.js +22 -8
- package/tools/toggle-strategy.js +7 -0
- package/types.d.ts +5 -0
- package/venues/hyperliquid/hl-balance.d.ts +116 -0
- package/venues/hyperliquid/hl-balance.js +145 -0
- package/venues/hyperliquid/hl-bracket-coordinator.d.ts +123 -0
- package/venues/hyperliquid/hl-bracket-coordinator.js +533 -0
- package/venues/hyperliquid/hl-brackets.d.ts +102 -0
- package/venues/hyperliquid/hl-brackets.js +172 -0
- package/venues/hyperliquid/hl-cloid.d.ts +22 -0
- package/venues/hyperliquid/hl-cloid.js +82 -0
- package/venues/hyperliquid/hl-info-cache.d.ts +46 -0
- package/venues/hyperliquid/hl-info-cache.js +125 -0
- package/venues/hyperliquid/hl-live-adapter.d.ts +146 -0
- package/venues/hyperliquid/hl-live-adapter.js +728 -0
- package/venues/hyperliquid/hl-precision.d.ts +61 -0
- package/venues/hyperliquid/hl-precision.js +176 -0
- package/venues/hyperliquid/hl-private.d.ts +88 -0
- package/venues/hyperliquid/hl-private.js +357 -0
- package/venues/hyperliquid/hl-public.d.ts +31 -4
- package/venues/hyperliquid/hl-public.js +163 -12
- package/venues/hyperliquid/hl-rate-gate.d.ts +57 -0
- package/venues/hyperliquid/hl-rate-gate.js +220 -0
- package/venues/hyperliquid/hl-user-stream.d.ts +90 -0
- package/venues/hyperliquid/hl-user-stream.js +220 -0
- package/venues/registry.d.ts +23 -9
- package/venues/registry.js +12 -13
- package/venues/symbols.d.ts +43 -0
- package/venues/symbols.js +107 -0
- package/wave9/live-account-capture.d.ts +67 -0
- package/wave9/live-account-capture.js +435 -0
- package/wave9/live-autonomous-protection.d.ts +39 -0
- package/wave9/live-autonomous-protection.js +112 -0
- package/wave9/live-durable-reconciliation-scheduler.d.ts +33 -0
- package/wave9/live-durable-reconciliation-scheduler.js +115 -0
- package/wave9/live-execution-ledger.d.ts +107 -0
- package/wave9/live-execution-ledger.js +498 -0
- package/wave9/live-position-confirmation.d.ts +18 -0
- package/wave9/live-position-confirmation.js +111 -0
- package/wave9/live-residual-protection.d.ts +18 -0
- package/wave9/live-residual-protection.js +250 -0
- package/wave9/live-startup-reconciliation.d.ts +38 -0
- package/wave9/live-startup-reconciliation.js +454 -0
- package/wave9/live-symbol-ownership.d.ts +20 -0
- package/wave9/live-symbol-ownership.js +132 -0
- package/wave9/paper-admission-guard.d.ts +199 -0
- package/wave9/paper-admission-guard.js +650 -0
- package/wave9/usdm-evidence-provider.d.ts +42 -0
- package/wave9/usdm-evidence-provider.js +133 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { formatError } from '../logger.js';
|
|
2
|
+
import { generateBracketId, parseBracketCid } from '../live/bracket-id.js';
|
|
3
|
+
import { confirmWave9LiveNativeStop } from './live-account-capture.js';
|
|
4
|
+
const NON_TERMINAL_BRACKET_STATES = new Set(['pending_entry', 'attaching', 'active', 'partial']);
|
|
5
|
+
function canonicalSymbol(symbol) {
|
|
6
|
+
return symbol.toUpperCase().replace(/[^A-Z0-9]/g, '').replace(/USDTUSDT$/, 'USDT');
|
|
7
|
+
}
|
|
8
|
+
function sameQuantity(left, right) {
|
|
9
|
+
return Math.abs(left - right) <= 1e-9 * Math.max(1, Math.abs(left), Math.abs(right));
|
|
10
|
+
}
|
|
11
|
+
function bracketCids(orders) {
|
|
12
|
+
const cids = new Set();
|
|
13
|
+
for (const order of orders) {
|
|
14
|
+
if (order.status !== 'open' || !order.clientOrderId)
|
|
15
|
+
continue;
|
|
16
|
+
const parsed = parseBracketCid(order.clientOrderId);
|
|
17
|
+
if (parsed?.role === 'stop' || parsed?.role === 'target')
|
|
18
|
+
cids.add(order.clientOrderId);
|
|
19
|
+
}
|
|
20
|
+
return [...cids].sort((left, right) => left.localeCompare(right));
|
|
21
|
+
}
|
|
22
|
+
function manual(candidateId, symbol, stopPrice, detail, residualQuantity) {
|
|
23
|
+
return {
|
|
24
|
+
status: 'manual_intervention',
|
|
25
|
+
detail: `IMMEDIATE MANUAL INTERVENTION REQUIRED: ${detail}`,
|
|
26
|
+
candidateId,
|
|
27
|
+
symbol,
|
|
28
|
+
stopPrice,
|
|
29
|
+
...(residualQuantity !== undefined ? { residualQuantity } : {}),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function asResidualProtectionAdapter(adapter) {
|
|
33
|
+
const candidate = adapter;
|
|
34
|
+
return typeof candidate.getBracketManager === 'function'
|
|
35
|
+
&& typeof candidate.getBracketLedger === 'function'
|
|
36
|
+
&& typeof candidate.cancelSymbolBracketOrders === 'function'
|
|
37
|
+
&& typeof candidate.resolveBracketLegLiveness === 'function'
|
|
38
|
+
&& typeof candidate.resolveBracketLegProof === 'function'
|
|
39
|
+
? candidate
|
|
40
|
+
: null;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Re-arm the exact frozen Wave 9 stop after a reduce-only close leaves a
|
|
44
|
+
* residual. Success means one current residual was observed and its newly
|
|
45
|
+
* candidate-bound native close-all STOP_MARKET was proven by exact CID.
|
|
46
|
+
* Every unverifiable state remains OPEN and escalates manual intervention.
|
|
47
|
+
*/
|
|
48
|
+
export async function reprotectWave9LiveResidual(adapter, executionLedger, candidateId, symbol) {
|
|
49
|
+
const record = executionLedger.getByCandidateId(candidateId);
|
|
50
|
+
const fallbackStop = record?.initialStop ?? 0;
|
|
51
|
+
if (!record || record.state === 'closed') {
|
|
52
|
+
return manual(candidateId, symbol, fallbackStop, 'durable Wave 9 execution ownership is unavailable');
|
|
53
|
+
}
|
|
54
|
+
if (record.symbol !== canonicalSymbol(symbol)) {
|
|
55
|
+
return manual(candidateId, symbol, record.initialStop, 'candidate symbol does not match the residual symbol');
|
|
56
|
+
}
|
|
57
|
+
const native = asResidualProtectionAdapter(adapter);
|
|
58
|
+
if (!native) {
|
|
59
|
+
return manual(candidateId, symbol, record.initialStop, 'native bracket re-protection capability is unavailable');
|
|
60
|
+
}
|
|
61
|
+
const manager = native.getBracketManager();
|
|
62
|
+
const bracketLedger = native.getBracketLedger();
|
|
63
|
+
if (!manager || !bracketLedger) {
|
|
64
|
+
return manual(candidateId, symbol, record.initialStop, 'native bracket manager or ledger is unavailable');
|
|
65
|
+
}
|
|
66
|
+
let positions;
|
|
67
|
+
try {
|
|
68
|
+
positions = await adapter.getPositionsOrNull(symbol);
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
return manual(candidateId, symbol, record.initialStop, `residual position read threw: ${formatError(err)}`);
|
|
72
|
+
}
|
|
73
|
+
if (positions === null) {
|
|
74
|
+
return manual(candidateId, symbol, record.initialStop, 'residual position state is unknown');
|
|
75
|
+
}
|
|
76
|
+
const matches = positions.filter((position) => canonicalSymbol(position.symbol) === record.symbol
|
|
77
|
+
&& typeof position.contracts === 'number'
|
|
78
|
+
&& Number.isFinite(position.contracts)
|
|
79
|
+
&& position.contracts > 0);
|
|
80
|
+
if (matches.length !== 1) {
|
|
81
|
+
return manual(candidateId, symbol, record.initialStop, matches.length === 0
|
|
82
|
+
? 'no residual is currently visible, but stable flat was not established'
|
|
83
|
+
: 'multiple residual positions match the candidate symbol');
|
|
84
|
+
}
|
|
85
|
+
const residual = matches[0];
|
|
86
|
+
const expectedSide = record.side === 'buy' ? 'long' : 'short';
|
|
87
|
+
if (residual.side !== expectedSide) {
|
|
88
|
+
return manual(candidateId, symbol, record.initialStop, `residual side ${residual.side} does not match candidate side ${expectedSide}`, residual.contracts);
|
|
89
|
+
}
|
|
90
|
+
const maximumAuthorizedQuantity = record.filledQuantity ?? record.quantity;
|
|
91
|
+
if (residual.contracts > maximumAuthorizedQuantity
|
|
92
|
+
&& !sameQuantity(residual.contracts, maximumAuthorizedQuantity)) {
|
|
93
|
+
return manual(candidateId, symbol, record.initialStop, `residual quantity ${residual.contracts} exceeds authorized quantity ${maximumAuthorizedQuantity}`, residual.contracts);
|
|
94
|
+
}
|
|
95
|
+
const confirmationInput = {
|
|
96
|
+
candidateId,
|
|
97
|
+
symbol,
|
|
98
|
+
entryClientOrderId: record.clientOrderId,
|
|
99
|
+
entrySide: record.side,
|
|
100
|
+
stopPrice: record.initialStop,
|
|
101
|
+
filledQuantity: residual.contracts,
|
|
102
|
+
};
|
|
103
|
+
try {
|
|
104
|
+
if (await confirmWave9LiveNativeStop(adapter, confirmationInput)) {
|
|
105
|
+
const existing = bracketLedger.getBySymbol(symbol);
|
|
106
|
+
return {
|
|
107
|
+
status: 'protected',
|
|
108
|
+
detail: 'existing exact candidate-bound native close-all stop is proven live',
|
|
109
|
+
candidateId,
|
|
110
|
+
symbol,
|
|
111
|
+
stopPrice: record.initialStop,
|
|
112
|
+
residualQuantity: residual.contracts,
|
|
113
|
+
...(existing?.slCid ? { stopClientOrderId: existing.slCid } : {}),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// Continue only when it is safe to replace a terminal/missing row below.
|
|
119
|
+
}
|
|
120
|
+
const existing = bracketLedger.getBySymbol(symbol);
|
|
121
|
+
let inventoriedCids;
|
|
122
|
+
try {
|
|
123
|
+
const openOrders = await adapter.getOpenOrders(symbol);
|
|
124
|
+
if (!Array.isArray(openOrders))
|
|
125
|
+
throw new Error('open-order inventory was not an array');
|
|
126
|
+
inventoriedCids = bracketCids(openOrders);
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
return manual(candidateId, symbol, record.initialStop, `could not obtain trusted pre-cancel bracket inventory: ${formatError(err)}`, residual.contracts);
|
|
130
|
+
}
|
|
131
|
+
// Never cancel a stop that may still be protecting the position. A direct
|
|
132
|
+
// exact-stop confirmation above already accepted the fully valid case. If
|
|
133
|
+
// any other stored/inventoried stop is live or its state is unknown, retain
|
|
134
|
+
// it and escalate instead of creating a cancel-then-attach protection gap.
|
|
135
|
+
const inventoriedStopCids = inventoriedCids.filter((cid) => parseBracketCid(cid)?.role === 'stop');
|
|
136
|
+
const stopCidsToProve = [...new Set([
|
|
137
|
+
...inventoriedStopCids,
|
|
138
|
+
...(existing?.slCid ? [existing.slCid] : []),
|
|
139
|
+
])].sort((left, right) => left.localeCompare(right));
|
|
140
|
+
for (const cid of stopCidsToProve) {
|
|
141
|
+
let liveness;
|
|
142
|
+
try {
|
|
143
|
+
liveness = await native.resolveBracketLegLiveness(cid);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
liveness = 'unknown';
|
|
147
|
+
}
|
|
148
|
+
if (liveness !== 'terminal') {
|
|
149
|
+
return manual(candidateId, symbol, record.initialStop, `existing stop ${cid} is ${liveness}; retaining it rather than opening a cancel/re-arm gap`, residual.contracts);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
await native.cancelSymbolBracketOrders(symbol);
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
return manual(candidateId, symbol, record.initialStop, `could not cancel stale bracket orders before re-arm: ${formatError(err)}`, residual.contracts);
|
|
157
|
+
}
|
|
158
|
+
const oldCids = [...new Set([
|
|
159
|
+
...inventoriedCids,
|
|
160
|
+
...[existing?.slCid, existing?.tpCid].filter((cid) => !!cid),
|
|
161
|
+
])].sort((left, right) => left.localeCompare(right));
|
|
162
|
+
for (const cid of oldCids) {
|
|
163
|
+
let liveness;
|
|
164
|
+
try {
|
|
165
|
+
liveness = await native.resolveBracketLegLiveness(cid);
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
liveness = 'unknown';
|
|
169
|
+
}
|
|
170
|
+
if (liveness !== 'terminal') {
|
|
171
|
+
return manual(candidateId, symbol, record.initialStop, `prior bracket leg ${cid} is ${liveness}; refusing an unverified duplicate stop`, residual.contracts);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
try {
|
|
175
|
+
const afterCancel = await adapter.getOpenOrders(symbol);
|
|
176
|
+
if (!Array.isArray(afterCancel))
|
|
177
|
+
throw new Error('post-cancel open-order inventory was not an array');
|
|
178
|
+
const remainingBracketCids = bracketCids(afterCancel);
|
|
179
|
+
if (remainingBracketCids.length > 0) {
|
|
180
|
+
return manual(candidateId, symbol, record.initialStop, `post-cancel inventory still contains bracket leg(s): ${remainingBracketCids.join(', ')}`, residual.contracts);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
return manual(candidateId, symbol, record.initialStop, `could not prove a clean post-cancel bracket inventory: ${formatError(err)}`, residual.contracts);
|
|
185
|
+
}
|
|
186
|
+
const currentBracket = bracketLedger.getBySymbol(symbol);
|
|
187
|
+
if (currentBracket && (!existing || currentBracket.bracketId !== existing.bracketId)) {
|
|
188
|
+
return manual(candidateId, symbol, record.initialStop, 'bracket ownership changed during residual re-protection', residual.contracts);
|
|
189
|
+
}
|
|
190
|
+
if (currentBracket && NON_TERMINAL_BRACKET_STATES.has(currentBracket.state)) {
|
|
191
|
+
try {
|
|
192
|
+
bracketLedger.markState(symbol, 'cancelled', {
|
|
193
|
+
closeReason: 'cancelled_auto',
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
return manual(candidateId, symbol, record.initialStop, `could not terminalize the proven-cancelled bracket row: ${formatError(err)}`, residual.contracts);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
let currentResidualQuantity;
|
|
201
|
+
try {
|
|
202
|
+
const currentPositions = await adapter.getPositionsOrNull(symbol);
|
|
203
|
+
if (currentPositions === null)
|
|
204
|
+
throw new Error('position state is unknown');
|
|
205
|
+
const currentMatches = currentPositions.filter((position) => canonicalSymbol(position.symbol) === record.symbol
|
|
206
|
+
&& typeof position.contracts === 'number'
|
|
207
|
+
&& Number.isFinite(position.contracts)
|
|
208
|
+
&& position.contracts > 0);
|
|
209
|
+
if (currentMatches.length !== 1 || currentMatches[0].side !== expectedSide) {
|
|
210
|
+
throw new Error(currentMatches.length === 0
|
|
211
|
+
? 'no residual is visible after cancellation, but stable flat was not established'
|
|
212
|
+
: 'residual identity changed during bracket cancellation');
|
|
213
|
+
}
|
|
214
|
+
currentResidualQuantity = currentMatches[0].contracts;
|
|
215
|
+
if (currentResidualQuantity > maximumAuthorizedQuantity
|
|
216
|
+
&& !sameQuantity(currentResidualQuantity, maximumAuthorizedQuantity)) {
|
|
217
|
+
throw new Error(`residual quantity ${currentResidualQuantity} exceeds authorized quantity ${maximumAuthorizedQuantity}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
catch (err) {
|
|
221
|
+
return manual(candidateId, symbol, record.initialStop, `could not bind the current residual after cancellation: ${formatError(err)}`, residual.contracts);
|
|
222
|
+
}
|
|
223
|
+
const bracketId = generateBracketId();
|
|
224
|
+
try {
|
|
225
|
+
manager.registerEntry({ symbol, side: record.side, stopPrice: record.initialStop }, bracketId, record.clientOrderId);
|
|
226
|
+
const attached = await manager.attachBrackets(symbol, currentResidualQuantity);
|
|
227
|
+
if (!attached.ok || !attached.slCid) {
|
|
228
|
+
return manual(candidateId, symbol, record.initialStop, `exact frozen stop attach failed after ${attached.attempts} attempt(s): ${attached.error ?? 'no stop CID'}`, currentResidualQuantity);
|
|
229
|
+
}
|
|
230
|
+
const verified = await confirmWave9LiveNativeStop(adapter, {
|
|
231
|
+
...confirmationInput,
|
|
232
|
+
filledQuantity: currentResidualQuantity,
|
|
233
|
+
});
|
|
234
|
+
if (!verified) {
|
|
235
|
+
return manual(candidateId, symbol, record.initialStop, `new stop ${attached.slCid} could not be proven as the exact native close-all STOP_MARKET`, currentResidualQuantity);
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
status: 'protected',
|
|
239
|
+
detail: 'exact frozen candidate-bound native close-all stop was re-attached and proven live',
|
|
240
|
+
candidateId,
|
|
241
|
+
symbol,
|
|
242
|
+
stopPrice: record.initialStop,
|
|
243
|
+
residualQuantity: currentResidualQuantity,
|
|
244
|
+
stopClientOrderId: attached.slCid,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
catch (err) {
|
|
248
|
+
return manual(candidateId, symbol, record.initialStop, `exact frozen stop re-arm threw: ${formatError(err)}`, currentResidualQuantity);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { IExchangeAdapter } from '../exchange-adapter.js';
|
|
2
|
+
import { type Wave9LiveStopConfirmationInput } from './live-account-capture.js';
|
|
3
|
+
import { recoverWave9LiveExposure, type Wave9LiveAutonomousProtectionOptions } from './live-autonomous-protection.js';
|
|
4
|
+
import type { Wave9LiveExecutionLedger } from './live-execution-ledger.js';
|
|
5
|
+
import { type Wave9LiveFlatConfirmation, type Wave9LiveFlatConfirmationOptions } from './live-position-confirmation.js';
|
|
6
|
+
export type Wave9LiveStartupRowStatus = 'protected' | 'closed' | 'manual_intervention';
|
|
7
|
+
export interface Wave9LiveStartupRowResult {
|
|
8
|
+
candidateId: string;
|
|
9
|
+
symbol: string;
|
|
10
|
+
priorState: 'attempted' | 'open';
|
|
11
|
+
status: Wave9LiveStartupRowStatus;
|
|
12
|
+
detail: string;
|
|
13
|
+
/** True only for a read/settlement state that a bounded READY retry may heal. */
|
|
14
|
+
retryable: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface Wave9LiveStartupReconciliationResult {
|
|
17
|
+
rows: Wave9LiveStartupRowResult[];
|
|
18
|
+
unresolvedCount: number;
|
|
19
|
+
protectedCount: number;
|
|
20
|
+
closedCount: number;
|
|
21
|
+
manualInterventionCount: number;
|
|
22
|
+
retryable: boolean;
|
|
23
|
+
}
|
|
24
|
+
export interface Wave9LiveStartupReconciliationOptions {
|
|
25
|
+
confirmFlat?: (adapter: IExchangeAdapter, symbol: string, options?: Wave9LiveFlatConfirmationOptions) => Promise<Wave9LiveFlatConfirmation>;
|
|
26
|
+
flatConfirmation?: Wave9LiveFlatConfirmationOptions;
|
|
27
|
+
confirmStop?: (adapter: IExchangeAdapter, input: Wave9LiveStopConfirmationInput) => Promise<boolean>;
|
|
28
|
+
recoverExposure?: typeof recoverWave9LiveExposure;
|
|
29
|
+
recoveryOptions?: Omit<Wave9LiveAutonomousProtectionOptions, 'authorizeExposureMutation'>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Reconcile crash-ambiguous durable Wave 9 rows after a LIVE adapter reaches
|
|
33
|
+
* READY. The caller must hold the shared trading-operation lock. This function
|
|
34
|
+
* never submits another entry. It only cancels an exact candidate entry
|
|
35
|
+
* remainder, persists stably-flat terminal state, or repairs/flattens exposure
|
|
36
|
+
* after exact entry-CID and current-position identity both agree.
|
|
37
|
+
*/
|
|
38
|
+
export declare function reconcileWave9LiveDurableRows(adapter: IExchangeAdapter, ledger: Wave9LiveExecutionLedger, options?: Wave9LiveStartupReconciliationOptions): Promise<Wave9LiveStartupReconciliationResult>;
|