From b31b98f8168950cc89620e7b3f14e3ac9df1fe80 Mon Sep 17 00:00:00 2001 From: discountry Date: Wed, 8 Oct 2025 01:55:05 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E7=BD=91=E6=A0=BC?= =?UTF-8?q?=E5=BC=95=E6=93=8E=EF=BC=8C=E6=B7=BB=E5=8A=A0=E5=8D=B3=E6=97=B6?= =?UTF-8?q?=E5=B9=B3=E4=BB=93=E8=AE=A2=E5=8D=95=E9=98=9F=E5=88=97=E4=BB=A5?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AE=A2=E5=8D=95=E5=A4=84=E7=90=86=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/strategy/grid-engine.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/strategy/grid-engine.ts b/src/strategy/grid-engine.ts index 1ca5574..c92dd80 100644 --- a/src/strategy/grid-engine.ts +++ b/src/strategy/grid-engine.ts @@ -105,6 +105,7 @@ export class GridEngine { private startupCleaned = false; private initialCloseHandled = false; private lastAbsPositionAmt = 0; + private immediateCloseToPlace: Array<{ sourceLevel: number; targetLevel: number; side: "BUY" | "SELL"; price: string }> = []; private accountSnapshot: AsterAccountSnapshot | null = null; private depthSnapshot: AsterDepth | null = null; @@ -526,6 +527,15 @@ export class GridEngine { if (classified === "filled") { if (meta.side === "BUY") this.pendingLongLevels.add(meta.level); else this.pendingShortLevels.add(meta.level); + // Immediately queue a close at the mapped target to ensure it is placed this tick + const target = this.levelMeta[meta.level]?.closeTarget; + if (target != null) { + const priceStr = this.formatPrice(this.gridLevels[target]!); + const side: "BUY" | "SELL" = meta.side === "BUY" ? "SELL" : "BUY"; + this.immediateCloseToPlace.push({ sourceLevel: meta.level, targetLevel: target, side, price: priceStr }); + // also map source->close key for disappearance tracking + this.closeKeyBySourceLevel.set(meta.level, this.getOrderKey(side, priceStr, false)); + } } else if (classified === "canceled") { // no action; allow immediate re-open (do not block) this.awaitingClassification.delete(meta.level); @@ -573,6 +583,19 @@ export class GridEngine { activeKeyCounts.set(k, (activeKeyCounts.get(k) ?? 0) + 1); } + // First, place any immediate close orders queued by fresh fills + if (this.immediateCloseToPlace.length) { + for (const item of this.immediateCloseToPlace) { + const key = this.getOrderKey(item.side, item.price, false); + const count = activeKeyCounts.get(key) ?? 0; + if (count < 2) { + desired.push({ level: item.targetLevel, side: item.side, price: item.price, amount: this.config.orderSize, reduceOnly: false }); + } + } + // clear queue regardless to avoid duplicates next tick + this.immediateCloseToPlace = []; + } + // opens below price (BUY) for (const level of this.buyLevelIndices) { const levelPrice = this.gridLevels[level]!;