/** * Scale Position API Endpoint * * Adds to an existing position and recalculates TP/SL orders * POST /api/trading/scale-position */ import { NextRequest, NextResponse } from 'next/server' import { getMergedConfig } from '@/config/trading' import { getInitializedPositionManager } from '@/lib/trading/position-manager' import { initializeDriftService } from '@/lib/drift/client' import { openPosition, placeExitOrders, cancelAllOrders } from '@/lib/drift/orders' interface ScalePositionRequest { tradeId: string scalePercent?: number // 50 = add 50%, 100 = double position } interface ScalePositionResponse { success: boolean message: string oldEntry?: number newEntry?: number oldSize?: number newSize?: number newTP1?: number newTP2?: number newSL?: number } export async function POST(request: NextRequest): Promise> { try { // Verify authorization const authHeader = request.headers.get('authorization') const expectedAuth = `Bearer ${process.env.API_SECRET_KEY}` if (!authHeader || authHeader !== expectedAuth) { return NextResponse.json( { success: false, message: 'Unauthorized', }, { status: 401 } ) } const body: ScalePositionRequest = await request.json() console.log('📈 Scaling position:', body) if (!body.tradeId) { return NextResponse.json( { success: false, message: 'tradeId is required', }, { status: 400 } ) } const scalePercent = body.scalePercent || 50 // Default: add 50% // Get current configuration const config = getMergedConfig() // Get Position Manager const positionManager = await getInitializedPositionManager() const activeTrades = positionManager.getActiveTrades() const trade = activeTrades.find(t => t.id === body.tradeId) if (!trade) { return NextResponse.json( { success: false, message: `Position ${body.tradeId} not found`, }, { status: 404 } ) } console.log(`📊 Current position: ${trade.symbol} ${trade.direction}`) console.log(` Entry: $${trade.entryPrice}`) console.log(` Size: ${trade.currentSize} (${trade.positionSize} USD)`) console.log(` Scaling by: ${scalePercent}%`) // Initialize Drift service const driftService = await initializeDriftService() // Check account health before scaling const healthData = await driftService.getAccountHealth() const healthPercent = healthData.marginRatio console.log(`💊 Account health: ${healthPercent}%`) if (healthPercent < 30) { return NextResponse.json( { success: false, message: `Account health too low (${healthPercent}%) to scale position`, }, { status: 400 } ) } // Calculate additional position size const additionalSizeUSD = (trade.positionSize * scalePercent) / 100 console.log(`💰 Adding $${additionalSizeUSD} to position...`) // Open additional position at market const addResult = await openPosition({ symbol: trade.symbol, direction: trade.direction, sizeUSD: additionalSizeUSD, slippageTolerance: config.slippageTolerance, }) if (!addResult.success || !addResult.fillPrice) { throw new Error(`Failed to open additional position: ${addResult.error}`) } console.log(`✅ Additional position opened at $${addResult.fillPrice}`) // Calculate new average entry price const oldTotalValue = trade.positionSize const newTotalValue = oldTotalValue + additionalSizeUSD const oldEntry = trade.entryPrice const newEntryContribution = addResult.fillPrice // Weighted average: (old_size * old_price + new_size * new_price) / total_size const newAvgEntry = ( (oldTotalValue * oldEntry) + (additionalSizeUSD * newEntryContribution) ) / newTotalValue console.log(`📊 New average entry: $${oldEntry} → $${newAvgEntry}`) console.log(`📊 New position size: $${oldTotalValue} → $${newTotalValue}`) // Cancel all existing exit orders console.log('🗑️ Cancelling old TP/SL orders...') try { await cancelAllOrders(trade.symbol) console.log('✅ Old orders cancelled') } catch (cancelError) { console.error('⚠️ Failed to cancel orders:', cancelError) // Continue anyway - might not have any orders } // Calculate new TP/SL prices based on new average entry const calculatePrice = (entry: number, percent: number, direction: 'long' | 'short') => { if (direction === 'long') { return entry * (1 + percent / 100) } else { return entry * (1 - percent / 100) } } const newTP1 = calculatePrice(newAvgEntry, config.takeProfit1Percent, trade.direction) const newTP2 = calculatePrice(newAvgEntry, config.takeProfit2Percent, trade.direction) const newSL = calculatePrice(newAvgEntry, config.stopLossPercent, trade.direction) const effectiveTp2SizePercent = config.useTp2AsTriggerOnly && (config.takeProfit2SizePercent ?? 0) <= 0 ? 0 : (config.takeProfit2SizePercent ?? 0) console.log(`🎯 New targets:`) console.log(` TP1: $${newTP1} (${config.takeProfit1Percent}%)`) console.log(` TP2: $${newTP2} (${config.takeProfit2Percent}%)`) console.log(` SL: $${newSL} (${config.stopLossPercent}%)`) // Place new exit orders console.log('📝 Placing new TP/SL orders...') const exitOrders = await placeExitOrders({ symbol: trade.symbol, direction: trade.direction, positionSizeUSD: newTotalValue, entryPrice: newAvgEntry, tp1Price: newTP1, tp2Price: newTP2, stopLossPrice: newSL, tp1SizePercent: config.takeProfit1SizePercent, tp2SizePercent: effectiveTp2SizePercent, useDualStops: config.useDualStops, softStopPrice: config.useDualStops ? calculatePrice(newAvgEntry, config.softStopPercent, trade.direction) : undefined, softStopBuffer: config.useDualStops ? config.softStopBuffer : undefined, hardStopPrice: config.useDualStops ? calculatePrice(newAvgEntry, config.hardStopPercent, trade.direction) : undefined, }) console.log(`✅ New exit orders placed`) // Update Position Manager with new values trade.entryPrice = newAvgEntry trade.positionSize = newTotalValue trade.currentSize = newTotalValue trade.tp1Price = newTP1 trade.tp2Price = newTP2 trade.stopLossPrice = newSL // Reset tracking values trade.tp1Hit = false trade.slMovedToBreakeven = false trade.slMovedToProfit = false trade.peakPnL = 0 trade.peakPrice = newAvgEntry console.log(`💾 Updated Position Manager`) return NextResponse.json({ success: true, message: `Position scaled by ${scalePercent}% - New entry: $${newAvgEntry.toFixed(2)}`, oldEntry: oldEntry, newEntry: newAvgEntry, oldSize: oldTotalValue, newSize: newTotalValue, newTP1: newTP1, newTP2: newTP2, newSL: newSL, }) } catch (error) { console.error('❌ Scale position error:', error) return NextResponse.json( { success: false, message: error instanceof Error ? error.message : 'Unknown error', }, { status: 500 } ) } }