Files
trading_bot_v3/ai-learning-analytics.js
mindesbunister 9b6a393e06 🔧 CRITICAL FIX: Price Data Sync & Position Monitor Enhancement
Fixed major price data sync issues:
- Removed hardcoded price (77.63) from position monitor
- Added real-time oracle data instead of stale TWAP pricing
- Implemented cache-busting headers for fresh data
- Updated fallback prices to current market levels

- Real-time P&L tracking with trend indicators (📈📉➡️)
- Enhanced stop loss proximity alerts with color-coded risk levels
- Analysis progress indicators during automation cycles
- Performance metrics (runtime, cycles, trades, errors)
- Fresh data validation and improved error handling

- Price accuracy: 77.63 → 84.47 (matches Drift UI)
- P&L accuracy: -.91 → -.59 (correct calculation)
- Risk assessment: CRITICAL → MEDIUM (proper evaluation)
- Stop loss distance: 0.91% → 4.8% (safe distance)

- CLI monitor script with 8-second updates
- Web dashboard component (PositionMonitor.tsx)
- Real-time automation status tracking
- Database and error monitoring improvements

This fixes the automation showing false emergency alerts when
position was actually performing normally.
2025-07-25 23:33:06 +02:00

362 lines
12 KiB
JavaScript

#!/usr/bin/env node
/**
* AI Learning Analytics System
*
* Analyzes AI trading performance improvements and generates proof of learning effectiveness
*/
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
class AILearningAnalytics {
constructor() {
this.startDate = new Date('2025-07-24'); // When AI trading started
}
async generateLearningReport() {
console.log('🧠 AI LEARNING EFFECTIVENESS REPORT');
console.log('=' .repeat(60));
console.log('');
try {
// Get all learning data since AI started
const learningData = await this.getLearningData();
const tradeData = await this.getTradeData();
const automationSessions = await this.getAutomationSessions();
// Calculate improvement metrics
const improvements = await this.calculateImprovements(learningData);
const pnlAnalysis = await this.calculateTotalPnL(tradeData);
const accuracyTrends = await this.calculateAccuracyTrends(learningData);
const confidenceEvolution = await this.calculateConfidenceEvolution(learningData);
// Generate report
this.displayOverallStats(learningData, tradeData, automationSessions);
this.displayLearningImprovements(improvements);
this.displayPnLAnalysis(pnlAnalysis);
this.displayAccuracyTrends(accuracyTrends);
this.displayConfidenceEvolution(confidenceEvolution);
// Generate JSON for frontend
const reportData = {
generated: new Date().toISOString(),
period: {
start: this.startDate.toISOString(),
end: new Date().toISOString(),
daysActive: Math.ceil((Date.now() - this.startDate.getTime()) / (1000 * 60 * 60 * 24))
},
overview: {
totalLearningRecords: learningData.length,
totalTrades: tradeData.length,
totalSessions: automationSessions.length,
activeSessions: automationSessions.filter(s => s.status === 'ACTIVE').length
},
improvements,
pnl: pnlAnalysis,
accuracy: accuracyTrends,
confidence: confidenceEvolution
};
// Save report for API
await this.saveReport(reportData);
console.log('\n📊 Report saved and ready for dashboard display!');
return reportData;
} catch (error) {
console.error('❌ Error generating learning report:', error.message);
throw error;
}
}
async getLearningData() {
return await prisma.aILearningData.findMany({
where: {
createdAt: {
gte: this.startDate
}
},
orderBy: { createdAt: 'asc' }
});
}
async getTradeData() {
return await prisma.trade.findMany({
where: {
createdAt: {
gte: this.startDate
},
isAutomated: true // Only AI trades
},
orderBy: { createdAt: 'asc' }
});
}
async getAutomationSessions() {
return await prisma.automationSession.findMany({
where: {
createdAt: {
gte: this.startDate
}
},
orderBy: { createdAt: 'desc' }
});
}
async calculateImprovements(learningData) {
if (learningData.length < 10) {
return {
improvement: 0,
trend: 'INSUFFICIENT_DATA',
message: 'Need more learning data to calculate improvements'
};
}
// 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 = this.getAverageConfidence(earlyData);
const recentConfidence = this.getAverageConfidence(recentData);
// Calculate accuracy if outcomes are available
const earlyAccuracy = this.getAccuracy(earlyData);
const recentAccuracy = this.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'
};
}
async calculateTotalPnL(tradeData) {
const analysis = {
totalTrades: tradeData.length,
totalPnL: 0,
totalPnLPercent: 0,
winningTrades: 0,
losingTrades: 0,
breakEvenTrades: 0,
avgTradeSize: 0,
bestTrade: null,
worstTrade: null,
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++;
}
// Track best/worst trades
if (!analysis.bestTrade || pnl > analysis.bestTrade.profit) {
analysis.bestTrade = trade;
}
if (!analysis.worstTrade || pnl < analysis.worstTrade.profit) {
analysis.worstTrade = trade;
}
});
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;
}
async calculateAccuracyTrends(learningData) {
const trends = [];
const chunkSize = Math.max(5, Math.floor(learningData.length / 10)); // At least 5 samples per chunk
for (let i = 0; i < learningData.length; i += chunkSize) {
const chunk = learningData.slice(i, i + chunkSize);
const accuracy = this.getAccuracy(chunk);
const confidence = this.getAverageConfidence(chunk);
trends.push({
period: i / chunkSize + 1,
samples: chunk.length,
accuracy: accuracy ? Number(accuracy.toFixed(2)) : null,
confidence: Number(confidence.toFixed(2)),
timestamp: chunk[chunk.length - 1]?.createdAt
});
}
return trends;
}
async calculateConfidenceEvolution(learningData) {
return learningData.map((record, index) => ({
index: index + 1,
timestamp: record.createdAt,
confidence: record.confidenceScore || 0,
accuracy: record.accuracyScore || null,
symbol: record.symbol,
outcome: record.outcome
}));
}
getAverageConfidence(data) {
const confidenceScores = data
.map(d => d.confidenceScore || d.analysisData?.confidence || 0.5)
.filter(score => score > 0);
return confidenceScores.length > 0 ?
confidenceScores.reduce((a, b) => a + b, 0) / confidenceScores.length : 0.5;
}
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;
}
displayOverallStats(learningData, tradeData, automationSessions) {
console.log('📈 OVERALL AI TRADING STATISTICS');
console.log(` Period: ${this.startDate.toDateString()} - ${new Date().toDateString()}`);
console.log(` Learning Records: ${learningData.length}`);
console.log(` AI Trades Executed: ${tradeData.length}`);
console.log(` Automation Sessions: ${automationSessions.length}`);
console.log(` Active Sessions: ${automationSessions.filter(s => s.status === 'ACTIVE').length}`);
console.log('');
}
displayLearningImprovements(improvements) {
console.log('🧠 AI LEARNING IMPROVEMENTS');
if (improvements.trend === 'INSUFFICIENT_DATA') {
console.log(` ⚠️ ${improvements.message}`);
} else {
console.log(` 📊 Confidence Improvement: ${improvements.confidenceImprovement > 0 ? '+' : ''}${improvements.confidenceImprovement}%`);
if (improvements.accuracyImprovement !== null) {
console.log(` 🎯 Accuracy Improvement: ${improvements.accuracyImprovement > 0 ? '+' : ''}${improvements.accuracyImprovement}%`);
}
console.log(` 📈 Trend: ${improvements.trend}`);
console.log(` Early Period: ${improvements.earlyPeriod.avgConfidence}% confidence (${improvements.earlyPeriod.samples} samples)`);
console.log(` Recent Period: ${improvements.recentPeriod.avgConfidence}% confidence (${improvements.recentPeriod.samples} samples)`);
}
console.log('');
}
displayPnLAnalysis(pnl) {
console.log('💰 TOTAL PnL ANALYSIS');
console.log(` Total Trades: ${pnl.totalTrades}`);
console.log(` Total PnL: $${pnl.totalPnL.toFixed(4)}`);
console.log(` Total PnL %: ${pnl.totalPnLPercent.toFixed(2)}%`);
console.log(` Win Rate: ${pnl.winRate.toFixed(1)}%`);
console.log(` Winning Trades: ${pnl.winningTrades}`);
console.log(` Losing Trades: ${pnl.losingTrades}`);
console.log(` Break Even: ${pnl.breakEvenTrades}`);
if (pnl.totalTrades > 0) {
console.log(` Average Trade Size: $${pnl.avgTradeSize.toFixed(2)}`);
console.log(` Average Win: $${pnl.avgWin.toFixed(4)}`);
console.log(` Average Loss: $${pnl.avgLoss.toFixed(4)}`);
console.log(` Profit Factor: ${pnl.profitFactor.toFixed(2)}`);
}
console.log('');
}
displayAccuracyTrends(trends) {
console.log('📊 ACCURACY TRENDS OVER TIME');
trends.forEach(trend => {
console.log(` Period ${trend.period}: ${trend.confidence}% confidence, ${trend.accuracy ? trend.accuracy + '% accuracy' : 'no accuracy data'} (${trend.samples} samples)`);
});
console.log('');
}
displayConfidenceEvolution(evolution) {
console.log('📈 RECENT CONFIDENCE EVOLUTION');
const recentData = evolution.slice(-10); // Last 10 records
recentData.forEach(record => {
const date = new Date(record.timestamp).toLocaleDateString();
console.log(` ${date}: ${(record.confidence * 100).toFixed(1)}% confidence (${record.symbol})`);
});
console.log('');
}
async saveReport(reportData) {
const fs = require('fs');
const reportPath = './public/ai-learning-report.json';
// Ensure public directory exists
if (!fs.existsSync('./public')) {
fs.mkdirSync('./public', { recursive: true });
}
fs.writeFileSync(reportPath, JSON.stringify(reportData, null, 2));
console.log(`📁 Report saved to: ${reportPath}`);
}
}
// Run the analytics
async function main() {
const analytics = new AILearningAnalytics();
try {
await analytics.generateLearningReport();
} catch (error) {
console.error('Failed to generate report:', error);
} finally {
await prisma.$disconnect();
}
}
if (require.main === module) {
main();
}
module.exports = AILearningAnalytics;