From d2867ba98c6219b6cd918000115833b7a4630d35 Mon Sep 17 00:00:00 2001 From: discountry Date: Mon, 6 Oct 2025 19:06:49 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E5=8D=8F=E8=B0=83=E5=99=A8=E5=92=8C=20GRVT=20=E9=80=82?= =?UTF-8?q?=E9=85=8D=E5=99=A8=EF=BC=8C=E6=B7=BB=E5=8A=A0=E8=A7=A6=E5=8F=91?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E6=94=AF=E6=8C=81=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E8=B6=8B=E5=8A=BF=E5=BC=95=E6=93=8E=E7=9A=84=E6=8D=9F=E7=9B=8A?= =?UTF-8?q?=E8=AE=A1=E7=AE=97=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/order-coordinator.ts | 1 + src/exchanges/grvt/gateway.ts | 2 +- src/exchanges/types.ts | 1 + src/strategy/trend-engine.ts | 23 +++++++++++++++-------- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/core/order-coordinator.ts b/src/core/order-coordinator.ts index e56e603..bff87cc 100644 --- a/src/core/order-coordinator.ts +++ b/src/core/order-coordinator.ts @@ -242,6 +242,7 @@ export async function placeStopLossOrder( closePosition: "true", timeInForce: "GTC", quantity: roundQtyDownToStep(quantity, qtyStep), + triggerType: "STOP_LOSS", }; // 部分交易所(例如 Paradex)要求 STOP_MARKET 同时提供 price 字段 params.price = params.stopPrice; diff --git a/src/exchanges/grvt/gateway.ts b/src/exchanges/grvt/gateway.ts index cd4fff1..2412c1f 100644 --- a/src/exchanges/grvt/gateway.ts +++ b/src/exchanges/grvt/gateway.ts @@ -1337,7 +1337,7 @@ function buildUnsignedOrder(params: { function buildTriggerMetadata(params: CreateOrderParams): GrvtUnsignedOrder["metadata"]["trigger"] | undefined { if (params.type === "STOP_MARKET") { - const triggerType = params.side === "BUY" ? "TAKE_PROFIT" : "STOP_LOSS"; + const triggerType = params.triggerType ?? (params.side === "BUY" ? "TAKE_PROFIT" : "STOP_LOSS"); const stopPrice = params.stopPrice ?? params.activationPrice; if (!stopPrice) { throw new Error("GRVT stop orders require a stopPrice or activationPrice"); diff --git a/src/exchanges/types.ts b/src/exchanges/types.ts index 6ff56c4..f41eeae 100644 --- a/src/exchanges/types.ts +++ b/src/exchanges/types.ts @@ -21,6 +21,7 @@ export interface CreateOrderParams { timeInForce?: TimeInForce; reduceOnly?: StringBoolean; closePosition?: StringBoolean; + triggerType?: "UNSPECIFIED" | "TAKE_PROFIT" | "STOP_LOSS"; } export interface AsterAccountPosition { diff --git a/src/strategy/trend-engine.ts b/src/strategy/trend-engine.ts index 6c7254c..3364d11 100644 --- a/src/strategy/trend-engine.ts +++ b/src/strategy/trend-engine.ts @@ -509,10 +509,21 @@ export class TrendEngine { } this.entryPricePendingLogged = false; const direction = position.positionAmt > 0 ? "long" : "short"; + const qtyAbs = Math.abs(position.positionAmt); + const depthBid = Number(this.depthSnapshot?.bids?.[0]?.[0]); + const depthAsk = Number(this.depthSnapshot?.asks?.[0]?.[0]); + const closeSidePriceRaw = direction === "long" ? depthBid : depthAsk; + const effectiveClosePrice = Number.isFinite(closeSidePriceRaw) + ? closeSidePriceRaw + : Number.isFinite(price) + ? price + : position.entryPrice; const pnl = - (direction === "long" - ? price - position.entryPrice - : position.entryPrice - price) * Math.abs(position.positionAmt); + qtyAbs > 0 + ? (direction === "long" + ? effectiveClosePrice - position.entryPrice + : position.entryPrice - effectiveClosePrice) * qtyAbs + : 0; const unrealized = Number.isFinite(position.unrealizedProfit) ? position.unrealizedProfit : null; @@ -671,11 +682,7 @@ export class TrendEngine { } const derivedLoss = pnl < -this.config.lossLimit; - const snapshotLoss = Boolean( - unrealized != null && - unrealized < -this.config.lossLimit && - pnl <= 0 - ); + const snapshotLoss = derivedLoss; if (derivedLoss || snapshotLoss) { const result = { closed: false, pnl };