Files
trading_bot_v3/lib/simple-automation.js
mindesbunister 0e3baa139f 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
2025-07-24 22:56:16 +02:00

351 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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 };