import { NextResponse } from 'next/server'; import { PrismaClient } from '@prisma/client'; /** * AI Learning Analytics API * * Provides real-time statistics about AI learning improvements and trading performance */ const prisma = new PrismaClient(); export async function GET(request) { try { const startDate = new Date('2025-07-24'); // When AI trading started // Get learning data const learningData = await prisma.aILearningData.findMany({ where: { createdAt: { gte: startDate } }, orderBy: { createdAt: 'asc' } }); // Get trade data const tradeData = await prisma.trade.findMany({ where: { createdAt: { gte: startDate }, isAutomated: true }, orderBy: { createdAt: 'asc' } }); // Get automation sessions const automationSessions = await prisma.automationSession.findMany({ where: { createdAt: { gte: startDate } }, orderBy: { createdAt: 'desc' } }); // Calculate improvements const improvements = calculateImprovements(learningData); const pnlAnalysis = calculatePnLAnalysis(tradeData); // Add real-time drift position data let currentPosition = null; try { const HttpUtil = require('../../../lib/http-util'); const positionData = await HttpUtil.get('http://localhost:9001/api/automation/position-monitor'); if (positionData.success && positionData.monitor) { currentPosition = { hasPosition: positionData.monitor.hasPosition, symbol: positionData.monitor.position?.symbol, side: positionData.monitor.position?.side, size: positionData.monitor.position?.size, entryPrice: positionData.monitor.position?.entryPrice, currentPrice: positionData.monitor.position?.currentPrice, unrealizedPnl: positionData.monitor.position?.unrealizedPnl, distanceFromStopLoss: positionData.monitor.stopLossProximity?.distancePercent, riskLevel: positionData.monitor.riskLevel, aiRecommendation: positionData.monitor.recommendation }; } } catch (positionError) { console.log('Could not fetch position data:', positionError.message); } // Build response const now = new Date(); const daysSinceStart = Math.ceil((now.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24)); const response = { generated: now.toISOString(), period: { start: startDate.toISOString(), end: now.toISOString(), daysActive: daysSinceStart }, overview: { totalLearningRecords: learningData.length, totalTrades: tradeData.length, totalSessions: automationSessions.length, activeSessions: automationSessions.filter(s => s.status === 'ACTIVE').length }, improvements, pnl: pnlAnalysis, currentPosition, realTimeMetrics: { daysSinceAIStarted: daysSinceStart, learningRecordsPerDay: Number((learningData.length / daysSinceStart).toFixed(1)), tradesPerDay: Number((tradeData.length / daysSinceStart).toFixed(1)), lastUpdate: now.toISOString(), isLearningActive: automationSessions.filter(s => s.status === 'ACTIVE').length > 0 }, learningProof: { hasImprovement: improvements?.confidenceImprovement > 0, improvementDirection: improvements?.trend, confidenceChange: improvements?.confidenceImprovement, accuracyChange: improvements?.accuracyImprovement, sampleSize: learningData.length, isStatisticallySignificant: learningData.length > 100 } }; return NextResponse.json(response); } catch (error) { console.error('Error generating AI analytics:', error); return NextResponse.json({ error: 'Failed to generate analytics', details: error.message }, { status: 500 }); } finally { await prisma.$disconnect(); } } function calculateImprovements(learningData) { if (learningData.length < 10) { return { improvement: 0, trend: 'INSUFFICIENT_DATA', message: 'Need more learning data to calculate improvements', confidenceImprovement: 0, accuracyImprovement: null }; } // Split data into early vs recent periods const midPoint = Math.floor(learningData.length / 2); const earlyData = learningData.slice(0, midPoint); const recentData = learningData.slice(midPoint); // Calculate average confidence scores const earlyConfidence = getAverageConfidence(earlyData); const recentConfidence = getAverageConfidence(recentData); // Calculate accuracy if outcomes are available const earlyAccuracy = getAccuracy(earlyData); const recentAccuracy = getAccuracy(recentData); const confidenceImprovement = ((recentConfidence - earlyConfidence) / earlyConfidence) * 100; const accuracyImprovement = earlyAccuracy && recentAccuracy ? ((recentAccuracy - earlyAccuracy) / earlyAccuracy) * 100 : null; return { confidenceImprovement: Number(confidenceImprovement.toFixed(2)), accuracyImprovement: accuracyImprovement ? Number(accuracyImprovement.toFixed(2)) : null, earlyPeriod: { samples: earlyData.length, avgConfidence: Number(earlyConfidence.toFixed(2)), accuracy: earlyAccuracy ? Number(earlyAccuracy.toFixed(2)) : null }, recentPeriod: { samples: recentData.length, avgConfidence: Number(recentConfidence.toFixed(2)), accuracy: recentAccuracy ? Number(recentAccuracy.toFixed(2)) : null }, trend: confidenceImprovement > 5 ? 'IMPROVING' : confidenceImprovement < -5 ? 'DECLINING' : 'STABLE' }; } function calculatePnLAnalysis(tradeData) { const analysis = { totalTrades: tradeData.length, totalPnL: 0, totalPnLPercent: 0, winningTrades: 0, losingTrades: 0, breakEvenTrades: 0, avgTradeSize: 0, winRate: 0, avgWin: 0, avgLoss: 0, profitFactor: 0 }; if (tradeData.length === 0) { return analysis; } let totalProfit = 0; let totalLoss = 0; let totalAmount = 0; tradeData.forEach(trade => { const pnl = trade.profit || 0; const pnlPercent = trade.pnlPercent || 0; const amount = trade.amount || 0; analysis.totalPnL += pnl; analysis.totalPnLPercent += pnlPercent; totalAmount += amount; if (pnl > 0) { analysis.winningTrades++; totalProfit += pnl; } else if (pnl < 0) { analysis.losingTrades++; totalLoss += Math.abs(pnl); } else { analysis.breakEvenTrades++; } }); analysis.avgTradeSize = totalAmount / tradeData.length; analysis.winRate = (analysis.winningTrades / tradeData.length) * 100; analysis.avgWin = analysis.winningTrades > 0 ? totalProfit / analysis.winningTrades : 0; analysis.avgLoss = analysis.losingTrades > 0 ? totalLoss / analysis.losingTrades : 0; analysis.profitFactor = analysis.avgLoss > 0 ? analysis.avgWin / analysis.avgLoss : 0; // Round numbers Object.keys(analysis).forEach(key => { if (typeof analysis[key] === 'number') { analysis[key] = Number(analysis[key].toFixed(4)); } }); return analysis; } function getAverageConfidence(data) { const confidenceScores = data .map(d => { // Handle confidence stored as percentage (75.0) vs decimal (0.75) let confidence = d.confidenceScore || d.analysisData?.confidence || 0.5; if (confidence > 1) { confidence = confidence / 100; // Convert percentage to decimal } return confidence; }) .filter(score => score > 0); return confidenceScores.length > 0 ? confidenceScores.reduce((a, b) => a + b, 0) / confidenceScores.length : 0.5; } function getAccuracy(data) { const withOutcomes = data.filter(d => d.outcome && d.accuracyScore); if (withOutcomes.length === 0) return null; const avgAccuracy = withOutcomes.reduce((sum, d) => sum + (d.accuracyScore || 0), 0) / withOutcomes.length; return avgAccuracy; } export async function POST(request) { return NextResponse.json({ success: true, message: 'Analytics refreshed', timestamp: new Date().toISOString() }); }