diff --git a/app/api/automation/trade/route.js b/app/api/automation/trade/route.js index a9a0996..7b41e13 100644 --- a/app/api/automation/trade/route.js +++ b/app/api/automation/trade/route.js @@ -58,18 +58,22 @@ export async function POST(request) { if (dexProvider === 'DRIFT') { console.log('🌊 Routing to Drift Protocol...') - // Call Drift API + // Call Drift API with correct action for trading const driftResponse = await fetch(`${process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3000'}/api/drift/trade`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ - action, + action: 'place_order', // This was missing! Was defaulting to 'get_balance' symbol: symbol.replace('USD', ''), // Convert SOLUSD to SOL amount, side, - leverage + leverage, + // Add stop loss and take profit parameters + stopLoss: true, + takeProfit: true, + riskPercent: 2 // 2% risk per trade }) }) diff --git a/app/api/drift/trade/route.js b/app/api/drift/trade/route.js index 23cdeb0..56ab27d 100644 --- a/app/api/drift/trade/route.js +++ b/app/api/drift/trade/route.js @@ -98,7 +98,16 @@ export async function POST(request) { }, { status: 400 }) } - const { action = 'get_balance', symbol = 'SOL', amount, side, leverage = 1 } = await request.json() + const { + action = 'get_balance', + symbol = 'SOL', + amount, + side, + leverage = 1, + stopLoss = true, + takeProfit = true, + riskPercent = 2 + } = await request.json() // Import Drift SDK components const { DriftClient, initialize } = await import('@drift-labs/sdk') @@ -193,7 +202,7 @@ export async function POST(request) { } } } else if (action === 'place_order') { - // Place a leverage order + // Place a leverage order with stop loss and take profit if (!amount || !side) { result = { error: 'Missing required parameters: amount and side' @@ -205,6 +214,12 @@ export async function POST(request) { const marketIndex = getMarketIndex(symbol) + // Get current market price for stop loss/take profit calculations + const perpMarketAccount = driftClient.getPerpMarketAccount(marketIndex) + const currentPrice = Number(perpMarketAccount.amm.lastMarkPriceTwap) / 1e6 + + console.log(`📊 Current ${symbol} price: $${currentPrice}`) + // Convert amount to base units (SOL uses 9 decimals) const baseAssetAmount = new BN(Math.floor(amount * 1e9)) @@ -223,11 +238,13 @@ export async function POST(request) { marketIndex, amount, leverage, + currentPrice, baseAssetAmount: baseAssetAmount.toString() }) - // Place perpetual order - const txSig = await driftClient.placePerpOrder({ + // 1. Place main perpetual market order + console.log('🚀 Placing main market order...') + const mainOrderTx = await driftClient.placePerpOrder({ orderType: OrderType.MARKET, marketIndex, direction, @@ -235,30 +252,114 @@ export async function POST(request) { reduceOnly: false, }) - console.log('✅ Order placed:', txSig) + console.log('✅ Main order placed:', mainOrderTx) - // Wait for confirmation - await new Promise(resolve => setTimeout(resolve, 3000)) + // Wait for main order to fill + await new Promise(resolve => setTimeout(resolve, 5000)) - // Get position after order + // 2. Calculate stop loss and take profit prices + const stopLossPercent = riskPercent / 100 // Convert 2% to 0.02 + const takeProfitPercent = stopLossPercent * 2 // 2:1 risk reward ratio + + let stopLossPrice, takeProfitPrice + + if (direction === PositionDirection.LONG) { + stopLossPrice = currentPrice * (1 - stopLossPercent) + takeProfitPrice = currentPrice * (1 + takeProfitPercent) + } else { + stopLossPrice = currentPrice * (1 + stopLossPercent) + takeProfitPrice = currentPrice * (1 - takeProfitPercent) + } + + console.log(`🎯 Risk management:`, { + stopLossPrice: stopLossPrice.toFixed(4), + takeProfitPrice: takeProfitPrice.toFixed(4), + riskPercent: `${riskPercent}%`, + rewardRatio: '2:1' + }) + + let stopLossTx = null, takeProfitTx = null + + // 3. Place stop loss order + if (stopLoss) { + try { + console.log('🛡️ Placing stop loss order...') + + const stopLossTriggerPrice = new BN(Math.floor(stopLossPrice * 1e6)) + const stopLossOrderPrice = new BN(Math.floor(stopLossPrice * 0.99 * 1e6)) // Slightly worse price to ensure execution + + stopLossTx = await driftClient.placePerpOrder({ + orderType: OrderType.TRIGGER_LIMIT, + marketIndex, + direction: direction === PositionDirection.LONG ? PositionDirection.SHORT : PositionDirection.LONG, + baseAssetAmount, + price: stopLossOrderPrice, + triggerPrice: stopLossTriggerPrice, + reduceOnly: true, + }) + + console.log('✅ Stop loss placed:', stopLossTx) + } catch (slError) { + console.warn('⚠️ Stop loss failed:', slError.message) + } + } + + // 4. Place take profit order + if (takeProfit) { + try { + console.log('🎯 Placing take profit order...') + + const takeProfitTriggerPrice = new BN(Math.floor(takeProfitPrice * 1e6)) + const takeProfitOrderPrice = new BN(Math.floor(takeProfitPrice * 1.01 * 1e6)) // Slightly better price to ensure execution + + takeProfitTx = await driftClient.placePerpOrder({ + orderType: OrderType.TRIGGER_LIMIT, + marketIndex, + direction: direction === PositionDirection.LONG ? PositionDirection.SHORT : PositionDirection.LONG, + baseAssetAmount, + price: takeProfitOrderPrice, + triggerPrice: takeProfitTriggerPrice, + reduceOnly: true, + }) + + console.log('✅ Take profit placed:', takeProfitTx) + } catch (tpError) { + console.warn('⚠️ Take profit failed:', tpError.message) + } + } + + // 5. Get final position after all orders const userAccount = await driftClient.getUserAccount() - const position = userAccount.perpPositions.find(pos => pos.marketIndex === marketIndex) + const position = userAccount.perpPositions.find(pos => pos.marketIndex === marketIndex && !pos.baseAssetAmount.isZero()) result = { - transactionId: txSig, + success: true, + transactionId: mainOrderTx, + stopLossTransactionId: stopLossTx, + takeProfitTransactionId: takeProfitTx, symbol, side, amount, leverage, + currentPrice, + stopLossPrice: stopLoss ? stopLossPrice : null, + takeProfitPrice: takeProfit ? takeProfitPrice : null, + riskManagement: { + stopLoss: !!stopLossTx, + takeProfit: !!takeProfitTx, + riskPercent + }, position: position ? { marketIndex: position.marketIndex, baseAssetAmount: position.baseAssetAmount.toString(), - quoteAssetAmount: position.quoteAssetAmount.toString() + quoteAssetAmount: position.quoteAssetAmount.toString(), + avgEntryPrice: (Number(position.quoteAssetAmount) / Number(position.baseAssetAmount) * 1e9).toFixed(4) } : null } } catch (orderError) { console.log('❌ Failed to place order:', orderError.message) result = { + success: false, error: 'Failed to place order', details: orderError.message } diff --git a/prisma/prisma/dev.db b/prisma/prisma/dev.db index 89cdd11..ba4b9f7 100644 Binary files a/prisma/prisma/dev.db and b/prisma/prisma/dev.db differ