diff --git a/app/api/automation/position-monitor/route.js b/app/api/automation/position-monitor/route.js index dc73a5b..2ee2a21 100644 --- a/app/api/automation/position-monitor/route.js +++ b/app/api/automation/position-monitor/route.js @@ -174,6 +174,45 @@ export async function GET() { } } + // Auto-restart automation if no position and cleanup completed successfully + if (!result.hasPosition && result.recommendation === 'START_TRADING') { + try { + console.log('🚀 AUTO-RESTART: No position detected with START_TRADING recommendation - checking if automation should restart'); + + // Check if automation is currently stopped + const statusResponse = await fetch(`${baseUrl}/api/automation/status`); + if (statusResponse.ok) { + const statusData = await statusResponse.json(); + + if (!statusData.isRunning) { + console.log('🔄 Automation is stopped - triggering auto-restart for new cycle'); + result.autoRestart = { + triggered: true, + reason: 'No position + START_TRADING recommendation', + message: 'System ready for new trading cycle' + }; + + // Note: We don't automatically start here to avoid conflicts + // The UI should detect this and offer restart option + } else { + console.log('✅ Automation already running - no restart needed'); + result.autoRestart = { + triggered: false, + reason: 'Automation already active', + message: 'System monitoring active' + }; + } + } + } catch (restartError) { + console.warn('⚠️ Could not check automation status for auto-restart:', restartError.message); + result.autoRestart = { + triggered: false, + error: restartError.message, + message: 'Could not check restart requirements' + }; + } + } + return NextResponse.json({ success: true, monitor: result diff --git a/app/api/drift/position-history/route.js b/app/api/drift/position-history/route.js index 80919d2..ed6a9f0 100644 --- a/app/api/drift/position-history/route.js +++ b/app/api/drift/position-history/route.js @@ -16,6 +16,97 @@ const getRpcStatus = () => { } } +// Function to record recently closed positions for learning +async function recordRecentlyClosedPosition() { + try { + // Check if there's a recent automation decision that should be closed + const { simpleAutomation } = await import('../../../lib/simple-automation.js'); + + if (simpleAutomation.lastDecision && simpleAutomation.lastDecision.executed) { + const decision = simpleAutomation.lastDecision; + const timeSinceDecision = Date.now() - new Date(decision.timestamp).getTime(); + + // If decision was executed recently (within 1 hour) and no position exists, record as closed + if (timeSinceDecision < 3600000) { // 1 hour + console.log('🔍 Found recent executed decision - checking if position was closed'); + + // Estimate profit based on current price vs entry + const response = await fetch('https://api.coingecko.com/api/v3/simple/price?ids=solana&vs_currencies=usd'); + const priceData = await response.json(); + const currentPrice = priceData.solana.usd; + + const entryPrice = decision.executionDetails.currentPrice; + const side = decision.executionDetails.side.toLowerCase(); + const amount = decision.executionDetails.amount; + + // Calculate P&L based on side and price movement + let pnl = 0; + let outcome = 'UNKNOWN'; + + if (side === 'long') { + pnl = (currentPrice - entryPrice) * (amount / entryPrice); + outcome = currentPrice > entryPrice ? 'WIN' : 'LOSS'; + } else if (side === 'short') { + pnl = (entryPrice - currentPrice) * (amount / entryPrice); + outcome = currentPrice < entryPrice ? 'WIN' : 'LOSS'; + } + + const pnlPercent = (pnl / amount) * 100; + + // Record the trade in database + const { PrismaClient } = await import('@prisma/client'); + const prisma = new PrismaClient(); + + try { + const tradeRecord = await prisma.trades.create({ + data: { + id: `trade_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, + userId: 'automation_user', // Default automation user + symbol: decision.executionDetails.symbol || 'SOL-PERP', + side: side.toUpperCase(), + amount: amount, + price: entryPrice, + entryPrice: entryPrice, + exitPrice: currentPrice, + stopLoss: decision.executionDetails.stopLoss, + takeProfit: decision.executionDetails.takeProfit, + leverage: decision.executionDetails.leverage || 1, + profit: pnl, + pnlPercent: pnlPercent, + outcome: outcome, + status: 'COMPLETED', + confidence: decision.confidence, + aiAnalysis: decision.reasoning, + isAutomated: true, + tradingMode: 'PERP', + driftTxId: decision.executionDetails.txId, + executedAt: new Date(decision.timestamp), + closedAt: new Date(), + createdAt: new Date(decision.timestamp), + updatedAt: new Date() + } + }); + + console.log('✅ Recorded completed trade:', tradeRecord.id); + + // Clear the decision to avoid re-recording + simpleAutomation.lastDecision = null; + + return tradeRecord; + + } finally { + await prisma.$disconnect(); + } + } + } + + return null; + } catch (error) { + console.error('❌ Error recording closed position:', error.message); + return null; + } +} + export async function GET() { try { console.log('📊 Position History API called') @@ -85,18 +176,68 @@ export async function GET() { let realTradeHistory = [] try { - console.log('🔍 Attempting to fetch real trading history from Drift...') + console.log('🔍 Attempting to fetch trading history from database...') - // Real trading history fetching would require: - // 1. Drift indexer API access - // 2. Transaction log parsing - // 3. Event listener aggregation - // Currently not implemented in SDK + // Import Prisma client + const { PrismaClient } = await import('@prisma/client'); + const prisma = new PrismaClient(); - console.log('⚠️ Real trading history fetch not implemented - returning empty data') + try { + // Get completed trades from database + const completedTrades = await prisma.trades.findMany({ + where: { + status: 'COMPLETED', + driftTxId: { + not: null, + not: { startsWith: 'SIM_' } // Exclude simulation trades + }, + tradingMode: 'PERP' // Only perpetual trades + }, + orderBy: { + closedAt: 'desc' + }, + take: 50 // Last 50 trades + }); + + console.log(`📊 Found ${completedTrades.length} completed trades in database`); + + // Convert to standardized format + realTradeHistory = completedTrades.map(trade => ({ + id: trade.id, + symbol: trade.symbol, + side: trade.side, + amount: trade.amount, + entryPrice: trade.entryPrice, + exitPrice: trade.exitPrice, + pnl: trade.profit, + pnlPercent: trade.pnlPercent, + outcome: trade.outcome, + leverage: trade.leverage || 1, + stopLoss: trade.stopLoss, + takeProfit: trade.takeProfit, + entryTime: trade.executedAt || trade.createdAt, + exitTime: trade.closedAt, + txId: trade.driftTxId, + confidence: trade.confidence, + aiAnalysis: trade.aiAnalysis + })); + + console.log(`✅ Successfully processed ${realTradeHistory.length} trades from database`); + + } finally { + await prisma.$disconnect(); + } } catch (error) { - console.log('❌ Could not fetch real trading history:', error.message) + console.log('❌ Could not fetch trading history from database:', error.message) + + // Fallback: Try to detect recently closed position and record it + try { + console.log('🔍 Checking for recently closed positions to record...'); + await recordRecentlyClosedPosition(); + } catch (recordError) { + console.log('⚠️ Could not record recent position:', recordError.message); + } } // Only use real data - no demo/mock data diff --git a/prisma/prisma/dev.db b/prisma/prisma/dev.db index c51cca2..58541f0 100644 Binary files a/prisma/prisma/dev.db and b/prisma/prisma/dev.db differ