dexbot 1.4.23 → 1.4.25
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/CHANGELOG.md +47 -0
- package/README.md +1 -0
- package/analysis/README.md +49 -0
- package/analysis/ama_fitting/package.json +1 -1
- package/analysis/grid_correction_check.ts +896 -0
- package/analysis/trend_detection/package.json +1 -1
- package/claw/package.json +1 -1
- package/claw/runtimes/openclaw-plugin/openclaw.plugin.json +1 -1
- package/claw/runtimes/openclaw-plugin/package.json +1 -1
- package/claw/tests/test_claw_mcp_transport.ts +2 -2
- package/dist/analysis/grid_correction_check.d.ts +90 -0
- package/dist/analysis/grid_correction_check.d.ts.map +1 -0
- package/dist/analysis/grid_correction_check.js +861 -0
- package/dist/analysis/grid_correction_check.js.map +1 -0
- package/dist/dexbot.d.ts.map +1 -1
- package/dist/dexbot.js +62 -6
- package/dist/dexbot.js.map +1 -1
- package/dist/modules/account_bots.d.ts.map +1 -1
- package/dist/modules/account_bots.js +53 -5
- package/dist/modules/account_bots.js.map +1 -1
- package/dist/modules/account_orders.d.ts +7 -10
- package/dist/modules/account_orders.d.ts.map +1 -1
- package/dist/modules/account_orders.js +26 -2
- package/dist/modules/account_orders.js.map +1 -1
- package/dist/modules/bitshares-native/subscriptions.d.ts.map +1 -1
- package/dist/modules/bitshares-native/subscriptions.js +176 -21
- package/dist/modules/bitshares-native/subscriptions.js.map +1 -1
- package/dist/modules/chain_orders.d.ts.map +1 -1
- package/dist/modules/chain_orders.js +21 -2
- package/dist/modules/chain_orders.js.map +1 -1
- package/dist/modules/config.d.ts.map +1 -1
- package/dist/modules/config.js +27 -0
- package/dist/modules/config.js.map +1 -1
- package/dist/modules/constants.d.ts +15 -1
- package/dist/modules/constants.d.ts.map +1 -1
- package/dist/modules/constants.js +70 -6
- package/dist/modules/constants.js.map +1 -1
- package/dist/modules/credit_runtime.d.ts.map +1 -1
- package/dist/modules/credit_runtime.js +31 -32
- package/dist/modules/credit_runtime.js.map +1 -1
- package/dist/modules/dexbot_class.d.ts +24 -0
- package/dist/modules/dexbot_class.d.ts.map +1 -1
- package/dist/modules/dexbot_class.js +66 -12
- package/dist/modules/dexbot_class.js.map +1 -1
- package/dist/modules/dexbot_cow_runtime.d.ts +22 -17
- package/dist/modules/dexbot_cow_runtime.d.ts.map +1 -1
- package/dist/modules/dexbot_cow_runtime.js +646 -128
- package/dist/modules/dexbot_cow_runtime.js.map +1 -1
- package/dist/modules/dexbot_fill_runtime.d.ts +11 -1
- package/dist/modules/dexbot_fill_runtime.d.ts.map +1 -1
- package/dist/modules/dexbot_fill_runtime.js +108 -1
- package/dist/modules/dexbot_fill_runtime.js.map +1 -1
- package/dist/modules/dexbot_maintenance_runtime.d.ts +17 -1
- package/dist/modules/dexbot_maintenance_runtime.d.ts.map +1 -1
- package/dist/modules/dexbot_maintenance_runtime.js +215 -26
- package/dist/modules/dexbot_maintenance_runtime.js.map +1 -1
- package/dist/modules/dexbot_startup_runtime.d.ts +1 -0
- package/dist/modules/dexbot_startup_runtime.d.ts.map +1 -1
- package/dist/modules/dexbot_startup_runtime.js +58 -7
- package/dist/modules/dexbot_startup_runtime.js.map +1 -1
- package/dist/modules/dexbot_state_recovery.d.ts.map +1 -1
- package/dist/modules/dexbot_state_recovery.js +55 -3
- package/dist/modules/dexbot_state_recovery.js.map +1 -1
- package/dist/modules/graceful_shutdown.d.ts +12 -1
- package/dist/modules/graceful_shutdown.d.ts.map +1 -1
- package/dist/modules/graceful_shutdown.js +39 -1
- package/dist/modules/graceful_shutdown.js.map +1 -1
- package/dist/modules/key_store.d.ts.map +1 -1
- package/dist/modules/key_store.js +38 -1
- package/dist/modules/key_store.js.map +1 -1
- package/dist/modules/order/accounting.d.ts.map +1 -1
- package/dist/modules/order/accounting.js +20 -3
- package/dist/modules/order/accounting.js.map +1 -1
- package/dist/modules/order/grid.d.ts +1 -1
- package/dist/modules/order/grid.d.ts.map +1 -1
- package/dist/modules/order/grid.js +288 -31
- package/dist/modules/order/grid.js.map +1 -1
- package/dist/modules/order/grid_reconcile.d.ts +4 -2
- package/dist/modules/order/grid_reconcile.d.ts.map +1 -1
- package/dist/modules/order/grid_reconcile.js +242 -222
- package/dist/modules/order/grid_reconcile.js.map +1 -1
- package/dist/modules/order/grid_reconcile_internal.d.ts +11 -1
- package/dist/modules/order/grid_reconcile_internal.d.ts.map +1 -1
- package/dist/modules/order/grid_reconcile_internal.js +132 -6
- package/dist/modules/order/grid_reconcile_internal.js.map +1 -1
- package/dist/modules/order/manager.d.ts +68 -14
- package/dist/modules/order/manager.d.ts.map +1 -1
- package/dist/modules/order/manager.js +241 -52
- package/dist/modules/order/manager.js.map +1 -1
- package/dist/modules/order/strategy.d.ts.map +1 -1
- package/dist/modules/order/strategy.js +25 -8
- package/dist/modules/order/strategy.js.map +1 -1
- package/dist/modules/order/sync_engine.d.ts.map +1 -1
- package/dist/modules/order/sync_engine.js +261 -166
- package/dist/modules/order/sync_engine.js.map +1 -1
- package/dist/modules/order/utils/math.d.ts +47 -5
- package/dist/modules/order/utils/math.d.ts.map +1 -1
- package/dist/modules/order/utils/math.js +175 -11
- package/dist/modules/order/utils/math.js.map +1 -1
- package/dist/modules/order/utils/order.d.ts +16 -15
- package/dist/modules/order/utils/order.d.ts.map +1 -1
- package/dist/modules/order/utils/order.js +199 -32
- package/dist/modules/order/utils/order.js.map +1 -1
- package/dist/modules/order/utils/slot.d.ts +8 -0
- package/dist/modules/order/utils/slot.d.ts.map +1 -0
- package/dist/modules/order/utils/slot.js +16 -0
- package/dist/modules/order/utils/slot.js.map +1 -0
- package/dist/modules/order/utils/system.d.ts.map +1 -1
- package/dist/modules/order/utils/system.js +3 -2
- package/dist/modules/order/utils/system.js.map +1 -1
- package/dist/modules/order/utils/validate.d.ts +5 -8
- package/dist/modules/order/utils/validate.d.ts.map +1 -1
- package/dist/modules/order/utils/validate.js +64 -82
- package/dist/modules/order/utils/validate.js.map +1 -1
- package/dist/modules/order/working_grid.d.ts +5 -0
- package/dist/modules/order/working_grid.d.ts.map +1 -1
- package/dist/modules/order/working_grid.js +21 -0
- package/dist/modules/order/working_grid.js.map +1 -1
- package/dist/modules/paths.d.ts +4 -2
- package/dist/modules/paths.d.ts.map +1 -1
- package/dist/modules/paths.js +79 -24
- package/dist/modules/paths.js.map +1 -1
- package/dist/scripts/analyze-orders.d.ts.map +1 -1
- package/dist/scripts/analyze-orders.js +23 -2
- package/dist/scripts/analyze-orders.js.map +1 -1
- package/dist/scripts/generate_market_adapter_whitelist.d.ts +2 -5
- package/dist/scripts/generate_market_adapter_whitelist.d.ts.map +1 -1
- package/dist/scripts/generate_market_adapter_whitelist.js +83 -1
- package/dist/scripts/generate_market_adapter_whitelist.js.map +1 -1
- package/docs/DEXBOT_COMPARISON.md +15 -15
- package/docs/EVOLUTION.md +10 -8
- package/docs/FUND_MOVEMENT_AND_ACCOUNTING.md +1 -1
- package/docs/GRID_RECALCULATION.md +6 -0
- package/docs/README.md +2 -2
- package/market_adapter/README.md +10 -0
- package/package.json +2 -1
- package/scripts/README.md +4 -0
|
@@ -45,6 +45,7 @@ declare class OrderManager {
|
|
|
45
45
|
_endOfBootstrapValidationDone: boolean;
|
|
46
46
|
_broadcastingFlag: number;
|
|
47
47
|
_broadcastingStartedAt: number;
|
|
48
|
+
_shuttingDown: boolean;
|
|
48
49
|
_illegalStateSignal: any;
|
|
49
50
|
_accountingFailureSignal: any;
|
|
50
51
|
_recoveryStateValue: {
|
|
@@ -133,6 +134,10 @@ declare class OrderManager {
|
|
|
133
134
|
_orphanFillsCreditedAt: number | null;
|
|
134
135
|
_pendingRecovery: Promise<void> | null;
|
|
135
136
|
_recentFillKeysSnapshot: Record<string, number> | null;
|
|
137
|
+
_lastFilledBuyPrice: number | null;
|
|
138
|
+
_lastFilledSellPrice: number | null;
|
|
139
|
+
_lastFilledPrice: number | null;
|
|
140
|
+
_lastFilledType: string | null;
|
|
136
141
|
_metrics: any;
|
|
137
142
|
private _currentWorkingGridStack;
|
|
138
143
|
_cowEngine: any;
|
|
@@ -194,6 +199,19 @@ declare class OrderManager {
|
|
|
194
199
|
* @returns {boolean}
|
|
195
200
|
*/
|
|
196
201
|
isBroadcastingActive(): boolean;
|
|
202
|
+
/**
|
|
203
|
+
* Whether the owning bot has begun shutting down. Mirrors the
|
|
204
|
+
* bot-level `_shuttingDown` flag (set via setShuttingDown() from
|
|
205
|
+
* DEXBot._shutdownImpl) so manager-level wait loops can bail out
|
|
206
|
+
* instead of proceeding with broadcasts after shutdown completed.
|
|
207
|
+
* @returns {boolean}
|
|
208
|
+
*/
|
|
209
|
+
isShuttingDown(): boolean;
|
|
210
|
+
/**
|
|
211
|
+
* @param {boolean} value
|
|
212
|
+
* @returns {void}
|
|
213
|
+
*/
|
|
214
|
+
setShuttingDown(value: any): void;
|
|
197
215
|
/**
|
|
198
216
|
* Auto-clears a stale broadcast flag after 120s so a hung
|
|
199
217
|
* broadcast cannot permanently block rebalancing.
|
|
@@ -534,22 +552,33 @@ declare class OrderManager {
|
|
|
534
552
|
* disk-load). This is the same write as _setBoundary but without the
|
|
535
553
|
* lock-hold warning — loadGrid / initializeGrid are single-threaded at
|
|
536
554
|
* startup and the boundary is being restored from a known-good snapshot,
|
|
537
|
-
* not committed alongside order mutations.
|
|
555
|
+
* not committed alongside order mutations. Accepts null to clear the
|
|
556
|
+
* boundary after a rejected persisted snapshot (P4) so re-derivation
|
|
557
|
+
* (P3) starts from a clean state.
|
|
538
558
|
*/
|
|
539
|
-
_restoreBoundary(newIdx: number): void;
|
|
559
|
+
_restoreBoundary(newIdx: number | null): void;
|
|
540
560
|
/**
|
|
541
|
-
*
|
|
542
|
-
*
|
|
543
|
-
*
|
|
544
|
-
*
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
*
|
|
549
|
-
*
|
|
550
|
-
*
|
|
561
|
+
* Observability (fix #4, docs/CONSOLIDATED_ORPHAN_FIX_SUMMARY.md §2): emit the live
|
|
562
|
+
* boundary whenever roles are (re)assigned, so a silent boundary crawl that
|
|
563
|
+
* re-rolls slots into the wrong rail is diagnosable in real time. Debug-level
|
|
564
|
+
* only; no behavioral effect.
|
|
565
|
+
*/
|
|
566
|
+
_logBoundaryDebug(source: string, newIdx: number | null): void;
|
|
567
|
+
/**
|
|
568
|
+
* Record last filled price for side-gated guard: only the side of the most recent fill is gated
|
|
569
|
+
* (BUY after BUY must be lower, SELL after SELL must be higher). Spread-correction bypasses.
|
|
570
|
+
* Cold start (null) => disabled. Per-type fields kept for observability/back-compat.
|
|
571
|
+
* @param {Array} fills
|
|
551
572
|
*/
|
|
552
|
-
|
|
573
|
+
recordLastFilledPrices(fills: any): void;
|
|
574
|
+
/**
|
|
575
|
+
* Seed last-filled guard from the live book at startup. Book-derived
|
|
576
|
+
* (survives restart), analogous to the deleted MarketAnchor book-seed.
|
|
577
|
+
* Closes the in-memory-only window where LAST-FILL-GUARD would be
|
|
578
|
+
* disabled until the first fill arrives.
|
|
579
|
+
* @param {Array} chainOpenOrders - raw chain open orders (from readOpenOrdersGuarded)
|
|
580
|
+
*/
|
|
581
|
+
seedLastFilledPricesFromBook(chainOpenOrders: any): void;
|
|
553
582
|
/**
|
|
554
583
|
* @returns {Object|null} The consumed signal or null
|
|
555
584
|
*/
|
|
@@ -622,12 +651,37 @@ declare class OrderManager {
|
|
|
622
651
|
updates: any;
|
|
623
652
|
};
|
|
624
653
|
};
|
|
654
|
+
/**
|
|
655
|
+
* Wait (bounded) until any non-COW broadcast/placement activity — the
|
|
656
|
+
* refcounted _broadcastingFlag — has released. Startup/structural
|
|
657
|
+
* reconcile Phase-2 placement now holds this flag across its create/update
|
|
658
|
+
* groups; launching a fill-driven COW rebalance on top of it mutates the
|
|
659
|
+
* master mid-broadcast, forcing a commit refusal and leaving a
|
|
660
|
+
* previous-generation order set on chain as duplicate-price orphans
|
|
661
|
+
* that block placements until drained.
|
|
662
|
+
*
|
|
663
|
+
* The wait is capped: after the timeout the rebalance proceeds anyway —
|
|
664
|
+
* the existing commit-refusal + chain-adoption machinery remains the
|
|
665
|
+
* backstop, so the worst case equals the pre-guard behavior.
|
|
666
|
+
*
|
|
667
|
+
* @param {number} [timeoutMs]
|
|
668
|
+
* @returns {Promise<{waitedMs: number, timedOut: boolean}>}
|
|
669
|
+
*/
|
|
670
|
+
_awaitBroadcastIdle(timeoutMs?: number): Promise<{
|
|
671
|
+
waitedMs: number;
|
|
672
|
+
timedOut: boolean;
|
|
673
|
+
shutdown: boolean;
|
|
674
|
+
}>;
|
|
625
675
|
/**
|
|
626
676
|
* @param {Array} [fills] - Fill events triggering rebalance
|
|
627
677
|
* @param {Set<string>} [excludeIds] - Order IDs to exclude
|
|
678
|
+
* @param {Object} [options]
|
|
679
|
+
* @param {boolean} [options.skipBroadcastWait] - Set by the COW re-plan path,
|
|
680
|
+
* which runs INSIDE its own startBroadcasting() region and must not wait
|
|
681
|
+
* on the flag it holds itself.
|
|
628
682
|
* @returns {Promise<any>}
|
|
629
683
|
*/
|
|
630
|
-
performSafeRebalance(fills?: any, excludeIds?: any): Promise<any>;
|
|
684
|
+
performSafeRebalance(fills?: any, excludeIds?: any, options?: any): Promise<any>;
|
|
631
685
|
_applySafeRebalanceCOW(fills?: any, excludeIds?: any): Promise<any>;
|
|
632
686
|
_getCowComparePrecisions(): {
|
|
633
687
|
buyPrecision: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../modules/order/manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../modules/order/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -27,9 +27,9 @@ import SyncEngine from './sync_engine.js';
|
|
|
27
27
|
import { calculateCurrentSpread, checkSpreadCondition, checkGridHealth } from './grid.js';
|
|
28
28
|
import * as Format from './format.js';
|
|
29
29
|
import { ORDER_TYPES, ORDER_STATES, REBALANCE_STATES, DEFAULT_CONFIG, TIMING, LOG_LEVEL, PIPELINE_TIMING, COW_PERFORMANCE, COW_ACTIONS } from '../constants.js';
|
|
30
|
-
import { getMinOrderSize, computeChainFundTotals, hasValidAccountTotals, resolveConfigValueWithRegistry, isExplicitZeroAllocation, floatToBlockchainInt, validateBoundaryCommit, resolveGapSlots
|
|
30
|
+
import { getMinOrderSize, computeChainFundTotals, hasValidAccountTotals, resolveConfigValueWithRegistry, isExplicitZeroAllocation, floatToBlockchainInt, validateBoundaryCommit, resolveGapSlots } from './utils/math.js';
|
|
31
31
|
import { validateOrder, validateGridForPersistence, validateWorkingGridFunds, checkFundDrift, reconcileGrid, optimizeRebalanceActions, projectTargetToWorkingGrid, buildStateUpdates, buildAbortedResult, buildSuccessResult, evaluateCommit } from './utils/validate.js';
|
|
32
|
-
import { resolveSpreadOrderSide, parseSlotIndex } from './utils/order.js';
|
|
32
|
+
import { resolveSpreadOrderSide, parseSlotIndex, parseChainOrder } from './utils/order.js';
|
|
33
33
|
import { getErrorMessage } from '../utils/errors.js';
|
|
34
34
|
const { toFiniteNumber } = Format;
|
|
35
35
|
// ===============================================================================
|
|
@@ -198,6 +198,25 @@ class COWRebalanceEngine {
|
|
|
198
198
|
this.logger?.log(`[COW] Rebalance planning took ${duration}ms`, 'warn');
|
|
199
199
|
}
|
|
200
200
|
this.logger?.log(`[COW] Plan: Actions=${optimizedActions.length}, StateUpdates=${stateUpdates.length}`, 'info');
|
|
201
|
+
// Per-action plan detail. UPDATE/ROTATE ops are the dangerous ones —
|
|
202
|
+
// their target size/price must be visible in production logs without
|
|
203
|
+
// on-chain archaeology (a mis-sized update op is only diagnosable from
|
|
204
|
+
// the chain afterwards otherwise).
|
|
205
|
+
for (const a of optimizedActions) {
|
|
206
|
+
if (!a || !a.type || !a.id)
|
|
207
|
+
continue;
|
|
208
|
+
const size = Number.isFinite(Number(a.newSize))
|
|
209
|
+
? Number(a.newSize)
|
|
210
|
+
: Number(a.order?.size);
|
|
211
|
+
const price = Number.isFinite(Number(a.newPrice))
|
|
212
|
+
? Number(a.newPrice)
|
|
213
|
+
: Number(a.order?.price);
|
|
214
|
+
const rotationSuffix = (a.newGridId && a.newGridId !== a.id) ? ` -> ${a.newGridId}` : '';
|
|
215
|
+
const line = `[COW] Plan action: ${a.type} ${a.id}${rotationSuffix} ` +
|
|
216
|
+
`(orderId=${a.orderId || 'none'}, size=${Number.isFinite(size) ? Format.formatAmount(size) : 'n/a'}, ` +
|
|
217
|
+
`price=${Number.isFinite(price) ? Format.formatPrice6(price) : 'n/a'})`;
|
|
218
|
+
this.logger?.log(line, a.type === COW_ACTIONS.UPDATE ? 'info' : 'debug');
|
|
219
|
+
}
|
|
201
220
|
return buildSuccessResult({
|
|
202
221
|
actions: optimizedActions,
|
|
203
222
|
stateUpdates,
|
|
@@ -225,6 +244,7 @@ class OrderManager {
|
|
|
225
244
|
_endOfBootstrapValidationDone;
|
|
226
245
|
_broadcastingFlag;
|
|
227
246
|
_broadcastingStartedAt;
|
|
247
|
+
_shuttingDown;
|
|
228
248
|
_illegalStateSignal;
|
|
229
249
|
_accountingFailureSignal;
|
|
230
250
|
_recoveryStateValue;
|
|
@@ -333,6 +353,13 @@ class OrderManager {
|
|
|
333
353
|
_orphanFillsCreditedAt;
|
|
334
354
|
_pendingRecovery;
|
|
335
355
|
_recentFillKeysSnapshot;
|
|
356
|
+
_lastFilledBuyPrice;
|
|
357
|
+
_lastFilledSellPrice;
|
|
358
|
+
_lastFilledPrice;
|
|
359
|
+
_lastFilledType;
|
|
360
|
+
// anchor fields removed
|
|
361
|
+
// Note: dedupe lives inside the anchor object (`_seenKeys`), not here.
|
|
362
|
+
// Kept for backwards compat if external code checks existence; not used.
|
|
336
363
|
_metrics;
|
|
337
364
|
_currentWorkingGridStack;
|
|
338
365
|
_cowEngine;
|
|
@@ -363,6 +390,7 @@ class OrderManager {
|
|
|
363
390
|
this._endOfBootstrapValidationDone = false;
|
|
364
391
|
this._broadcastingFlag = 0;
|
|
365
392
|
this._broadcastingStartedAt = 0;
|
|
393
|
+
this._shuttingDown = false;
|
|
366
394
|
this._illegalStateSignal = null;
|
|
367
395
|
this._accountingFailureSignal = null;
|
|
368
396
|
this._recoveryStateValue = {
|
|
@@ -437,6 +465,10 @@ class OrderManager {
|
|
|
437
465
|
this._pendingRecovery = null;
|
|
438
466
|
this._recentFillKeysSnapshot = null;
|
|
439
467
|
this._lastStaleTotalsWarnAt = {};
|
|
468
|
+
this._lastFilledBuyPrice = null;
|
|
469
|
+
this._lastFilledSellPrice = null;
|
|
470
|
+
this._lastFilledPrice = null;
|
|
471
|
+
this._lastFilledType = null;
|
|
440
472
|
this._metrics = {
|
|
441
473
|
fundRecalcCount: 0,
|
|
442
474
|
lockAcquisitions: 0,
|
|
@@ -545,6 +577,23 @@ class OrderManager {
|
|
|
545
577
|
isBroadcastingActive() {
|
|
546
578
|
return this._broadcastingFlag > 0;
|
|
547
579
|
}
|
|
580
|
+
/**
|
|
581
|
+
* Whether the owning bot has begun shutting down. Mirrors the
|
|
582
|
+
* bot-level `_shuttingDown` flag (set via setShuttingDown() from
|
|
583
|
+
* DEXBot._shutdownImpl) so manager-level wait loops can bail out
|
|
584
|
+
* instead of proceeding with broadcasts after shutdown completed.
|
|
585
|
+
* @returns {boolean}
|
|
586
|
+
*/
|
|
587
|
+
isShuttingDown() {
|
|
588
|
+
return this._shuttingDown === true;
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* @param {boolean} value
|
|
592
|
+
* @returns {void}
|
|
593
|
+
*/
|
|
594
|
+
setShuttingDown(value) {
|
|
595
|
+
this._shuttingDown = value === true;
|
|
596
|
+
}
|
|
548
597
|
/**
|
|
549
598
|
* Auto-clears a stale broadcast flag after 120s so a hung
|
|
550
599
|
* broadcast cannot permanently block rebalancing.
|
|
@@ -611,9 +660,14 @@ class OrderManager {
|
|
|
611
660
|
* @returns {void}
|
|
612
661
|
*/
|
|
613
662
|
startBroadcasting() {
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
663
|
+
// Refresh the stale-watchdog timestamp on EVERY increment, not just
|
|
664
|
+
// the 0→1 transition: with refcounted holders (e.g. structural
|
|
665
|
+
// Phase-2 reconcile + an inner COW batch) measuring only from the
|
|
666
|
+
// first holder's start lets the 120s watchdog hard-reset while a
|
|
667
|
+
// later holder is still legitimately active. Each new holder
|
|
668
|
+
// restarts the window; the commit-refusal backstop bounds any
|
|
669
|
+
// pathological stream of short holders.
|
|
670
|
+
this._broadcastingStartedAt = Date.now();
|
|
617
671
|
this._broadcastingFlag++;
|
|
618
672
|
this.logger?.log?.('[BROADCAST] Flag incremented — fill processing will be deferred until stopBroadcasting()', 'debug');
|
|
619
673
|
}
|
|
@@ -626,6 +680,11 @@ class OrderManager {
|
|
|
626
680
|
}
|
|
627
681
|
if (this._broadcastingFlag === 0) {
|
|
628
682
|
this._broadcastingStartedAt = 0;
|
|
683
|
+
// Runtime hook (wired by the bot): the fill consumer defers while
|
|
684
|
+
// this flag is held and its defer branch returns without
|
|
685
|
+
// rescheduling, so fills enqueued during a long region would
|
|
686
|
+
// starve indefinitely. Fire once when the last region ends.
|
|
687
|
+
this._onBroadcastRegionEnd?.();
|
|
629
688
|
}
|
|
630
689
|
}
|
|
631
690
|
/**
|
|
@@ -1372,71 +1431,149 @@ class OrderManager {
|
|
|
1372
1431
|
`Boundary writes should only happen inside _commitWorkingGrid.`, 'warn');
|
|
1373
1432
|
}
|
|
1374
1433
|
this.boundaryIdx = newIdx;
|
|
1434
|
+
this._logBoundaryDebug('set', newIdx);
|
|
1375
1435
|
}
|
|
1376
1436
|
/**
|
|
1377
1437
|
* Restore boundaryIdx outside the COW commit path (startup, recovery,
|
|
1378
1438
|
* disk-load). This is the same write as _setBoundary but without the
|
|
1379
1439
|
* lock-hold warning — loadGrid / initializeGrid are single-threaded at
|
|
1380
1440
|
* startup and the boundary is being restored from a known-good snapshot,
|
|
1381
|
-
* not committed alongside order mutations.
|
|
1441
|
+
* not committed alongside order mutations. Accepts null to clear the
|
|
1442
|
+
* boundary after a rejected persisted snapshot (P4) so re-derivation
|
|
1443
|
+
* (P3) starts from a clean state.
|
|
1382
1444
|
*/
|
|
1383
1445
|
_restoreBoundary(newIdx) {
|
|
1384
1446
|
this.boundaryIdx = newIdx;
|
|
1447
|
+
this._logBoundaryDebug('restore', newIdx);
|
|
1385
1448
|
}
|
|
1386
1449
|
/**
|
|
1387
|
-
*
|
|
1388
|
-
*
|
|
1389
|
-
*
|
|
1390
|
-
*
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
* (structuralResyncRequested) so the maintenance loop reconciles against
|
|
1394
|
-
* the chain. Purpose is any-writer detection — if a path other than the
|
|
1395
|
-
* promotion clamp commits a boundary that invades the opposite rail or
|
|
1396
|
-
* strands placed orders inside the spread, this fires.
|
|
1397
|
-
*/
|
|
1398
|
-
_assertGapBandIntactPostCommit() {
|
|
1450
|
+
* Observability (fix #4, docs/CONSOLIDATED_ORPHAN_FIX_SUMMARY.md §2): emit the live
|
|
1451
|
+
* boundary whenever roles are (re)assigned, so a silent boundary crawl that
|
|
1452
|
+
* re-rolls slots into the wrong rail is diagnosable in real time. Debug-level
|
|
1453
|
+
* only; no behavioral effect.
|
|
1454
|
+
*/
|
|
1455
|
+
_logBoundaryDebug(source, newIdx) {
|
|
1399
1456
|
try {
|
|
1400
|
-
const
|
|
1401
|
-
|
|
1457
|
+
const self = this;
|
|
1458
|
+
const boundary = newIdx == null ? self.boundaryIdx : newIdx;
|
|
1459
|
+
if (boundary == null)
|
|
1402
1460
|
return;
|
|
1403
|
-
const
|
|
1404
|
-
const
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1461
|
+
const gapSlots = typeof self._gapSlots === 'number' ? self._gapSlots : 0;
|
|
1462
|
+
const sellStart = boundary + 1 + gapSlots;
|
|
1463
|
+
const countActive = (type) => {
|
|
1464
|
+
let n = 0;
|
|
1465
|
+
for (const o of (self.orders?.values?.() || [])) {
|
|
1466
|
+
if (o && o.type === type && o.orderId)
|
|
1467
|
+
n++;
|
|
1468
|
+
}
|
|
1469
|
+
return n;
|
|
1470
|
+
};
|
|
1471
|
+
this.logger?.log?.(`[BOUNDARY] ${source} boundary=${boundary} sellStart=${sellStart} gapSlots=${gapSlots} ` +
|
|
1472
|
+
`spreadCount=${self.currentSpreadCount ?? self.initialSpreadCount ?? '?'} ` +
|
|
1473
|
+
`activeBuy=${countActive(ORDER_TYPES.BUY)} activeSell=${countActive(ORDER_TYPES.SELL)}`, 'debug');
|
|
1474
|
+
}
|
|
1475
|
+
catch {
|
|
1476
|
+
/* observability only — never throw from logging */
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
/**
|
|
1480
|
+
* Record last filled price for side-gated guard: only the side of the most recent fill is gated
|
|
1481
|
+
* (BUY after BUY must be lower, SELL after SELL must be higher). Spread-correction bypasses.
|
|
1482
|
+
* Cold start (null) => disabled. Per-type fields kept for observability/back-compat.
|
|
1483
|
+
* @param {Array} fills
|
|
1484
|
+
*/
|
|
1485
|
+
recordLastFilledPrices(fills) {
|
|
1486
|
+
if (!Array.isArray(fills) || fills.length === 0)
|
|
1487
|
+
return;
|
|
1488
|
+
for (const f of fills) {
|
|
1489
|
+
if (!f || (f.type !== ORDER_TYPES.BUY && f.type !== ORDER_TYPES.SELL))
|
|
1490
|
+
continue;
|
|
1491
|
+
let price = Number(f.price ?? f.order?.price);
|
|
1492
|
+
if (!Number.isFinite(price) || price <= 0) {
|
|
1493
|
+
try {
|
|
1494
|
+
const slot = f.id ? this.orders?.get?.(f.id) : null;
|
|
1495
|
+
price = slot ? Number(slot.price) : null;
|
|
1496
|
+
}
|
|
1497
|
+
catch {
|
|
1498
|
+
price = null;
|
|
1499
|
+
}
|
|
1414
1500
|
}
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1501
|
+
if (!Number.isFinite(price) || price <= 0)
|
|
1502
|
+
continue;
|
|
1503
|
+
this._lastFilledPrice = price;
|
|
1504
|
+
this._lastFilledType = f.type;
|
|
1505
|
+
if (f.type === ORDER_TYPES.BUY)
|
|
1506
|
+
this._lastFilledBuyPrice = price;
|
|
1507
|
+
else if (f.type === ORDER_TYPES.SELL)
|
|
1508
|
+
this._lastFilledSellPrice = price;
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
/**
|
|
1512
|
+
* Seed last-filled guard from the live book at startup. Book-derived
|
|
1513
|
+
* (survives restart), analogous to the deleted MarketAnchor book-seed.
|
|
1514
|
+
* Closes the in-memory-only window where LAST-FILL-GUARD would be
|
|
1515
|
+
* disabled until the first fill arrives.
|
|
1516
|
+
* @param {Array} chainOpenOrders - raw chain open orders (from readOpenOrdersGuarded)
|
|
1517
|
+
*/
|
|
1518
|
+
seedLastFilledPricesFromBook(chainOpenOrders) {
|
|
1519
|
+
if (!Array.isArray(chainOpenOrders) || chainOpenOrders.length === 0)
|
|
1520
|
+
return;
|
|
1521
|
+
if (this._lastFilledPrice != null)
|
|
1522
|
+
return;
|
|
1523
|
+
if (this._lastFilledType != null)
|
|
1524
|
+
return;
|
|
1525
|
+
// Only seed when cold (no fills yet) — don't overwrite a live value.
|
|
1526
|
+
if (this._lastFilledBuyPrice != null && this._lastFilledSellPrice != null)
|
|
1527
|
+
return;
|
|
1528
|
+
try {
|
|
1529
|
+
let maxBuy = null;
|
|
1530
|
+
let minSell = null;
|
|
1531
|
+
for (const o of chainOpenOrders) {
|
|
1532
|
+
const parsed = parseChainOrder(o, this.assets);
|
|
1533
|
+
if (!parsed)
|
|
1534
|
+
continue;
|
|
1535
|
+
const price = Number(parsed.price);
|
|
1536
|
+
if (!Number.isFinite(price) || price <= 0)
|
|
1418
1537
|
continue;
|
|
1419
|
-
if (
|
|
1420
|
-
|
|
1421
|
-
|
|
1538
|
+
if (parsed.type === ORDER_TYPES.BUY) {
|
|
1539
|
+
if (maxBuy == null || price > maxBuy)
|
|
1540
|
+
maxBuy = price;
|
|
1422
1541
|
}
|
|
1542
|
+
else if (parsed.type === ORDER_TYPES.SELL) {
|
|
1543
|
+
if (minSell == null || price < minSell)
|
|
1544
|
+
minSell = price;
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
if (maxBuy != null && this._lastFilledBuyPrice == null)
|
|
1548
|
+
this._lastFilledBuyPrice = maxBuy;
|
|
1549
|
+
if (minSell != null && this._lastFilledSellPrice == null)
|
|
1550
|
+
this._lastFilledSellPrice = minSell;
|
|
1551
|
+
if (this._lastFilledPrice == null) {
|
|
1552
|
+
if (maxBuy != null && minSell != null)
|
|
1553
|
+
this._lastFilledPrice = (maxBuy + minSell) / 2;
|
|
1554
|
+
else if (maxBuy != null)
|
|
1555
|
+
this._lastFilledPrice = maxBuy;
|
|
1556
|
+
else if (minSell != null)
|
|
1557
|
+
this._lastFilledPrice = minSell;
|
|
1423
1558
|
}
|
|
1424
|
-
if (
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
this._recoveryState = {
|
|
1429
|
-
...this._recoveryState,
|
|
1430
|
-
lastFailureAt: Date.now(),
|
|
1431
|
-
structuralResyncRequested: true
|
|
1432
|
-
};
|
|
1559
|
+
if (this._lastFilledType == null) {
|
|
1560
|
+
if (maxBuy != null && minSell != null) {
|
|
1561
|
+
// Seed is ambiguous (no real fill yet) — leave type null so guard stays disabled until first fill
|
|
1562
|
+
this._lastFilledType = null;
|
|
1433
1563
|
}
|
|
1564
|
+
else if (maxBuy != null)
|
|
1565
|
+
this._lastFilledType = ORDER_TYPES.BUY;
|
|
1566
|
+
else if (minSell != null)
|
|
1567
|
+
this._lastFilledType = ORDER_TYPES.SELL;
|
|
1568
|
+
}
|
|
1569
|
+
if (maxBuy != null || minSell != null) {
|
|
1570
|
+
try {
|
|
1571
|
+
this.logger?.log?.(`[LAST-FILL-GUARD] Seeded from book: lastBuy=${maxBuy} lastSell=${minSell} lastPrice=${this._lastFilledPrice} lastType=${this._lastFilledType}`, 'info');
|
|
1572
|
+
}
|
|
1573
|
+
catch { }
|
|
1434
1574
|
}
|
|
1435
1575
|
}
|
|
1436
|
-
catch
|
|
1437
|
-
// Detector must never break the commit path.
|
|
1438
|
-
this.logger.log(`[COW] Gap-band post-commit check failed: ${getErrorMessage(err)}`, 'warn');
|
|
1439
|
-
}
|
|
1576
|
+
catch { }
|
|
1440
1577
|
}
|
|
1441
1578
|
/**
|
|
1442
1579
|
* @returns {Object|null} The consumed signal or null
|
|
@@ -1555,13 +1692,66 @@ class OrderManager {
|
|
|
1555
1692
|
dustThresholdPercent: this.config?.gridLimits?.PARTIAL_DUST_THRESHOLD_PERCENTAGE
|
|
1556
1693
|
});
|
|
1557
1694
|
}
|
|
1695
|
+
/**
|
|
1696
|
+
* Wait (bounded) until any non-COW broadcast/placement activity — the
|
|
1697
|
+
* refcounted _broadcastingFlag — has released. Startup/structural
|
|
1698
|
+
* reconcile Phase-2 placement now holds this flag across its create/update
|
|
1699
|
+
* groups; launching a fill-driven COW rebalance on top of it mutates the
|
|
1700
|
+
* master mid-broadcast, forcing a commit refusal and leaving a
|
|
1701
|
+
* previous-generation order set on chain as duplicate-price orphans
|
|
1702
|
+
* that block placements until drained.
|
|
1703
|
+
*
|
|
1704
|
+
* The wait is capped: after the timeout the rebalance proceeds anyway —
|
|
1705
|
+
* the existing commit-refusal + chain-adoption machinery remains the
|
|
1706
|
+
* backstop, so the worst case equals the pre-guard behavior.
|
|
1707
|
+
*
|
|
1708
|
+
* @param {number} [timeoutMs]
|
|
1709
|
+
* @returns {Promise<{waitedMs: number, timedOut: boolean}>}
|
|
1710
|
+
*/
|
|
1711
|
+
async _awaitBroadcastIdle(timeoutMs = 30000) {
|
|
1712
|
+
if (this._shuttingDown) {
|
|
1713
|
+
return { waitedMs: 0, timedOut: false, shutdown: true };
|
|
1714
|
+
}
|
|
1715
|
+
if (!this.isBroadcastingActive())
|
|
1716
|
+
return { waitedMs: 0, timedOut: false, shutdown: false };
|
|
1717
|
+
const startedAt = Date.now();
|
|
1718
|
+
let logged = false;
|
|
1719
|
+
while (this.isBroadcastingActive()) {
|
|
1720
|
+
if (this._shuttingDown) {
|
|
1721
|
+
this.logger?.log?.(`[SAFE-REBALANCE] Broadcast wait aborted: shutdown in progress after ${Date.now() - startedAt}ms`, 'warn');
|
|
1722
|
+
return { waitedMs: Date.now() - startedAt, timedOut: false, shutdown: true };
|
|
1723
|
+
}
|
|
1724
|
+
const waited = Date.now() - startedAt;
|
|
1725
|
+
if (waited >= timeoutMs) {
|
|
1726
|
+
this.logger?.log?.(`[SAFE-REBALANCE] Broadcast still active after ${waited}ms; proceeding (commit-refusal + chain adoption remains the backstop)`, 'warn');
|
|
1727
|
+
return { waitedMs: waited, timedOut: true, shutdown: false };
|
|
1728
|
+
}
|
|
1729
|
+
if (!logged) {
|
|
1730
|
+
this.logger?.log?.('[SAFE-REBALANCE] Deferring: broadcast/placement activity active (startup/structural reconcile or another batch)', 'info');
|
|
1731
|
+
logged = true;
|
|
1732
|
+
}
|
|
1733
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
1734
|
+
}
|
|
1735
|
+
return { waitedMs: Date.now() - startedAt, timedOut: false, shutdown: false };
|
|
1736
|
+
}
|
|
1558
1737
|
/**
|
|
1559
1738
|
* @param {Array} [fills] - Fill events triggering rebalance
|
|
1560
1739
|
* @param {Set<string>} [excludeIds] - Order IDs to exclude
|
|
1740
|
+
* @param {Object} [options]
|
|
1741
|
+
* @param {boolean} [options.skipBroadcastWait] - Set by the COW re-plan path,
|
|
1742
|
+
* which runs INSIDE its own startBroadcasting() region and must not wait
|
|
1743
|
+
* on the flag it holds itself.
|
|
1561
1744
|
* @returns {Promise<any>}
|
|
1562
1745
|
*/
|
|
1563
|
-
async performSafeRebalance(fills = [], excludeIds = new Set()) {
|
|
1746
|
+
async performSafeRebalance(fills = [], excludeIds = new Set(), options = {}) {
|
|
1564
1747
|
this.logger.log("[SAFE-REBALANCE] Starting with COW...", "info");
|
|
1748
|
+
if (!options?.skipBroadcastWait) {
|
|
1749
|
+
const idle = await this._awaitBroadcastIdle();
|
|
1750
|
+
if (idle.shutdown || this._shuttingDown) {
|
|
1751
|
+
this.logger.log('[SAFE-REBALANCE] Aborting rebalance: shutdown in progress', 'warn');
|
|
1752
|
+
return buildAbortedResult('Shutdown in progress — safe rebalance aborted');
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1565
1755
|
return await this._gridLock.acquire(async () => {
|
|
1566
1756
|
return await this._applySafeRebalanceCOW(fills, excludeIds);
|
|
1567
1757
|
});
|
|
@@ -1719,7 +1909,6 @@ class OrderManager {
|
|
|
1719
1909
|
releaseStackEntry();
|
|
1720
1910
|
return false;
|
|
1721
1911
|
}
|
|
1722
|
-
this._assertGapBandIntactPostCommit();
|
|
1723
1912
|
try {
|
|
1724
1913
|
if (!skipRecalc) {
|
|
1725
1914
|
// If the last accounting failure was due to stale accountTotals,
|