diff --git a/app/api/learning/persistent-status/route.js b/app/api/learning/persistent-status/route.js index 9d0d7b1..88e8d54 100644 --- a/app/api/learning/persistent-status/route.js +++ b/app/api/learning/persistent-status/route.js @@ -1,158 +1,172 @@ import { NextResponse } from 'next/server'; -import fs from 'fs/promises'; -import path from 'path'; +import { PrismaClient } from '@prisma/client'; -const PERSISTENT_DATA_FILE = path.join(process.cwd(), 'data', 'learning-persistent.json'); - -// Default persistent data structure -const defaultPersistentData = { - totalTrades: 0, - winningTrades: 0, - losingTrades: 0, - totalPnL: 0, - winRate: 0, - avgWinAmount: 0, - avgLossAmount: 0, - bestTrade: 0, - worstTrade: 0, - learningDecisions: 0, - aiEnhancements: 0, - riskThresholds: { - emergency: 1, - risk: 2, - mediumRisk: 5 - }, - lastUpdated: new Date().toISOString(), - systemStatus: 'learning', - dataCollected: true -}; - -async function ensureDataDirectory() { - const dataDir = path.join(process.cwd(), 'data'); - try { - await fs.access(dataDir); - } catch { - await fs.mkdir(dataDir, { recursive: true }); - } -} - -async function loadPersistentData() { - try { - await ensureDataDirectory(); - const data = await fs.readFile(PERSISTENT_DATA_FILE, 'utf8'); - return JSON.parse(data); - } catch (error) { - // File doesn't exist or is invalid, return default data - return defaultPersistentData; - } -} - -async function savePersistentData(data) { - try { - await ensureDataDirectory(); - await fs.writeFile(PERSISTENT_DATA_FILE, JSON.stringify(data, null, 2)); - return true; - } catch (error) { - console.error('Error saving persistent data:', error); - return false; - } -} +const prisma = new PrismaClient(); export async function GET() { try { - const persistentData = await loadPersistentData(); - - // Get current automation status if available - let currentStatus = null; - let learningStatus = null; - try { - const { getAutomationInstance } = await import('../../../../lib/automation-singleton.js'); - const automation = await getAutomationInstance(); - if (automation) { - currentStatus = automation.getStatus(); - - // If automation has learning status, get it too - if (typeof automation.getLearningStatus === 'function') { - learningStatus = await automation.getLearningStatus(); - if (learningStatus && learningStatus.report) { - // Update some data from current learning status - persistentData.lastUpdated = new Date().toISOString(); - persistentData.systemStatus = learningStatus.enabled ? 'active' : 'standby'; - } - } + // Get real trading data from database + const trades = await prisma.trades.findMany({ + orderBy: { createdAt: 'desc' }, + take: 50, // Last 50 trades for meaningful statistics + select: { + id: true, + symbol: true, + side: true, + amount: true, + entryPrice: true, + exitPrice: true, + profit: true, + leverage: true, + confidence: true, + createdAt: true, + outcome: true } - } catch (error) { - console.warn('Could not get current automation status:', error.message); - } + }); - return NextResponse.json({ - success: true, - persistentData: { - ...persistentData, - isLive: currentStatus?.isActive || currentStatus?.isRunning || learningStatus?.enabled || false, - currentRunTime: currentStatus?.startTime || null, - enhancedSummary: { - totalDecisions: persistentData.learningDecisions, - successRate: persistentData.winRate, - systemConfidence: persistentData.winRate > 60 ? 0.8 : persistentData.winRate > 40 ? 0.6 : 0.3, - isActive: persistentData.systemStatus === 'active', - totalTrades: persistentData.totalTrades, - totalPnL: persistentData.totalPnL - }, - tradingStats: { - totalTrades: persistentData.totalTrades, - winningTrades: persistentData.winningTrades, - losingTrades: persistentData.losingTrades, - winRate: persistentData.winRate, - totalPnL: persistentData.totalPnL, - avgWinAmount: persistentData.avgWinAmount, - avgLossAmount: persistentData.avgLossAmount, - bestTrade: persistentData.bestTrade, - worstTrade: persistentData.worstTrade - }, - learningMetrics: { - totalDecisions: persistentData.learningDecisions, - aiEnhancements: persistentData.aiEnhancements, - riskThresholds: persistentData.riskThresholds, - dataQuality: persistentData.totalTrades > 10 ? 'Good' : persistentData.totalTrades > 5 ? 'Fair' : 'Limited' + // Calculate real performance metrics + let totalTrades = trades.length; + let winningTrades = 0; + let losingTrades = 0; + let totalPnL = 0; + let winAmounts = []; + let lossAmounts = []; + let bestTrade = 0; + let worstTrade = 0; + + trades.forEach(trade => { + const profit = trade.profit || 0; + totalPnL += profit; + + if (profit > 0) { + winningTrades++; + winAmounts.push(profit); + if (profit > bestTrade) bestTrade = profit; + } else if (profit < 0) { + losingTrades++; + lossAmounts.push(profit); + if (profit < worstTrade) worstTrade = profit; + } + }); + + const winRate = totalTrades > 0 ? (winningTrades / totalTrades) * 100 : 0; + const avgWinAmount = winAmounts.length > 0 ? winAmounts.reduce((a, b) => a + b, 0) / winAmounts.length : 0; + const avgLossAmount = lossAmounts.length > 0 ? lossAmounts.reduce((a, b) => a + b, 0) / lossAmounts.length : 0; + + // Get learning decisions count + const learningData = await prisma.ai_learning_data.findMany({ + where: { + createdAt: { + gte: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000) // Last 30 days } } }); + // Get recent trades for display + const recentTrades = trades.slice(0, 3).map(trade => ({ + id: trade.id, + symbol: trade.symbol, + type: trade.side?.toUpperCase() || 'UNKNOWN', + entry: trade.entryPrice || 0, + exit: trade.exitPrice || 0, + pnl: trade.profit || 0, + outcome: (trade.profit || 0) > 0 ? 'WIN' : (trade.profit || 0) < 0 ? 'LOSS' : 'BREAK-EVEN', + timestamp: trade.createdAt.toISOString() + })); + + // Get current automation status + let isActive = false; + let currentRunTime = null; + try { + const { getAutomationInstance } = await import('../../../../lib/automation-singleton.js'); + const automation = await getAutomationInstance(); + if (automation) { + isActive = automation.isRunning || false; + currentRunTime = automation.stats?.startTime || null; + } + } catch (error) { + console.warn('Could not get automation status:', error.message); + } + + const persistentData = { + totalTrades, + winningTrades, + losingTrades, + totalPnL: Math.round(totalPnL * 100) / 100, + winRate: Math.round(winRate * 10) / 10, + avgWinAmount: Math.round(avgWinAmount * 100) / 100, + avgLossAmount: Math.round(avgLossAmount * 100) / 100, + bestTrade: Math.round(bestTrade * 100) / 100, + worstTrade: Math.round(worstTrade * 100) / 100, + learningDecisions: learningData.length, + aiEnhancements: Math.floor(learningData.length / 7), // Enhancement every 7 decisions + riskThresholds: { + emergency: totalPnL < -50 ? 1 : 3, + risk: totalPnL < -30 ? 2 : 5, + mediumRisk: totalPnL < -10 ? 5 : 8 + }, + lastUpdated: new Date().toISOString(), + systemStatus: isActive ? 'active' : 'standby', + dataCollected: totalTrades > 0, + recentTrades, + isLive: isActive, + currentRunTime, + enhancedSummary: { + totalDecisions: learningData.length, + successRate: winRate, + systemConfidence: winRate > 60 ? 0.8 : winRate > 40 ? 0.6 : winRate > 20 ? 0.3 : 0.1, + isActive, + totalTrades, + totalPnL: Math.round(totalPnL * 100) / 100 + }, + tradingStats: { + totalTrades, + winningTrades, + losingTrades, + winRate: Math.round(winRate * 10) / 10, + totalPnL: Math.round(totalPnL * 100) / 100, + avgWinAmount: Math.round(avgWinAmount * 100) / 100, + avgLossAmount: Math.round(avgLossAmount * 100) / 100, + bestTrade: Math.round(bestTrade * 100) / 100, + worstTrade: Math.round(worstTrade * 100) / 100 + }, + learningMetrics: { + totalDecisions: learningData.length, + aiEnhancements: Math.floor(learningData.length / 7), + riskThresholds: { + emergency: totalPnL < -50 ? 1 : 3, + risk: totalPnL < -30 ? 2 : 5, + mediumRisk: totalPnL < -10 ? 5 : 8 + }, + dataQuality: totalTrades > 10 ? 'Good' : totalTrades > 5 ? 'Fair' : 'Limited' + } + }; + + await prisma.$disconnect(); + + return NextResponse.json({ + success: true, + persistentData + }); + } catch (error) { console.error('Error in persistent status API:', error); + await prisma.$disconnect(); + return NextResponse.json({ success: false, - error: error.message, - persistentData: defaultPersistentData + error: error.message }, { status: 500 }); } } export async function POST(request) { try { - const updateData = await request.json(); - const currentData = await loadPersistentData(); - - // Update the persistent data - const updatedData = { - ...currentData, - ...updateData, - lastUpdated: new Date().toISOString() - }; - - // Recalculate derived metrics - if (updatedData.totalTrades > 0) { - updatedData.winRate = (updatedData.winningTrades / updatedData.totalTrades) * 100; - } - - const saved = await savePersistentData(updatedData); - + // For updating specific metrics (not implemented in this version) return NextResponse.json({ - success: saved, - message: saved ? 'Persistent data updated' : 'Failed to save data', - data: updatedData - }); + success: false, + message: 'POST method not implemented - data comes from database' + }, { status: 501 }); } catch (error) { console.error('Error updating persistent data:', error); diff --git a/prisma/prisma/dev.db b/prisma/prisma/dev.db index 46a7e6e..5992edf 100644 Binary files a/prisma/prisma/dev.db and b/prisma/prisma/dev.db differ