diff --git a/app/api/drift/cleanup-orders/route.js b/app/api/drift/cleanup-orders/route.js index d37c979..524aa9c 100644 --- a/app/api/drift/cleanup-orders/route.js +++ b/app/api/drift/cleanup-orders/route.js @@ -99,13 +99,9 @@ export async function POST() { // Check if this order is for a market where we have no position const hasPosition = positionMarkets.has(order.marketIndex) - // CRITICAL FIX: Only cancel reduce-only orders if there's NO position - // Stop Loss and Take Profit orders are reduce-only but should EXIST when we have a position - const isReduceOnly = order.reduceOnly - - // Only cancel orders that are truly orphaned (no position for that market) - // Do NOT cancel reduce-only orders when we have a position (these are SL/TP!) - return !hasPosition && !isReduceOnly + // CORRECTED LOGIC: Cancel ALL orders when no position exists + // If we have no position, then ALL orders (including SL/TP) are orphaned + return !hasPosition }) // Additionally, find lingering SL/TP orders when position has changed significantly diff --git a/app/api/drift/place-order/route.js b/app/api/drift/place-order/route.js index bf33523..9c0df77 100644 --- a/app/api/drift/place-order/route.js +++ b/app/api/drift/place-order/route.js @@ -24,7 +24,7 @@ export async function POST(request) { }); // Import Drift SDK - const { DriftClient, initialize, MarketType, PositionDirection, OrderType, OrderTriggerCondition, Wallet, BN } = await import('@drift-labs/sdk'); + const { DriftClient, initialize, MarketType, PositionDirection, OrderType, OrderTriggerCondition, BN } = await import('@drift-labs/sdk'); const { Connection, Keypair } = await import('@solana/web3.js'); // Setup connection and wallet @@ -40,7 +40,10 @@ export async function POST(request) { const privateKeyArray = JSON.parse(process.env.SOLANA_PRIVATE_KEY); const keypair = Keypair.fromSecretKey(new Uint8Array(privateKeyArray)); - const wallet = new Wallet(keypair); + + // Use the correct Wallet class like in cleanup endpoint + const { default: NodeWallet } = await import('@coral-xyz/anchor/dist/cjs/nodewallet.js'); + const wallet = new NodeWallet(keypair); // Initialize Drift client const env = 'mainnet-beta'; @@ -49,12 +52,9 @@ export async function POST(request) { connection, wallet, programID: sdkConfig.DRIFT_PROGRAM_ID, - accountSubscription: { - type: 'polling', - accountLoader: { - commitment: 'confirmed' - } - } + opts: { + commitment: 'confirmed', + }, }); await driftClient.subscribe(); diff --git a/app/api/trading/execute-drift/route.js b/app/api/trading/execute-drift/route.js index 1aa54f8..8224d8a 100644 --- a/app/api/trading/execute-drift/route.js +++ b/app/api/trading/execute-drift/route.js @@ -216,11 +216,28 @@ export async function POST(request) { console.log('✅ Drift order placed:', txSig) + // Validate trigger distances before placing SL/TP orders + const MIN_TRIGGER_DISTANCE_PERCENT = 2.0; // Minimum 2% distance from current price + // Set up stop loss and take profit if specified let stopLossOrderId = null let takeProfitOrderId = null if (stopLoss) { + // Validate stop loss distance + const slDistance = Math.abs(stopLoss - currentPrice) / currentPrice * 100; + + if (slDistance < MIN_TRIGGER_DISTANCE_PERCENT) { + console.warn(`⚠️ Stop loss too close: ${slDistance.toFixed(2)}% < ${MIN_TRIGGER_DISTANCE_PERCENT}% minimum`); + // Adjust stop loss to minimum distance + if (direction === PositionDirection.LONG) { + stopLoss = currentPrice * (1 - MIN_TRIGGER_DISTANCE_PERCENT / 100); + } else { + stopLoss = currentPrice * (1 + MIN_TRIGGER_DISTANCE_PERCENT / 100); + } + console.log(`🔧 Adjusted stop loss to: $${stopLoss.toFixed(4)} (${MIN_TRIGGER_DISTANCE_PERCENT}% distance)`); + } + try { const stopLossParams = { orderType: OrderType.TRIGGER_LIMIT, @@ -243,6 +260,20 @@ export async function POST(request) { } if (takeProfit) { + // Validate take profit distance + const tpDistance = Math.abs(takeProfit - currentPrice) / currentPrice * 100; + + if (tpDistance < MIN_TRIGGER_DISTANCE_PERCENT) { + console.warn(`⚠️ Take profit too close: ${tpDistance.toFixed(2)}% < ${MIN_TRIGGER_DISTANCE_PERCENT}% minimum`); + // Adjust take profit to minimum distance + if (direction === PositionDirection.LONG) { + takeProfit = currentPrice * (1 + MIN_TRIGGER_DISTANCE_PERCENT / 100); + } else { + takeProfit = currentPrice * (1 - MIN_TRIGGER_DISTANCE_PERCENT / 100); + } + console.log(`🔧 Adjusted take profit to: $${takeProfit.toFixed(4)} (${MIN_TRIGGER_DISTANCE_PERCENT}% distance)`); + } + try { const takeProfitParams = { orderType: OrderType.TRIGGER_LIMIT, diff --git a/prisma/prisma/dev.db b/prisma/prisma/dev.db index 0da04d8..c51cca2 100644 Binary files a/prisma/prisma/dev.db and b/prisma/prisma/dev.db differ