@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
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
import { parseBracketCid } from '../live/bracket-id.js';
|
|
18
18
|
import { normalizeBracketSymbol } from '../live/bracket-ledger.js';
|
|
19
19
|
import { formatError, logger } from '../logger.js';
|
|
20
|
+
import { HyperliquidLiveAdapter } from '../venues/hyperliquid/hl-live-adapter.js';
|
|
21
|
+
import { isTerminalBracketState } from '../venues/hyperliquid/hl-bracket-coordinator.js';
|
|
22
|
+
import { parseHlBracketCloid } from '../venues/hyperliquid/hl-cloid.js';
|
|
23
|
+
import { isProtectiveHlOrder } from '../venues/hyperliquid/hl-brackets.js';
|
|
20
24
|
const TAG = 'audit-bracket-protection';
|
|
21
25
|
// Per-symbol verdict history for flicker detection. When audit verdicts
|
|
22
26
|
// transition protected→unprotected→protected repeatedly inside a short
|
|
@@ -73,7 +77,12 @@ export async function auditBracketProtectionTool(_args, deps) {
|
|
|
73
77
|
positions: entries,
|
|
74
78
|
};
|
|
75
79
|
}
|
|
76
|
-
// Live mode.
|
|
80
|
+
// Live mode — venue dispatch (issue #209). The Binance-shaped path below
|
|
81
|
+
// reads algo-order fields HL doesn't have; on HL it produced permanent
|
|
82
|
+
// false "unprotected" verdicts (the spiral seed).
|
|
83
|
+
if (deps.adapter instanceof HyperliquidLiveAdapter) {
|
|
84
|
+
return auditHlLive(deps.adapter);
|
|
85
|
+
}
|
|
77
86
|
const live = deps.adapter;
|
|
78
87
|
const ledger = live.getBracketLedger?.() ?? null;
|
|
79
88
|
const bracketsEnabled = ledger !== null;
|
|
@@ -525,3 +534,150 @@ function extractTriggerPrice(o) {
|
|
|
525
534
|
}
|
|
526
535
|
return undefined;
|
|
527
536
|
}
|
|
537
|
+
/**
|
|
538
|
+
* Hyperliquid live audit (issue #209). Same contracts as the Binance path:
|
|
539
|
+
* null ≠ empty ({error} on an unavailable read — the agent skips the cycle and
|
|
540
|
+
* MUST NOT act), and an EMPTY open-orders set against a non-terminal ledger row
|
|
541
|
+
* WITH cids is unverifiable, never "unprotected" (HL has no zero-weight per-leg
|
|
542
|
+
* resolver, so the honest floor is the whole-audit {error}). External trigger
|
|
543
|
+
* legs count as protection (`manual_order_protecting`) via the HL order shape
|
|
544
|
+
* (isTrigger/reduceOnly/orderType — T-7 fields), mirroring the Binance rule
|
|
545
|
+
* that a manually-placed stop must never be reported as naked.
|
|
546
|
+
*/
|
|
547
|
+
async function auditHlLive(adapter) {
|
|
548
|
+
const ledger = adapter.getHlBracketCoordinator().getLedger();
|
|
549
|
+
const positionsOrNull = await adapter.getPositionsOrNull();
|
|
550
|
+
if (positionsOrNull === null) {
|
|
551
|
+
return {
|
|
552
|
+
error: 'Exchange data unavailable (Hyperliquid fetch failed / rate-gated). Skipping audit ' +
|
|
553
|
+
'this cycle — bracket state on the exchange is unchanged. Retry on next heartbeat.',
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
const activePositions = positionsOrNull.filter(p => Math.abs(Number(p.contracts ?? 0)) > 0);
|
|
557
|
+
if (activePositions.length === 0) {
|
|
558
|
+
return {
|
|
559
|
+
ok: true,
|
|
560
|
+
mode: 'live',
|
|
561
|
+
brackets_enabled: true,
|
|
562
|
+
total_positions: 0,
|
|
563
|
+
protected_count: 0,
|
|
564
|
+
unprotected_count: 0,
|
|
565
|
+
positions: [],
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
const entries = [];
|
|
569
|
+
for (const p of activePositions) {
|
|
570
|
+
let symbolOrders;
|
|
571
|
+
try {
|
|
572
|
+
symbolOrders = await adapter.getOpenOrders(p.symbol);
|
|
573
|
+
}
|
|
574
|
+
catch (err) {
|
|
575
|
+
const m = formatError(err);
|
|
576
|
+
logger.warn(TAG, `HL audit skipped — open orders unavailable for ${p.symbol}: ${m}`);
|
|
577
|
+
return {
|
|
578
|
+
error: `Exchange data unavailable for ${p.symbol} (Hyperliquid open-orders fetch failed). ` +
|
|
579
|
+
`Skipping audit this cycle — do NOT run attach_brackets or ` +
|
|
580
|
+
`close_position(reason='bracket_integrity') on the basis of this call. Underlying: ${m}`,
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
const ledgerRow = ledger.getBySymbol(p.symbol) ?? null;
|
|
584
|
+
const rowNonTerminalWithCids = !!ledgerRow && !isTerminalBracketState(ledgerRow.state) && Boolean(ledgerRow.slCid || ledgerRow.tpCid);
|
|
585
|
+
if (symbolOrders.length === 0 && rowNonTerminalWithCids) {
|
|
586
|
+
// Untrusted-empty contradiction (the SOL/INJ lesson, HL edition): the
|
|
587
|
+
// ledger says legs are live but the successful fetch shows nothing.
|
|
588
|
+
// Empty is NOT positive disconfirmation — refuse honestly.
|
|
589
|
+
return {
|
|
590
|
+
error: `Cannot confirm bracket protection for ${p.symbol} — the exchange returned an empty ` +
|
|
591
|
+
`open-orders set while the ledger row is ${ledgerRow.state} with stored cloids. ` +
|
|
592
|
+
`Empty ≠ "brackets gone". Skipping audit this cycle; do NOT run attach_brackets or ` +
|
|
593
|
+
`close_position(reason='bracket_integrity'). Retry next heartbeat.`,
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
let hasBracketStop = false;
|
|
597
|
+
let hasBracketTarget = false;
|
|
598
|
+
let hasManualStop = false;
|
|
599
|
+
let hasManualTarget = false;
|
|
600
|
+
let stopPrice;
|
|
601
|
+
let targetPrice;
|
|
602
|
+
for (const o of symbolOrders) {
|
|
603
|
+
const parsed = o.clientOrderId ? parseHlBracketCloid(o.clientOrderId) : null;
|
|
604
|
+
const triggerPrice = extractTriggerPrice(o);
|
|
605
|
+
const info = o.info ?? {};
|
|
606
|
+
if (parsed?.role === 'stop') {
|
|
607
|
+
hasBracketStop = true;
|
|
608
|
+
stopPrice = triggerPrice ?? stopPrice;
|
|
609
|
+
}
|
|
610
|
+
else if (parsed?.role === 'target') {
|
|
611
|
+
hasBracketTarget = true;
|
|
612
|
+
targetPrice = triggerPrice ?? targetPrice;
|
|
613
|
+
}
|
|
614
|
+
else if (isProtectiveHlOrder(info)) {
|
|
615
|
+
const t = String(info.orderType ?? o.type ?? '').toLowerCase();
|
|
616
|
+
if (t.includes('take profit') || t.includes('tp') || t.includes('take_profit')) {
|
|
617
|
+
hasManualTarget = true;
|
|
618
|
+
targetPrice = triggerPrice ?? targetPrice;
|
|
619
|
+
}
|
|
620
|
+
else {
|
|
621
|
+
hasManualStop = true;
|
|
622
|
+
stopPrice = triggerPrice ?? stopPrice;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
const hasStop = hasBracketStop || hasManualStop;
|
|
627
|
+
const hasTarget = hasBracketTarget || hasManualTarget;
|
|
628
|
+
if (ledgerRow?.stopPrice !== undefined)
|
|
629
|
+
stopPrice = ledgerRow.stopPrice;
|
|
630
|
+
if (ledgerRow?.targetPrice !== undefined)
|
|
631
|
+
targetPrice = ledgerRow.targetPrice;
|
|
632
|
+
let reason;
|
|
633
|
+
if (hasStop || hasTarget) {
|
|
634
|
+
reason = hasBracketStop || hasBracketTarget ? 'bracket_active' : 'manual_order_protecting';
|
|
635
|
+
}
|
|
636
|
+
else if (ledgerRow &&
|
|
637
|
+
(ledgerRow.state === 'active' || ledgerRow.state === 'partial' || ledgerRow.state === 'attaching')) {
|
|
638
|
+
reason = 'stale_ledger_row';
|
|
639
|
+
}
|
|
640
|
+
else if (ledgerRow && isTerminalBracketState(ledgerRow.state)) {
|
|
641
|
+
reason = 'ledger_terminal_no_order';
|
|
642
|
+
}
|
|
643
|
+
else {
|
|
644
|
+
reason = 'no_protective_order';
|
|
645
|
+
}
|
|
646
|
+
// ★ T-2 under-coverage: a stop can exist AND still leave scaled-in size
|
|
647
|
+
// naked (fixed-size legs). Surface it in logs; the adapter's 60s
|
|
648
|
+
// truth-check sweep auto-resizes.
|
|
649
|
+
const contracts = Math.abs(Number(p.contracts ?? 0));
|
|
650
|
+
if (hasBracketStop && ledgerRow?.qty !== undefined && ledgerRow.qty + 1e-8 < contracts) {
|
|
651
|
+
logger.warn(TAG, `HL audit: ${p.symbol} stop leg sized ${ledgerRow.qty} vs position ${contracts} — ` +
|
|
652
|
+
'under-covered (T-2); the truth-check sweep will resize');
|
|
653
|
+
}
|
|
654
|
+
entries.push({
|
|
655
|
+
symbol: p.symbol,
|
|
656
|
+
side: p.side,
|
|
657
|
+
contracts: p.contracts,
|
|
658
|
+
entry_price: p.entryPrice,
|
|
659
|
+
mark_price: p.markPrice,
|
|
660
|
+
has_stop: hasStop,
|
|
661
|
+
has_target: hasTarget,
|
|
662
|
+
stop_price: stopPrice,
|
|
663
|
+
target_price: targetPrice,
|
|
664
|
+
ledger_state: ledgerRow?.state ?? 'no_ledger_row',
|
|
665
|
+
reason,
|
|
666
|
+
recommended_action: hasStop ? 'none' : 'attach_brackets',
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
const nowTs = Date.now();
|
|
670
|
+
for (const e of entries) {
|
|
671
|
+
recordVerdictAndCheckFlicker(normalizeBracketSymbol(e.symbol), e.has_stop, nowTs);
|
|
672
|
+
}
|
|
673
|
+
const unprotected = entries.filter(e => !e.has_stop).length;
|
|
674
|
+
return {
|
|
675
|
+
ok: true,
|
|
676
|
+
mode: 'live',
|
|
677
|
+
brackets_enabled: true,
|
|
678
|
+
total_positions: entries.length,
|
|
679
|
+
protected_count: entries.length - unprotected,
|
|
680
|
+
unprotected_count: unprotected,
|
|
681
|
+
positions: entries,
|
|
682
|
+
};
|
|
683
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IExchangeAdapter } from '../exchange-adapter.js';
|
|
2
|
+
import type { BracketLedger } from '../live/bracket-ledger.js';
|
|
3
|
+
export interface BracketControl {
|
|
4
|
+
venue: 'binance' | 'hyperliquid';
|
|
5
|
+
ledger: BracketLedger;
|
|
6
|
+
modifyStop(symbol: string, newStopPrice: number): Promise<void>;
|
|
7
|
+
modifyTarget(symbol: string, newTargetPrice: number): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
/** Resolve the venue's bracket-mutation surface, or null when brackets are
|
|
10
|
+
* not enabled (Binance with brackets.mode=off; never null on HL live —
|
|
11
|
+
* exchange-side legs are HL live's ONLY protection, so they are always on). */
|
|
12
|
+
export declare function resolveBracketControl(adapter: IExchangeAdapter): BracketControl | null;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Venue dispatch for the bracket-mutating tools (issue #209).
|
|
2
|
+
//
|
|
3
|
+
// modify_stop / modify_target need one seam: "give me the thing that can move
|
|
4
|
+
// a leg, plus the ledger that knows the current geometry". On Binance that is
|
|
5
|
+
// BracketManager (+ LiveAdapter's ledger); on Hyperliquid it is the
|
|
6
|
+
// HlBracketCoordinator (which owns its own venue-distinct ledger). The tools
|
|
7
|
+
// must never know which venue they are on beyond this resolver — the
|
|
8
|
+
// hard-cast-to-LiveAdapter pattern is exactly what left the HL arm returning
|
|
9
|
+
// "Bracket orders are not enabled" on every call (the #209 recovery gap).
|
|
10
|
+
import { HyperliquidLiveAdapter } from '../venues/hyperliquid/hl-live-adapter.js';
|
|
11
|
+
/** Resolve the venue's bracket-mutation surface, or null when brackets are
|
|
12
|
+
* not enabled (Binance with brackets.mode=off; never null on HL live —
|
|
13
|
+
* exchange-side legs are HL live's ONLY protection, so they are always on). */
|
|
14
|
+
export function resolveBracketControl(adapter) {
|
|
15
|
+
if (adapter instanceof HyperliquidLiveAdapter) {
|
|
16
|
+
const coordinator = adapter.getHlBracketCoordinator();
|
|
17
|
+
return {
|
|
18
|
+
venue: 'hyperliquid',
|
|
19
|
+
ledger: coordinator.getLedger(),
|
|
20
|
+
modifyStop: (symbol, px) => coordinator.modifyStop(symbol, px),
|
|
21
|
+
modifyTarget: (symbol, px) => coordinator.modifyTarget(symbol, px),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const live = adapter;
|
|
25
|
+
const mgr = live.getBracketManager?.();
|
|
26
|
+
const ledger = live.getBracketLedger?.();
|
|
27
|
+
if (!mgr || !ledger)
|
|
28
|
+
return null;
|
|
29
|
+
return {
|
|
30
|
+
venue: 'binance',
|
|
31
|
+
ledger,
|
|
32
|
+
modifyStop: (symbol, px) => mgr.modifyStop(symbol, px),
|
|
33
|
+
modifyTarget: (symbol, px) => mgr.modifyTarget(symbol, px),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { IExchangeAdapter } from '../exchange-adapter.js';
|
|
2
|
+
import type { TradingOperationLock } from '../lifecycle/trading-operation-lock.js';
|
|
2
3
|
import type { CcxtOrder } from '../types.js';
|
|
3
4
|
export declare function cancelAllOrdersTool(args: {
|
|
4
5
|
symbol?: string;
|
|
5
6
|
}, deps: {
|
|
6
7
|
adapter: IExchangeAdapter;
|
|
8
|
+
operationLock?: TradingOperationLock;
|
|
7
9
|
}): Promise<CcxtOrder[]>;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
// Tool: cancel_all_orders — cancel all open orders (paper or live)
|
|
2
2
|
// NO readiness gate — emergency control (kill switch), must always work.
|
|
3
3
|
export async function cancelAllOrdersTool(args, deps) {
|
|
4
|
-
|
|
4
|
+
const cancel = () => deps.adapter.cancelAllOrders(args.symbol);
|
|
5
|
+
return deps.adapter.isLive && deps.operationLock
|
|
6
|
+
? deps.operationLock.withAccountLock(`generic-cancel-all-orders-final:${args.symbol ?? 'all'}`, cancel)
|
|
7
|
+
: cancel();
|
|
5
8
|
}
|
package/tools/cancel-order.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import type { IExchangeAdapter } from '../exchange-adapter.js';
|
|
2
|
+
import type { TradingOperationLock } from '../lifecycle/trading-operation-lock.js';
|
|
2
3
|
import type { CcxtOrder } from '../types.js';
|
|
4
|
+
import type { Wave9LiveSymbolOwnershipCheck } from '../wave9/live-symbol-ownership.js';
|
|
3
5
|
export declare function cancelOrderTool(args: {
|
|
4
6
|
id: string;
|
|
5
7
|
symbol?: string;
|
|
6
8
|
}, deps: {
|
|
7
9
|
adapter: IExchangeAdapter;
|
|
10
|
+
operationLock?: TradingOperationLock;
|
|
11
|
+
checkWave9LiveSymbolOwnership?: Wave9LiveSymbolOwnershipCheck;
|
|
8
12
|
}): Promise<CcxtOrder | {
|
|
9
13
|
error: string;
|
|
10
14
|
}>;
|
package/tools/cancel-order.js
CHANGED
|
@@ -1,12 +1,58 @@
|
|
|
1
|
-
// Tool: cancel_order — cancel a single order (paper or live)
|
|
2
|
-
//
|
|
1
|
+
// Tool: cancel_order — cancel a single order (paper or live).
|
|
2
|
+
// There is no readiness gate, but LIVE cancellation cannot individually strip
|
|
3
|
+
// candidate-bound Wave 9 protection. The emergency escape is an explicit
|
|
4
|
+
// operator close, which reduces exposure instead of leaving it naked.
|
|
3
5
|
import { formatError } from '../logger.js';
|
|
4
6
|
export async function cancelOrderTool(args, deps) {
|
|
5
7
|
if (!args.id) {
|
|
6
8
|
return { error: 'Order ID is required.' };
|
|
7
9
|
}
|
|
10
|
+
if (!deps.adapter.isLive) {
|
|
11
|
+
try {
|
|
12
|
+
return await deps.adapter.cancelOrder(args.id, args.symbol);
|
|
13
|
+
}
|
|
14
|
+
catch (err) {
|
|
15
|
+
return { error: formatError(err) };
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
if (deps.checkWave9LiveSymbolOwnership && !deps.operationLock) {
|
|
19
|
+
return {
|
|
20
|
+
error: 'Live cancel_order refused: the shared trading operation lock is required ' +
|
|
21
|
+
'while Wave 9 LIVE ownership checks are enabled.',
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const cancelLive = async () => {
|
|
25
|
+
let symbol = args.symbol?.trim();
|
|
26
|
+
if (!symbol) {
|
|
27
|
+
const matches = (await deps.adapter.getOpenOrders())
|
|
28
|
+
.filter((order) => order.id === args.id);
|
|
29
|
+
if (matches.length !== 1 || !matches[0].symbol) {
|
|
30
|
+
throw new Error(`cancel_order refused: order ${args.id} could not be resolved to exactly one ` +
|
|
31
|
+
`trusted open-order symbol (matches=${matches.length}).`);
|
|
32
|
+
}
|
|
33
|
+
symbol = matches[0].symbol;
|
|
34
|
+
}
|
|
35
|
+
if (deps.checkWave9LiveSymbolOwnership) {
|
|
36
|
+
let ownership;
|
|
37
|
+
try {
|
|
38
|
+
ownership = await deps.checkWave9LiveSymbolOwnership(symbol);
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
throw new Error(`cancel_order refused at mutation boundary: Wave 9 LIVE ownership check failed ` +
|
|
42
|
+
`for ${symbol} (${formatError(err)}).`);
|
|
43
|
+
}
|
|
44
|
+
if (ownership.status === 'owned' || ownership.status === 'ambiguous') {
|
|
45
|
+
throw new Error(`cancel_order refused at mutation boundary: ${symbol} has ` +
|
|
46
|
+
`${ownership.status} Wave 9 LIVE ownership (${ownership.reason}). ` +
|
|
47
|
+
'Use operator_command to close the position instead of stripping candidate-bound protection.');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return deps.adapter.cancelOrder(args.id, symbol);
|
|
51
|
+
};
|
|
8
52
|
try {
|
|
9
|
-
return
|
|
53
|
+
return deps.operationLock
|
|
54
|
+
? await deps.operationLock.withAccountLock(`generic-cancel-order-final:${args.id}`, cancelLive)
|
|
55
|
+
: await cancelLive();
|
|
10
56
|
}
|
|
11
57
|
catch (err) {
|
|
12
58
|
return { error: formatError(err) };
|
|
@@ -4,6 +4,11 @@ import type { CcxtOrder } from '../types.js';
|
|
|
4
4
|
import { type ClosePositionArgs } from './assessment-validation.js';
|
|
5
5
|
import { type AutoCaptureContext } from '../ingest/position-auto-capture.js';
|
|
6
6
|
import { type ExitGateMode } from '../config/position-review-config.js';
|
|
7
|
+
import type { TradingOperationLock } from '../lifecycle/trading-operation-lock.js';
|
|
8
|
+
import type { Wave9LiveExecutionLedger } from '../wave9/live-execution-ledger.js';
|
|
9
|
+
import type { Wave9LiveSymbolOwnershipCheck } from '../wave9/live-symbol-ownership.js';
|
|
10
|
+
import { type Wave9LiveResidualProtectionResult } from '../wave9/live-residual-protection.js';
|
|
11
|
+
import { type Wave9PaperAdmissionGuard } from '../wave9/paper-admission-guard.js';
|
|
7
12
|
export declare function closePositionTool(args: ClosePositionArgs, deps: {
|
|
8
13
|
binanceApi: PublicMarketDataApi;
|
|
9
14
|
adapter: IExchangeAdapter;
|
|
@@ -11,6 +16,24 @@ export declare function closePositionTool(args: ClosePositionArgs, deps: {
|
|
|
11
16
|
/** Override for tests — production reads from plugin-config.json on each
|
|
12
17
|
* call so the flag can be flipped without a restart. */
|
|
13
18
|
exitGateMode?: ExitGateMode;
|
|
19
|
+
wave9AdmissionGuard?: Wave9PaperAdmissionGuard;
|
|
20
|
+
refreshPaperState?: () => void;
|
|
21
|
+
wave9TradingModeCheck?: () => string;
|
|
22
|
+
wave9VenueCheck?: () => string;
|
|
23
|
+
captureWave9PositionFingerprint?: (symbol: string) => Promise<{
|
|
24
|
+
fingerprint: string;
|
|
25
|
+
position: {
|
|
26
|
+
candidateId?: string;
|
|
27
|
+
missionId?: string;
|
|
28
|
+
setupType?: string;
|
|
29
|
+
side: 'long' | 'short';
|
|
30
|
+
};
|
|
31
|
+
}>;
|
|
32
|
+
wave9LiveLedger?: Wave9LiveExecutionLedger;
|
|
33
|
+
checkWave9LiveSymbolOwnership?: Wave9LiveSymbolOwnershipCheck;
|
|
34
|
+
reprotectWave9LiveResidual?: (adapter: IExchangeAdapter, ledger: Wave9LiveExecutionLedger, candidateId: string, symbol: string) => Promise<Wave9LiveResidualProtectionResult>;
|
|
35
|
+
operationLock?: TradingOperationLock;
|
|
36
|
+
operationLockHeld?: boolean;
|
|
14
37
|
}): Promise<CcxtOrder | {
|
|
15
38
|
error: string;
|
|
16
39
|
}>;
|