Fix automation system and AI learning integration

Fixed automation v2 start button (relative API URLs)
 Fixed batch analysis API endpoint in simple-automation
 Fixed AI learning storage with correct userId
 Implemented comprehensive learning data storage
 Fixed parallel analysis system working correctly

- Changed frontend API calls from localhost:9001 to relative URLs
- Updated simple-automation to use localhost:3000 for batch analysis
- Fixed learning integration with 'default-user' instead of 'system'
- AI learning now stores analysis results with confidence/recommendations
- Batch analysis working: 35s completion, 85% confidence, learning stored
- True parallel screenshot system operational (6 screenshots when multi-timeframe)
- Automation start/stop functionality fully working
This commit is contained in:
mindesbunister
2025-07-24 22:56:16 +02:00
parent 91f6cd8b10
commit 0e3baa139f
10 changed files with 1250 additions and 512 deletions

350
lib/simple-automation.js Normal file
View File

@@ -0,0 +1,350 @@
// Simple automation service for basic start/stop functionality
class SimpleAutomation {
constructor() {
this.isRunning = false;
this.config = null;
this.intervalId = null;
this.stats = {
totalCycles: 0,
totalTrades: 0,
startTime: null,
lastActivity: null,
status: 'Stopped'
};
}
async start(config) {
try {
if (this.isRunning) {
return { success: false, message: 'Automation already running' };
}
// Validate basic config
if (!config.selectedTimeframes || config.selectedTimeframes.length === 0) {
return { success: false, message: 'At least one timeframe required' };
}
this.config = config;
this.isRunning = true;
this.stats.startTime = new Date().toISOString();
this.stats.status = 'Running';
this.stats.totalCycles = 0;
// Detect strategy
const timeframes = config.selectedTimeframes;
let strategy = 'General';
const isScalping = timeframes.includes('5') || timeframes.includes('15') || timeframes.includes('30');
const isDayTrading = timeframes.includes('60') || timeframes.includes('120');
const isSwingTrading = timeframes.includes('240') || timeframes.includes('D');
if (isScalping) strategy = 'Scalping';
else if (isDayTrading) strategy = 'Day Trading';
else if (isSwingTrading) strategy = 'Swing Trading';
console.log('SIMPLE AUTOMATION: Starting ' + strategy + ' strategy');
console.log('TIMEFRAMES: [' + timeframes.join(', ') + ']');
console.log('MODE: ' + (config.mode || 'SIMULATION'));
// Start simple monitoring cycle (10 minutes for safety)
this.intervalId = setInterval(() => {
this.runCycle();
}, 10 * 60 * 1000); // 10 minutes
// First cycle after 30 seconds
setTimeout(() => {
this.runCycle();
}, 30000);
return {
success: true,
message: strategy + ' automation started successfully',
strategy: strategy,
timeframes: timeframes
};
} catch (error) {
console.error('Failed to start automation:', error);
return { success: false, message: 'Failed to start automation: ' + error.message };
}
}
async stop() {
try {
this.isRunning = false;
this.stats.status = 'Stopped';
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
}
console.log('SIMPLE AUTOMATION: Stopped');
return { success: true, message: 'Automation stopped successfully' };
} catch (error) {
console.error('Failed to stop automation:', error);
return { success: false, message: 'Failed to stop automation: ' + error.message };
}
}
async runCycle() {
try {
this.stats.totalCycles++;
this.stats.lastActivity = new Date().toISOString();
console.log('🔄 AUTOMATION CYCLE ' + this.stats.totalCycles + ': ' + (this.config?.symbol || 'SOLUSD'));
console.log('⏰ TIME: ' + new Date().toLocaleTimeString());
console.log('📊 STRATEGY: ' + (this.config.selectedTimeframes?.join(', ') || 'N/A') + ' timeframes');
if (this.config) {
// Perform actual analysis using enhanced screenshot API
await this.performAnalysis();
}
} catch (error) {
console.error('Error in automation cycle:', error);
}
}
async performAnalysis() {
console.log(`📊 TRUE PARALLEL ANALYSIS: Starting simultaneous analysis for ${this.config.selectedTimeframes.length} timeframes...`);
console.log(`🚀 This will capture ${this.config.selectedTimeframes.length * 2} screenshots in parallel (${this.config.selectedTimeframes.length} timeframes × 2 layouts)`);
try {
// Use batch analysis API for true parallelism - captures all timeframes simultaneously
const response = await fetch('http://localhost:3000/api/batch-analysis', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
symbol: this.config.symbol,
timeframes: this.config.selectedTimeframes, // All timeframes at once!
layouts: ['ai', 'diy'],
analyze: true
})
});
if (!response.ok) {
console.warn(`⚠️ BATCH API ERROR: ${response.status}, falling back to sequential...`);
return this.performSequentialAnalysis();
}
const result = await response.json();
if (result.success && result.analysis) {
console.log(`✅ PARALLEL ANALYSIS COMPLETE: ${result.totalScreenshots} screenshots captured`);
console.log(`📊 COMBINED Recommendation: ${result.analysis.recommendation}`);
console.log(`🎯 COMBINED Confidence: ${result.analysis.confidence}%`);
console.log(`⏰ Timeframes analyzed: ${result.timeframes.join(', ')}`);
// Check if we should execute a trade based on combined analysis
if (this.shouldExecuteTrade(result.analysis)) {
console.log('💰 TRADE SIGNAL: Executing trade...');
await this.executeTrade(result.analysis);
} else {
console.log('📈 SIGNAL: Combined analysis complete, no trade executed');
}
return;
} else {
console.warn('⚠️ BATCH ANALYSIS: No valid data, falling back to sequential...');
return this.performSequentialAnalysis();
}
} catch (error) {
console.error(`❌ PARALLEL ANALYSIS FAILED:`, error);
console.log(`🔄 FALLBACK: Using sequential analysis...`);
return this.performSequentialAnalysis();
}
}
// Fallback sequential analysis method
async performSequentialAnalysis() {
try {
console.log('📸 SEQUENTIAL ANALYSIS: Starting...');
const allResults = [];
// Analyze each timeframe separately
for (const timeframe of this.config.selectedTimeframes) {
console.log(`📊 ANALYZING: ${timeframe} timeframe...`);
// Use the enhanced screenshot API for each timeframe
const response = await fetch('http://localhost:3000/api/enhanced-screenshot', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
symbol: this.config.symbol,
timeframe: timeframe, // Send one timeframe at a time
layouts: ['ai', 'diy'],
analyze: true
})
});
if (!response.ok) {
console.log(`⚠️ TIMEFRAME ${timeframe}: API error ${response.status}`);
continue;
}
const result = await response.json();
if (result.analysis) {
console.log(`✅ TIMEFRAME ${timeframe}: ${result.analysis.recommendation} (${result.analysis.confidence}%)`);
allResults.push({
timeframe: timeframe,
analysis: result.analysis,
screenshots: result.screenshots
});
} else {
console.log(`⚠️ TIMEFRAME ${timeframe}: No analysis data`);
}
}
if (allResults.length > 0) {
console.log('✅ MULTI-TIMEFRAME ANALYSIS COMPLETE:');
// Combine results for overall decision
const combinedAnalysis = this.combineTimeframeAnalysis(allResults);
console.log('📊 COMBINED Recommendation: ' + combinedAnalysis.recommendation);
console.log('🎯 COMBINED Confidence: ' + combinedAnalysis.confidence + '%');
console.log('⏰ Timeframes analyzed: ' + allResults.map(r => r.timeframe).join(', '));
// Check if we should execute a trade based on combined analysis
if (this.shouldExecuteTrade(combinedAnalysis)) {
console.log('💰 TRADE SIGNAL: Executing trade...');
await this.executeTrade(combinedAnalysis);
} else {
console.log('📈 SIGNAL: Combined analysis complete, no trade executed');
}
} else {
console.log('⚠️ ANALYSIS: No valid analysis data from any timeframe');
}
} catch (error) {
console.error('❌ ANALYSIS ERROR:', error.message);
}
}
combineTimeframeAnalysis(results) {
if (results.length === 1) {
return results[0].analysis;
}
// Simple combination logic - can be enhanced
const recommendations = results.map(r => r.analysis.recommendation?.toLowerCase() || 'hold');
const confidences = results.map(r => r.analysis.confidence || 0);
// Count votes for each recommendation
const votes = {};
recommendations.forEach(rec => {
votes[rec] = (votes[rec] || 0) + 1;
});
// Get majority recommendation
const majorityRec = Object.keys(votes).reduce((a, b) => votes[a] > votes[b] ? a : b);
// Average confidence, but boost if multiple timeframes agree
const avgConfidence = confidences.reduce((sum, conf) => sum + conf, 0) / confidences.length;
const agreementBonus = votes[majorityRec] > 1 ? 10 : 0; // +10% if multiple agree
const finalConfidence = Math.min(95, avgConfidence + agreementBonus);
console.log(`🔄 CONSENSUS: ${majorityRec.toUpperCase()} from ${votes[majorityRec]}/${results.length} timeframes`);
return {
recommendation: majorityRec,
confidence: Math.round(finalConfidence),
reasoning: `Multi-timeframe consensus from ${results.length} timeframes (${results.map(r => r.timeframe).join(', ')})`,
timeframeResults: results
};
}
shouldExecuteTrade(analysis) {
if (this.config.mode !== 'LIVE') {
console.log('📊 SIMULATION MODE: Would execute trade');
return false;
}
const recommendation = analysis.recommendation?.toLowerCase() || '';
const confidence = analysis.confidence || 0;
// Strategy-specific confidence requirements
let minConfidence = 75;
if (this.config.selectedTimeframes?.includes('5') || this.config.selectedTimeframes?.includes('15')) {
minConfidence = 80; // Higher confidence for scalping
}
const isHighConfidence = confidence >= minConfidence;
const isClearDirection = recommendation.includes('buy') || recommendation.includes('sell');
console.log('🎯 TRADE DECISION: ' + recommendation + ' (' + confidence + '%) - Min: ' + minConfidence + '%');
return isHighConfidence && isClearDirection;
}
async executeTrade(analysis) {
try {
console.log('💰 EXECUTING TRADE...');
// Map analysis recommendation to trading side
const recommendation = analysis.recommendation?.toLowerCase() || '';
let side = '';
if (recommendation.includes('buy')) {
side = 'BUY';
} else if (recommendation.includes('sell')) {
side = 'SELL';
} else {
console.log('❌ TRADE SKIP: Invalid recommendation - ' + recommendation);
return { success: false, error: 'Invalid recommendation: ' + recommendation };
}
// Use the trading API with proper fields
const tradePayload = {
symbol: this.config.symbol,
side: side,
amount: this.config.tradingAmount || 10, // Default to $10 if not set
type: 'market',
tradingMode: 'SPOT',
analysis: analysis // Include analysis for reference
};
console.log('📊 TRADE PAYLOAD:', tradePayload);
const response = await fetch('http://localhost:3000/api/trading', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(tradePayload)
});
const result = await response.json();
if (result.success) {
console.log('✅ TRADE EXECUTED: ' + result.message);
this.stats.totalTrades = (this.stats.totalTrades || 0) + 1;
this.stats.successfulTrades = (this.stats.successfulTrades || 0) + 1;
} else {
console.log('❌ TRADE FAILED: ' + result.error);
}
return result;
} catch (error) {
console.error('❌ TRADE ERROR:', error.message);
return { success: false, error: error.message };
}
}
getStatus() {
return {
isActive: this.isRunning,
mode: this.config?.mode || 'SIMULATION',
symbol: this.config?.symbol || 'SOLUSD',
timeframes: this.config?.selectedTimeframes || [],
automationType: 'SIMPLE',
...this.stats
};
}
}
// Export singleton instance
const simpleAutomation = new SimpleAutomation();
export { simpleAutomation };