From 797e80b56abad600ceb6a97183330712af20cf4c Mon Sep 17 00:00:00 2001 From: mindesbunister Date: Wed, 29 Oct 2025 17:34:10 +0100 Subject: [PATCH] CRITICAL FIX: TP/SL orders using wrong size calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **ROOT CAUSE:** placeExitOrders() calculated position size using TP/SL prices instead of entry price **Problem:** - TP1 order size: 85 / TP1_price (00.746) = 2.914 SOL - Actual position: 80 / entry_price (99.946) = 3.901 SOL - TP1 should close: 3.901 * 75% = 2.926 SOL - But it only closed: 2.914 SOL = 74.7% ❌ WRONG! **Result:** TP1 closed ~25% instead of 75%, no runner left **Fix:** - Changed usdToBase() to use entryPrice for ALL size calculations - Added entryPrice param to PlaceExitOrdersOptions interface - Updated all API routes to pass entryPrice **Testing:** Next trade will have correctly sized TP/SL orders --- .env | 2 +- app/api/trading/execute/route.ts | 1 + app/api/trading/reduce-position/route.ts | 1 + app/api/trading/scale-position/route.ts | 1 + app/api/trading/test-db/route.ts | 1 + app/api/trading/test/route.ts | 1 + lib/drift/orders.ts | 13 ++++++++----- 7 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.env b/.env index 7018327..69db2f0 100644 --- a/.env +++ b/.env @@ -61,7 +61,7 @@ PYTH_HERMES_URL=https://hermes.pyth.network # Position sizing # Base position size in USD (default: 50 for safe testing) # Example: 50 with 10x leverage = $500 notional position -MAX_POSITION_SIZE_USD=78 +MAX_POSITION_SIZE_USD=54 # Leverage multiplier (1-20, default: 10) # Higher leverage = bigger gains AND bigger losses diff --git a/app/api/trading/execute/route.ts b/app/api/trading/execute/route.ts index fb48142..23d0633 100644 --- a/app/api/trading/execute/route.ts +++ b/app/api/trading/execute/route.ts @@ -251,6 +251,7 @@ export async function POST(request: NextRequest): Promise { - const base = usd / price + // CRITICAL: Use ENTRY price to calculate position size, not TP price! + // This ensures we close the correct percentage of the actual position + const usdToBase = (usd: number) => { + const base = usd / options.entryPrice // Use entry price for size calculation return Math.floor(base * 1e9) // 9 decimals expected by SDK } @@ -244,7 +247,7 @@ export async function placeExitOrders(options: PlaceExitOrdersOptions): Promise< // Place TP1 LIMIT reduce-only if (tp1USD > 0) { - const baseAmount = usdToBase(tp1USD, options.tp1Price) + const baseAmount = usdToBase(tp1USD) if (baseAmount >= Math.floor(marketConfig.minOrderSize * 1e9)) { const orderParams: any = { orderType: OrderType.LIMIT, @@ -266,7 +269,7 @@ export async function placeExitOrders(options: PlaceExitOrdersOptions): Promise< // Place TP2 LIMIT reduce-only if (tp2USD > 0) { - const baseAmount = usdToBase(tp2USD, options.tp2Price) + const baseAmount = usdToBase(tp2USD) if (baseAmount >= Math.floor(marketConfig.minOrderSize * 1e9)) { const orderParams: any = { orderType: OrderType.LIMIT, @@ -293,7 +296,7 @@ export async function placeExitOrders(options: PlaceExitOrdersOptions): Promise< // 3. Single TRIGGER_MARKET (default, guaranteed execution) const slUSD = options.positionSizeUSD - const slBaseAmount = usdToBase(slUSD, options.stopLossPrice) + const slBaseAmount = usdToBase(slUSD) if (slBaseAmount >= Math.floor(marketConfig.minOrderSize * 1e9)) { const useDualStops = options.useDualStops ?? false