/** * Test Database Trade Endpoint * * Creates small test trades to verify database functionality * POST /api/trading/test-db */ import { NextRequest, NextResponse } from 'next/server' import { initializeDriftService } from '@/lib/drift/client' import { openPosition, placeExitOrders } from '@/lib/drift/orders' import { getMergedConfig } from '@/config/trading' import { getInitializedPositionManager, ActiveTrade } from '@/lib/trading/position-manager' import { createTrade } from '@/lib/database/trades' export interface TestTradeRequest { symbol?: string // Default: 'SOL-PERP' direction?: 'long' | 'short' // Default: 'long' sizeUSD?: number // Default: $10 leverage?: number // Default: 1x } export interface TestTradeResponse { success: boolean message?: string trade?: { id: string positionId: string symbol: string direction: 'long' | 'short' entryPrice: number positionSize: number leverage: number } error?: string } export async function POST(request: NextRequest): Promise> { try { console.log('๐Ÿงช Test trade request received') // Parse request body const body: TestTradeRequest = await request.json().catch(() => ({})) // Use minimal settings for test trade const symbol = body.symbol || 'SOL-PERP' const direction = body.direction || 'long' const baseSize = body.sizeUSD || 10 // $10 base collateral const leverage = body.leverage || 1 // 1x leverage (safe) // IMPORTANT: For Drift, we pass the BASE size (collateral), not notional // Drift internally applies the leverage const positionSizeUSD = baseSize // This is the actual collateral/margin used const notionalSize = baseSize * leverage // This is what shows in Drift UI console.log(`๐Ÿงช Creating TEST trade:`) console.log(` Symbol: ${symbol}`) console.log(` Direction: ${direction}`) console.log(` Collateral: $${baseSize}`) console.log(` Leverage: ${leverage}x`) console.log(` Notional size: $${notionalSize} (what you'll see in Drift)`) console.log(` โš ๏ธ Marked as TEST TRADE`) // Get base config but override with test settings const config = getMergedConfig({ positionSize: baseSize, leverage: leverage, stopLossPercent: -1.5, takeProfit1Percent: 0.7, takeProfit2Percent: 1.5, }) // Initialize Drift service const driftService = await initializeDriftService() // Check account health const health = await driftService.getAccountHealth() console.log('๐Ÿ’Š Account health:', health) if (health.freeCollateral <= 0) { return NextResponse.json( { success: false, error: 'Insufficient collateral', message: `Free collateral: $${health.freeCollateral.toFixed(2)}`, }, { status: 400 } ) } // Open position const openResult = await openPosition({ symbol, direction, sizeUSD: positionSizeUSD, slippageTolerance: config.slippageTolerance, }) if (!openResult.success) { return NextResponse.json( { success: false, error: 'Position open failed', message: openResult.error, }, { status: 500 } ) } const entryPrice = openResult.fillPrice! // Calculate exit prices const calculatePrice = (entry: number, percent: number, dir: 'long' | 'short') => { if (dir === 'long') { return entry * (1 + percent / 100) } else { return entry * (1 - percent / 100) } } const stopLossPrice = calculatePrice(entryPrice, config.stopLossPercent, direction) const tp1Price = calculatePrice(entryPrice, config.takeProfit1Percent, direction) const tp2Price = calculatePrice(entryPrice, config.takeProfit2Percent, direction) const emergencyStopPrice = calculatePrice(entryPrice, config.emergencyStopPercent, direction) console.log('๐Ÿ“Š Test trade targets:') console.log(` Entry: $${entryPrice.toFixed(4)}`) console.log(` SL: $${stopLossPrice.toFixed(4)} (${config.stopLossPercent}%)`) console.log(` TP1: $${tp1Price.toFixed(4)} (${config.takeProfit1Percent}%)`) console.log(` TP2: $${tp2Price.toFixed(4)} (${config.takeProfit2Percent}%)`) // Place exit orders let exitOrderSignatures: string[] = [] try { const exitRes = await placeExitOrders({ symbol, positionSizeUSD, entryPrice, tp1Price, tp2Price, stopLossPrice, tp1SizePercent: config.takeProfit1SizePercent || 50, tp2SizePercent: config.takeProfit2SizePercent || 100, direction, useDualStops: config.useDualStops, softStopPrice: config.useDualStops ? calculatePrice(entryPrice, config.softStopPercent, direction) : undefined, softStopBuffer: config.softStopBuffer, hardStopPrice: config.useDualStops ? calculatePrice(entryPrice, config.hardStopPercent, direction) : undefined, }) if (exitRes.success && exitRes.signatures) { exitOrderSignatures = exitRes.signatures console.log('๐Ÿ“จ Exit orders placed:', exitRes.signatures) } } catch (err) { console.error('โŒ Failed to place exit orders:', err) } // Create active trade object for position manager const activeTrade: ActiveTrade = { id: `test-trade-${Date.now()}`, positionId: openResult.transactionSignature!, symbol, direction, entryPrice, entryTime: Date.now(), positionSize: positionSizeUSD, leverage, stopLossPrice, tp1Price, tp2Price, emergencyStopPrice, currentSize: positionSizeUSD, originalPositionSize: positionSizeUSD, // Store original size for P&L takeProfitPrice1: tp1Price, takeProfitPrice2: tp2Price, tp1Hit: false, tp2Hit: false, slMovedToBreakeven: false, slMovedToProfit: false, trailingStopActive: false, realizedPnL: 0, unrealizedPnL: 0, peakPnL: 0, peakPrice: entryPrice, maxFavorableExcursion: 0, maxAdverseExcursion: 0, maxFavorablePrice: entryPrice, maxAdversePrice: entryPrice, priceCheckCount: 0, lastPrice: entryPrice, lastUpdateTime: Date.now(), } // Add to position manager const positionManager = await getInitializedPositionManager() await positionManager.addTrade(activeTrade) console.log('โœ… Test trade added to position manager') // Save to database with TEST flag try { const dbTrade = await createTrade({ positionId: openResult.transactionSignature!, symbol, direction, entryPrice, entrySlippage: openResult.slippage, positionSizeUSD, leverage, stopLossPrice, takeProfit1Price: tp1Price, takeProfit2Price: tp2Price, tp1SizePercent: config.takeProfit1SizePercent || 50, tp2SizePercent: config.takeProfit2SizePercent || 100, configSnapshot: config, entryOrderTx: openResult.transactionSignature!, tp1OrderTx: exitOrderSignatures[0], tp2OrderTx: exitOrderSignatures[1], slOrderTx: config.useDualStops ? undefined : exitOrderSignatures[2], softStopOrderTx: config.useDualStops ? exitOrderSignatures[2] : undefined, hardStopOrderTx: config.useDualStops ? exitOrderSignatures[3] : undefined, signalSource: 'test-api', signalStrength: 'test', timeframe: 'test', isTestTrade: true, // Mark as test trade }) console.log('๐Ÿ’พโœ… Test trade saved to database with ID:', dbTrade.id) console.log('๐Ÿท๏ธ Trade marked as TEST - will be excluded from analytics') return NextResponse.json({ success: true, message: `โœ… Test trade created! Collateral: $${baseSize} | Leverage: ${leverage}x | Notional: $${notionalSize} ${direction} on ${symbol}`, trade: { id: dbTrade.id, positionId: openResult.transactionSignature!, symbol, direction, entryPrice, positionSize: positionSizeUSD, notionalSize: notionalSize, leverage, }, }) } catch (dbError) { console.error('โŒ Failed to save test trade to database:', dbError) return NextResponse.json({ success: false, error: 'Database save failed', message: dbError instanceof Error ? dbError.message : 'Unknown database error', }, { status: 500 }) } } catch (error) { console.error('โŒ Test trade execution error:', error) return NextResponse.json( { success: false, error: 'Internal server error', message: error instanceof Error ? error.message : 'Unknown error', }, { status: 500 } ) } }