From 7612e25dd1942ebb10baf9ae5bbfba479c781a62 Mon Sep 17 00:00:00 2001 From: discountry Date: Sun, 7 Dec 2025 22:33:56 +0800 Subject: [PATCH] add stoploss --- src/exchanges/lighter/gateway.ts | 23 +++++++++++++++++------ src/strategy/offset-maker-engine.ts | 2 ++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/exchanges/lighter/gateway.ts b/src/exchanges/lighter/gateway.ts index e62eac0..e88a322 100644 --- a/src/exchanges/lighter/gateway.ts +++ b/src/exchanges/lighter/gateway.ts @@ -1756,7 +1756,7 @@ export class LighterGateway { return qty; } - private getAvailableAssetAmount(assetId?: number | null, symbol?: string | null): number | null { + private getAvailableAssetAmount(assetId?: number | null, symbol?: string | null): { available: number | null; wallet: number | null } { if (!this.assets.size) return null; const normalizedSymbol = symbol ? symbol.toUpperCase() : null; for (const asset of this.assets.values()) { @@ -1767,19 +1767,30 @@ export class LighterGateway { const locked = parseNumber(asset.locked_balance ?? 0); if (balance == null) continue; const available = locked != null ? balance - locked : balance; - return Number.isFinite(available) ? available : null; + return { + available: Number.isFinite(available) ? available : null, + wallet: Number.isFinite(balance) ? balance : null, + }; } - return null; + return { available: null, wallet: null }; } private assertSpotBalance(params: { isAsk: boolean; quantity: number | null | undefined; price: number | null }): void { const qty = Number(params.quantity); if (!Number.isFinite(qty) || qty <= 0) return; if (params.isAsk) { - const availableBase = this.getAvailableAssetAmount(this.baseAssetId, this.baseAssetSymbol); - if (availableBase != null && availableBase + 1e-9 < qty) { + const baseAmounts = this.getAvailableAssetAmount(this.baseAssetId, this.baseAssetSymbol); + const availableBase = baseAmounts?.available ?? null; + const walletBase = baseAmounts?.wallet ?? null; + const effective = Math.max( + availableBase != null && Number.isFinite(availableBase) ? availableBase : 0, + walletBase != null && Number.isFinite(walletBase) ? walletBase : 0 + ); + if (effective + 1e-9 < qty) { throw new Error( - `Insufficient base asset (${this.baseAssetSymbol ?? "BASE"} available ${availableBase}) for spot sell ${qty}` + `Insufficient base asset (${this.baseAssetSymbol ?? "BASE"} available ${availableBase ?? 0}${ + walletBase != null ? ` wallet ${walletBase}` : "" + }) for spot sell ${qty}` ); } return; diff --git a/src/strategy/offset-maker-engine.ts b/src/strategy/offset-maker-engine.ts index 4e3193a..4b39c93 100644 --- a/src/strategy/offset-maker-engine.ts +++ b/src/strategy/offset-maker-engine.ts @@ -780,6 +780,8 @@ export class OffsetMakerEngine { if (!triggerStop) return; this.tradeLog.push("stop", `现货止损,当前仓位=${absPosition.toFixed(6)} PnL=${pnl.toFixed(4)} USDT`); try { + // 尽力撤销所有未完成挂单,避免锁定基础资产导致余额不足 + await this.exchange.cancelAllOrders({ symbol: this.config.symbol }).catch(() => {}); await this.flushOrders(); await marketClose( this.exchange,