From e96cbb6ff4ce3538f07d7b2023db2c97baf02de5 Mon Sep 17 00:00:00 2001 From: discountry Date: Wed, 8 Oct 2025 19:48:25 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0Paradex=E7=BD=91?= =?UTF-8?q?=E5=85=B3=EF=BC=8C=E6=B7=BB=E5=8A=A0=E5=B9=B3=E4=BB=93=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E4=BB=A5=E4=BC=98=E5=8C=96=E8=AE=A2=E5=8D=95=E9=87=91?= =?UTF-8?q?=E9=A2=9D=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/exchanges/paradex/gateway.ts | 39 +++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/exchanges/paradex/gateway.ts b/src/exchanges/paradex/gateway.ts index bb49a1f..be3a644 100644 --- a/src/exchanges/paradex/gateway.ts +++ b/src/exchanges/paradex/gateway.ts @@ -551,7 +551,7 @@ export class ParadexGateway { const symbol = this.marketSymbol; const type = this.mapOrderTypeToCcxt(params.type); const side = params.side.toLowerCase(); - const amount = params.quantity; + let amount = params.quantity; const price = params.price; const extraParams: Record = {}; @@ -560,6 +560,43 @@ export class ParadexGateway { if (params.reduceOnly !== undefined) { extraParams.reduceOnly = params.reduceOnly === "true"; } + if (params.closePosition !== undefined) { + // propagate closePosition flag to the exchange params when provided + (extraParams as any).closePosition = params.closePosition === "true"; + } + + // Normalize amount for Paradex according to market precision/limits. + // Particularly important for STOP_MARKET closePosition orders where rounding + // upstream may result in 0 due to larger strategy qtyStep. + try { + const market = typeof (this.exchange as any).market === "function" + ? (this.exchange as any).market(symbol) + : (this.exchange.markets ?? {})[symbol]; + const precisionDigits = Number((market?.precision?.amount ?? market?.amountPrecision)); + const limitMin = Number(market?.limits?.amount?.min); + const minByPrecision = Number.isFinite(precisionDigits) && precisionDigits > 0 + ? Number(Math.pow(10, -precisionDigits).toFixed(Math.max(0, precisionDigits))) + : undefined; + const minAmount = Number.isFinite(limitMin) && limitMin > 0 + ? limitMin + : (minByPrecision ?? undefined); + + // If closePosition is requested and amount is missing or too small, bump to minimum allowed + const isClosePosition = (extraParams as any).closePosition === true; + if (isClosePosition) { + const current = Number(amount); + if (!Number.isFinite(current) || current <= 0 || (Number.isFinite(minAmount) && current < (minAmount as number))) { + amount = (minAmount as number) ?? 1e-5; // sensible fallback if market data is missing + } + } + + // Quantize to exchange precision if helper is available + if (typeof (this.exchange as any).amountToPrecision === "function" && Number.isFinite(Number(amount))) { + amount = Number((this.exchange as any).amountToPrecision(symbol, amount)); + } + } catch (_normalizeError) { + // Swallow precision normalization errors and let exchange validation surface if any + } try { const order = (await this.exchange.createOrder(