Files
trading_bot_v4/app/api/trading/test-db/route.ts
2025-11-05 15:28:12 +01:00

267 lines
8.7 KiB
TypeScript

/**
* 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<NextResponse<TestTradeResponse>> {
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,
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,
atrAtEntry: undefined,
runnerTrailingPercent: undefined,
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 }
)
}
}