// Simple automation service for basic start/stop functionality import { SimplifiedStopLossLearner } from './simplified-stop-loss-learner-fixed.js'; // Import AI Leverage Calculator for dynamic leverage async function importAILeverageCalculator() { try { const { AILeverageCalculator } = await import('./ai-leverage-calculator.js'); return AILeverageCalculator; } catch (error) { console.warn('⚠️ AI Leverage Calculator not available, using default leverage'); return null; } } // Import Enhanced Risk Manager with Learning for intelligent beach mode operation async function importEnhancedRiskManager() { try { const EnhancedAutonomousRiskManager = require('./enhanced-autonomous-risk-manager.js'); return EnhancedAutonomousRiskManager; } catch (error) { console.warn('⚠️ Enhanced Risk Manager not available, falling back to stable monitor'); // Fallback to stable risk monitor try { const StableRiskMonitor = require('./stable-risk-monitor.js'); return StableRiskMonitor; } catch (fallbackError) { console.warn('⚠️ Stable Risk Monitor also not available, using basic monitoring'); return null; } } } class SimpleAutomation { constructor() { this.isRunning = false; this.config = null; this.intervalId = null; this.riskManager = null; // Autonomous AI Risk Manager this.lastDecision = null; // Store last AI decision for UI display this.lastDCATime = 0; // Track last DCA execution time this.dcaCooldownHours = 2; // Minimum 2 hours between DCA trades // Initialize AI Learning System this.learner = new SimplifiedStopLossLearner(); console.log('🧠 AI Learning System initialized'); this.stats = { totalCycles: 0, totalTrades: 0, startTime: null, lastActivity: null, status: 'Stopped', networkErrors: 0, consecutiveErrors: 0 }; } 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'; console.log('✅ AUTOMATION STATUS: isRunning =', this.isRunning); console.log('🎯 LIVE TRADING:', this.config.enableTrading ? 'ENABLED' : 'DISABLED'); this.stats.totalCycles = 0; // Initialize Enhanced AI Risk Manager with Learning Capabilities try { const EnhancedRiskManagerClass = await importEnhancedRiskManager(); if (EnhancedRiskManagerClass) { this.riskManager = new EnhancedRiskManagerClass(); console.log('🧠 ENHANCED BEACH MODE: AI learning system activated'); console.log('🎯 System will learn from every decision and improve over time'); // Start enhanced autonomous operation setTimeout(() => { if (this.riskManager && this.riskManager.beachMode) { this.riskManager.beachMode(); console.log('🏖️ Full autonomous operation with AI learning active'); } }, 2000); } } catch (error) { console.log('🔄 Continuing without enhanced autonomous risk monitoring'); console.error('Risk manager initialization error:', error.message); } // Auto-enable trading when in LIVE mode if (config.mode === 'LIVE') { this.config.enableTrading = true; console.log('🔥 LIVE TRADING ENABLED: Real trades will be executed'); } else { this.config.enableTrading = false; console.log('📊 SIMULATION MODE: Trades will be simulated only'); } // 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 dynamic monitoring cycle with risk-based intervals console.log('🚀 STARTING: Dynamic monitoring with scalping optimization'); this.currentInterval = 30 * 1000; // Start with 30 seconds for immediate analysis this.startDynamicMonitoring(); // First cycle after 5 seconds (immediate for scalping) setTimeout(() => { console.log('🔥 IMMEDIATE CYCLE: Starting first analysis cycle'); this.runCycle(); }, 5000); 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 { console.log('🛑 STOPPING AUTOMATION...'); this.isRunning = false; this.stats.status = 'Stopped'; console.log('✅ AUTOMATION STATUS: isRunning =', this.isRunning); if (this.intervalId) { clearTimeout(this.intervalId); // Changed from clearInterval to clearTimeout this.intervalId = null; } // Stop risk monitor if running if (this.riskManager && this.riskManager.stop) { this.riskManager.stop(); console.log('🏖️ Beach mode monitoring stopped'); } 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 }; } } // Dynamic monitoring with risk-based intervals startDynamicMonitoring() { const runMonitoringCycle = async () => { if (!this.isRunning) return; await this.runCycle(); // Get current risk level from position monitor const nextInterval = await this.getNextInterval(); // Schedule next cycle with dynamic interval this.intervalId = setTimeout(runMonitoringCycle, nextInterval); }; // Start the dynamic cycle this.intervalId = setTimeout(runMonitoringCycle, this.currentInterval); } // Determine next interval based on risk level and position status async getNextInterval() { try { // Check position monitor for current risk level AND position status const baseUrl = process.env.INTERNAL_API_URL || 'http://localhost:3000'; const response = await fetch(`${baseUrl}/api/automation/position-monitor`); if (response.ok) { const data = await response.json(); const riskLevel = data.monitor?.riskLevel || 'NONE'; const hasPosition = data.monitor?.hasPosition; const recommendation = data.monitor?.recommendation; // Get timeframe-based intervals (scalping needs faster analysis) const baseInterval = this.getTimeframeBasedIntervals(); // 🚨 SCALPING LOGIC: No position = IMMEDIATE re-entry scanning if (!hasPosition && recommendation === 'START_TRADING') { const isScalping = this.config.selectedTimeframes?.includes('5m') || this.config.selectedTimeframes?.includes('15m'); if (isScalping) { // Ultra-fast intervals for scalping when no position const scalpingInterval = 2 * 60 * 1000; // 2 minutes for immediate re-entry console.log('🏃‍♂️ SCALPING ALERT: No position - scanning every 2 minutes for re-entry'); this.currentInterval = scalpingInterval; return scalpingInterval; } else { // Fast intervals for day trading when no position const dayTradingInterval = 5 * 60 * 1000; // 5 minutes for day trading console.log('⚡ DAY TRADING: No position - scanning every 5 minutes for re-entry'); this.currentInterval = dayTradingInterval; return dayTradingInterval; } } // Risk-based multipliers for existing positions let riskMultiplier; switch (riskLevel) { case 'CRITICAL': riskMultiplier = 0.5; // 50% faster when critical break; case 'HIGH': riskMultiplier = 0.7; // 30% faster when high risk break; case 'MEDIUM': riskMultiplier = 1.0; // Normal speed break; case 'LOW': riskMultiplier = 1.5; // 50% slower when low risk break; case 'NONE': default: // For NONE risk (no position), use base interval but don't slow down riskMultiplier = hasPosition ? 1.0 : 0.8; // Slightly faster when no position } const finalInterval = Math.round(baseInterval * riskMultiplier); const finalMinutes = finalInterval / (60 * 1000); console.log(`📊 Risk: ${riskLevel} | Position: ${hasPosition ? 'YES' : 'NO'} | Interval: ${finalMinutes} min`); console.log(`⚡ Optimized for ${this.getSelectedTimeframes().join(',') || 'default'} timeframes`); const intervalMs = finalInterval; console.log(`📊 DYNAMIC INTERVAL: Risk level ${riskLevel} → Next analysis in ${finalMinutes} minutes`); this.currentInterval = intervalMs; return intervalMs; } } catch (error) { console.warn('⚠️ Failed to get risk level for dynamic interval, using default 10 minutes:', error.message); } // Fallback to 10 minutes this.currentInterval = 10 * 60 * 1000; return this.currentInterval; } async runCycle() { try { // Check if automation should still be running if (!this.isRunning) { console.log('⏹️ AUTOMATION STOPPED: Skipping cycle'); return; } 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(); // Reset error counter on successful cycle this.stats.consecutiveErrors = 0; } } catch (error) { console.error('❌ CRITICAL ERROR in automation cycle:', error); console.error('❌ Stack trace:', error.stack); // Increment error counter this.stats.consecutiveErrors = (this.stats.consecutiveErrors || 0) + 1; // If too many consecutive errors, stop automation if (this.stats.consecutiveErrors >= 3) { console.error('🚨 TOO MANY ERRORS: Stopping automation after', this.stats.consecutiveErrors, 'consecutive failures'); this.isRunning = false; this.stats.status = 'Stopped due to errors'; if (this.intervalId) { clearTimeout(this.intervalId); // Changed from clearInterval to clearTimeout this.intervalId = null; } return; } console.log(`⚠️ Error ${this.stats.consecutiveErrors}/3 - Will retry next cycle`); } } async performAnalysis() { console.log(`📊 ANALYSIS CYCLE: Starting analysis for ${this.config.selectedTimeframes.length} timeframes...`); try { // 🚨 STEP 1: Check position monitor FIRST to determine market status const baseUrl = process.env.INTERNAL_API_URL || 'http://localhost:3000'; let hasPosition = false; let recommendation = 'HOLD'; let activeOrders = 0; try { console.log('🔍 Checking position monitor status...'); const monitorResponse = await fetch(`${baseUrl}/api/automation/position-monitor`); if (monitorResponse.ok) { const monitorData = await monitorResponse.json(); hasPosition = monitorData.monitor?.hasPosition || false; recommendation = monitorData.monitor?.recommendation || 'HOLD'; activeOrders = monitorData.monitor?.orphanedOrderCleanup?.summary?.activeOrders || 0; console.log(`📍 POSITION STATUS: ${hasPosition ? 'ACTIVE POSITION' : 'NO POSITION'}`); console.log(`🎯 MONITOR RECOMMENDATION: ${recommendation}`); console.log(`📋 ACTIVE ORDERS: ${activeOrders}`); } else { console.warn(`⚠️ Position monitor API error: ${monitorResponse.status}`); } } catch (monitorError) { console.warn('⚠️ Could not fetch position monitor, using defaults:', monitorError.message); } // 🚨 NO POSITION SCENARIO - SCALPING MODE if (!hasPosition) { console.log('🏃‍♂️ SCALPING MODE: No position detected - aggressive re-entry needed'); // 🧹 MANDATORY CLEANUP: Always clear ALL orders before re-entry (regardless of count) console.log('🧹 MANDATORY CLEANUP: Clearing all orphaned orders before re-entry...'); try { const cleanupResponse = await fetch(`${baseUrl}/api/drift/cleanup-orders`, { method: 'POST' }); if (cleanupResponse.ok) { const cleanupResult = await cleanupResponse.json(); const totalCanceled = cleanupResult.summary?.totalCanceled || 0; const activeOrdersAfter = cleanupResult.summary?.activeOrders || 0; console.log(`✅ CLEANUP COMPLETE: ${totalCanceled} orders canceled`); console.log(`📊 CLEANUP RESULT: ${activeOrdersAfter} orders remaining`); // Additional safety check - if orders still remain, try cancel-all endpoint if (activeOrdersAfter > 0) { console.log('🔄 ADDITIONAL CLEANUP: Found remaining orders, using cancel-all...'); const cancelAllResponse = await fetch(`${baseUrl}/api/drift/cancel-all-orders`, { method: 'POST' }); if (cancelAllResponse.ok) { const cancelAllResult = await cancelAllResponse.json(); console.log(`✅ CANCEL-ALL COMPLETE: ${cancelAllResult.totalCanceled || 0} additional orders canceled`); } } } else { console.warn(`⚠️ Cleanup API error: ${cleanupResponse.status}`); } } catch (cleanupError) { console.warn('⚠️ Order cleanup failed:', cleanupError.message); // Fallback: Try direct cancel-all as backup try { console.log('🔄 FALLBACK CLEANUP: Attempting direct cancel-all...'); const fallbackResponse = await fetch(`${baseUrl}/api/drift/cancel-all-orders`, { method: 'POST' }); if (fallbackResponse.ok) { const fallbackResult = await fallbackResponse.json(); console.log(`✅ FALLBACK COMPLETE: ${fallbackResult.totalCanceled || 0} orders canceled`); } } catch (fallbackError) { console.warn('⚠️ Fallback cleanup also failed:', fallbackError.message); } } // 🔍 VERIFY CLEANUP: Wait a moment and verify orders are cleared await new Promise(resolve => setTimeout(resolve, 1000)); // 1 second delay // For scalping, if no position, we ALWAYS analyze for immediate re-entry if (recommendation === 'START_TRADING' || !hasPosition) { console.log('🚀 IMMEDIATE ANALYSIS: Market cleared, scanning for entry opportunities...'); // Continue with analysis below } } else { console.log('📊 POSITION MONITORING: Existing position detected, normal analysis'); } // 🚨 STEP 2: Perform parallel analysis with better error handling console.log(`🚀 PARALLEL SCREENSHOTS: ${this.config.selectedTimeframes.length * 2} captures starting...`); try { const response = await fetch(`${baseUrl}/api/batch-analysis`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ symbol: this.config.symbol, timeframes: this.config.selectedTimeframes, 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) { // Reset consecutive error counter on success this.stats.consecutiveErrors = 0; 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 (await 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 (batchError) { // Track network errors this.stats.networkErrors++; this.stats.consecutiveErrors++; console.error(`❌ PARALLEL ANALYSIS FAILED (Network Error #${this.stats.networkErrors}):`, batchError.message); // If too many consecutive errors, slow down if (this.stats.consecutiveErrors >= 3) { console.warn(`⚠️ HIGH NETWORK ERROR COUNT: ${this.stats.consecutiveErrors} consecutive failures. System will continue but may slow down.`); } console.log(`🔄 FALLBACK: Using sequential analysis...`); return this.performSequentialAnalysis(); } } catch (error) { // Main try-catch for the entire performAnalysis method this.stats.consecutiveErrors++; console.error('❌ ANALYSIS ERROR:', error.message); // Fallback to sequential if all else fails try { return this.performSequentialAnalysis(); } catch (fallbackError) { console.error('❌ SEQUENTIAL ANALYSIS ALSO FAILED:', fallbackError.message); } } } // 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 baseUrl = process.env.INTERNAL_API_URL || 'http://localhost:3000'; const response = await fetch(`${baseUrl}/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 (await 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 }; } async shouldExecuteTrade(analysis) { console.log(`🎯 TRADE MODE: ${this.config.mode || 'SIMULATION'} - Trading ${this.config.enableTrading ? 'ENABLED' : 'DISABLED'}`); const recommendation = analysis.recommendation?.toLowerCase() || ''; const confidence = analysis.confidence || 0; // 🚨 DYNAMIC CONFIDENCE BASED ON POSITION STATUS // Check if we have an active position let hasActivePosition = false; try { // This will be updated by the position monitor check in performAnalysis // For now, assume no position if we're running scalping analysis const isScalping = this.config.selectedTimeframes?.includes('5m') || this.config.selectedTimeframes?.includes('15m'); hasActivePosition = false; // Will be properly detected in position monitor } catch (error) { console.warn('⚠️ Could not determine position status for confidence adjustment'); } // 🎯 IMPROVED CONFIDENCE THRESHOLDS - Higher standards to reduce losses let minConfidence = 80; // Increased default confidence if (!hasActivePosition) { // NO POSITION = Still require high confidence for quality entries if (this.config.selectedTimeframes?.includes('1h')) { minConfidence = 75; // 1h timeframe - medium confidence console.log('📊 1H TRADING: Using 75% confidence threshold (no position)'); } else if (this.config.selectedTimeframes?.includes('4h')) { minConfidence = 70; // 4h timeframe - lower confidence OK due to higher reliability console.log('📈 4H TRADING: Using 70% confidence threshold (no position)'); } else if (this.config.selectedTimeframes?.includes('5m')) { minConfidence = 80; // 5m requires very high confidence due to noise console.log('⚡ 5M SCALPING: Using high 80% confidence (noisy timeframe)'); } else if (this.config.selectedTimeframes?.includes('15m')) { minConfidence = 78; // 15m also requires high confidence console.log('🏃‍♂️ 15M SCALPING: Using high 78% confidence (noisy timeframe)'); } else { minConfidence = 72; // Slightly lower for day trading console.log('📈 DAY TRADING: Using 72% confidence (no position)'); } } else { // EXISTING POSITION = Higher confidence threshold for additional entries if (this.config.selectedTimeframes?.includes('5m') || this.config.selectedTimeframes?.includes('15m')) { minConfidence = 80; // Higher confidence for scalping with existing position console.log('⚖️ POSITION EXISTS: Using conservative 80% confidence'); } else { minConfidence = 75; // Standard confidence for day trading console.log('📊 POSITION EXISTS: Using standard 75% confidence'); } } const isHighConfidence = confidence >= minConfidence; const isClearDirection = recommendation.includes('buy') || recommendation.includes('sell') || recommendation.includes('long') || recommendation.includes('short'); // 🧠 GET AI LEARNING RECOMMENDATION TO INFLUENCE DECISION let finalWillExecute = isHighConfidence && isClearDirection; let learningInfluence = null; try { const learningRec = await this.getAILearningRecommendation(analysis); if (learningRec) { learningInfluence = learningRec; console.log(`🧠 AI LEARNING INPUT: ${learningRec.action} (${(learningRec.confidence * 100).toFixed(1)}% confidence)`); console.log(`📚 Learning Reasoning: ${learningRec.reasoning}`); // Adjust decision based on learning if (learningRec.action === 'HOLD_POSITION' && learningRec.confidence > 0.7) { console.log('🧠 AI Learning suggests HOLD - reducing execution likelihood'); finalWillExecute = finalWillExecute && (confidence >= (minConfidence + 10)); // Require 10% higher confidence } else if (learningRec.action === 'EXECUTE_TRADE' && learningRec.confidence > 0.7) { console.log('🧠 AI Learning suggests EXECUTE - lowering confidence threshold'); finalWillExecute = (confidence >= (minConfidence - 5)) && isClearDirection; // Allow 5% lower confidence } } } catch (error) { console.log('⚠️ Learning recommendation error:', error.message); } console.log(`🎯 TRADE DECISION: ${recommendation} (${confidence}%) vs Required: ${minConfidence}%`); console.log(`🧠 Learning Influence: ${learningInfluence ? learningInfluence.action : 'None'}`); console.log(`✅ Final Decision: ${finalWillExecute ? 'EXECUTE' : 'HOLD'}`); // 🧠 RECORD AI DECISION FOR LEARNING this.recordAIDecisionForLearning(analysis, { recommendation, confidence, minConfidenceRequired: minConfidence, hasActivePosition, willExecute: finalWillExecute, learningInfluence: learningInfluence }); // Store decision data for UI display this.lastDecision = { timestamp: new Date().toISOString(), recommendation: analysis.recommendation || 'HOLD', confidence: confidence, minConfidenceRequired: minConfidence, hasActivePosition: hasActivePosition, reasoning: analysis.reasoning || analysis.summary || 'No detailed reasoning available', executed: false, executionDetails: null, executionError: null, learningRecorded: true, learningInfluence: learningInfluence }; return finalWillExecute; } async executeTrade(analysis) { try { console.log('💰 EXECUTING TRADE...'); console.log('📊 Analysis data:', JSON.stringify(analysis, null, 2)); // Check if we already have a position to prevent fragmentation const apiBaseUrl = process.env.INTERNAL_API_URL || 'http://localhost:3000'; const existingPositions = await fetch(`${apiBaseUrl}/api/drift/positions`); const positionsData = await existingPositions.json(); if (positionsData.success && positionsData.positions.length > 0) { console.log('🔍 EXISTING POSITION DETECTED - Checking DCA scaling opportunity...'); // Check DCA cooldown period to prevent over-execution const currentTime = Date.now(); const timeSinceLastDCA = (currentTime - this.lastDCATime) / (1000 * 60 * 60); // Hours if (timeSinceLastDCA < this.dcaCooldownHours) { const remainingCooldown = (this.dcaCooldownHours - timeSinceLastDCA).toFixed(1); console.log(`⏰ DCA COOLDOWN ACTIVE - ${remainingCooldown} hours remaining`); console.log('🛡️ Preventing DCA over-execution that caused 24+ orders'); return { success: false, error: `DCA cooldown active - ${remainingCooldown} hours remaining`, existingPosition: positionsData.positions[0], cooldownRemaining: remainingCooldown }; } const currentPosition = positionsData.positions[0]; console.log('📊 Current position:', currentPosition); console.log('✅ DCA cooldown passed - executing POSITION SCALING DCA...'); // Check if analysis direction matches existing position const recommendation = analysis.recommendation?.toLowerCase() || ''; let analysisDirection = ''; if (recommendation.includes('buy')) { analysisDirection = 'buy'; } else if (recommendation.includes('sell')) { analysisDirection = 'sell'; } else { return { success: false, error: `Invalid recommendation for DCA: ${recommendation}`, existingPosition: currentPosition, suggestedAction: 'Cannot determine direction from analysis' }; } const positionDirection = currentPosition.side.toLowerCase(); if (analysisDirection === 'buy' && positionDirection === 'long') { console.log('🎯 SCALING LONG POSITION - Adding to existing long position'); return await this.executePositionScaling(analysis, this.config.tradingAmount || 49); } else if (analysisDirection === 'sell' && positionDirection === 'short') { console.log('🎯 SCALING SHORT POSITION - Adding to existing short position'); return await this.executePositionScaling(analysis, this.config.tradingAmount || 49); } else { console.log('🔄 DIRECTION MISMATCH - Analysis suggests opposite direction'); console.log(` Position: ${positionDirection.toUpperCase()} | Analysis: ${analysisDirection.toUpperCase()}`); return { success: false, error: `Direction mismatch: Position is ${positionDirection}, analysis suggests ${analysisDirection}`, existingPosition: currentPosition, suggestedAction: 'Consider position consolidation or exit strategy' }; } } // 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 }; } console.log(`🔧 DEBUG: Side variable initialized as: "${side}" from recommendation: "${recommendation}"`); // Validate side is properly set if (!side || (side !== 'BUY' && side !== 'SELL')) { console.log('❌ TRADE ERROR: Side variable not properly initialized'); return { success: false, error: 'Side variable initialization error' }; } // Extract stop loss and take profit from analysis let stopLoss = null; let takeProfit = null; // Try to extract from the structured analysis format if (analysis.stopLoss && typeof analysis.stopLoss === 'object') { stopLoss = analysis.stopLoss.price; } else if (analysis.stopLoss && typeof analysis.stopLoss === 'number') { stopLoss = analysis.stopLoss; } // Extract take profit - prefer tp1 if available if (analysis.takeProfits && typeof analysis.takeProfits === 'object') { if (analysis.takeProfits.tp1 && analysis.takeProfits.tp1.price) { takeProfit = analysis.takeProfits.tp1.price; } else if (analysis.takeProfits.tp2 && analysis.takeProfits.tp2.price) { takeProfit = analysis.takeProfits.tp2.price; } } else if (analysis.takeProfit && typeof analysis.takeProfit === 'number') { takeProfit = analysis.takeProfit; } // Fallback: try to extract from nested levels object if (!stopLoss && analysis.levels) { stopLoss = analysis.levels.stopLoss || analysis.levels.stop; } if (!takeProfit && analysis.levels) { takeProfit = analysis.levels.takeProfit || analysis.levels.target; } // Parse numeric values if they're strings if (stopLoss && typeof stopLoss === 'string') { stopLoss = parseFloat(stopLoss.replace(/[^0-9.]/g, '')); } if (takeProfit && typeof takeProfit === 'string') { takeProfit = parseFloat(takeProfit.replace(/[^0-9.]/g, '')); } // 🛡️ FALLBACK RISK MANAGEMENT: Ensure SL/TP always exist if (!stopLoss || !takeProfit) { console.log('⚠️ Missing AI-calculated SL/TP, generating fallback values...'); const currentPrice = analysis.entry?.price || analysis.currentPrice || 178; if (!stopLoss) { // Fallback: 1.5% stop loss for scalping if (side === 'BUY' || side === 'LONG') { stopLoss = currentPrice * 0.985; // 1.5% below entry } else { stopLoss = currentPrice * 1.015; // 1.5% above entry } console.log(`🔧 Generated fallback stop loss: $${stopLoss.toFixed(4)} (1.5%)`); } if (!takeProfit) { // Fallback: 3% take profit for scalping (2:1 risk/reward) if (side === 'BUY' || side === 'LONG') { takeProfit = currentPrice * 1.03; // 3% above entry } else { takeProfit = currentPrice * 0.97; // 3% below entry } console.log(`🔧 Generated fallback take profit: $${takeProfit.toFixed(4)} (3%)`); } } console.log(`🎯 Final trade levels - SL: ${stopLoss}, TP: ${takeProfit}`); // Calculate optimal leverage using AI Leverage Calculator let optimalLeverage = 1; // Default fallback let leverageResult = null; // Store leverage calculation result for UI display console.log('🔧 DEBUG: Starting leverage calculation...'); try { const AILeverageCalculator = await importAILeverageCalculator(); console.log('🔧 DEBUG: AI Leverage Calculator imported:', !!AILeverageCalculator); if (AILeverageCalculator && stopLoss) { console.log('🔧 DEBUG: Both calculator and stopLoss available, proceeding...'); // Get current price from analysis const currentPrice = analysis.entry?.price || analysis.currentPrice || 178; // fallback price // Get real account data from Drift API let accountValue = 49; // fallback let availableBalance = 49; // fallback try { console.log('🔧 DEBUG: Fetching balance from:', apiBaseUrl); const balanceResponse = await fetch(`${apiBaseUrl}/api/drift/balance`); const balanceData = await balanceResponse.json(); if (balanceData.success) { accountValue = balanceData.accountValue; availableBalance = balanceData.availableBalance; console.log(`💰 Real account data: $${accountValue.toFixed(2)} total, $${availableBalance.toFixed(2)} available`); } else { console.log('🔧 DEBUG: Balance API returned error:', balanceData); } } catch (balanceError) { console.warn('⚠️ Failed to get real balance, using fallback:', balanceError.message); } console.log(`🧮 Calculating optimal leverage: Entry=$${currentPrice}, StopLoss=$${stopLoss}`); console.log(`🔧 DEBUG: Side variable before leverage calc: "${side}"`); const leverageCalcResult = AILeverageCalculator.calculateOptimalLeverage({ accountValue, availableBalance, entryPrice: currentPrice, stopLossPrice: stopLoss, side: side === 'BUY' ? 'long' : 'short', maxLeverageAllowed: 100, // Drift platform max (can go up to 101x) safetyBuffer: 0.10 // 10% safety buffer }); // Store the result for UI display leverageResult = leverageCalcResult; optimalLeverage = leverageCalcResult.recommendedLeverage; optimalLeverage = leverageCalcResult.recommendedLeverage; console.log(`🎯 AI Calculated Leverage: ${optimalLeverage.toFixed(1)}x (Risk: ${leverageCalcResult.riskAssessment})`); console.log(`📊 Leverage Details: ${leverageCalcResult.reasoning}`); } else { console.log('🔧 DEBUG: Skipping leverage calc - Calculator:', !!AILeverageCalculator, 'StopLoss:', !!stopLoss); } } catch (leverageError) { console.warn('⚠️ Leverage calculation failed, using default 1x:', leverageError.message); } console.log(`🔧 DEBUG: Final leverage to use: ${optimalLeverage}x`); // 🧹 MANDATORY CLEANUP: Clear all orders before new trade execution console.log('🧹 PRE-TRADE CLEANUP: Ensuring no orphaned orders before new trade...'); try { const cleanupResponse = await fetch(`${apiBaseUrl}/api/drift/cleanup-orders`, { method: 'POST' }); if (cleanupResponse.ok) { const cleanupResult = await cleanupResponse.json(); const totalCanceled = cleanupResult.summary?.totalCanceled || 0; console.log(`✅ PRE-TRADE CLEANUP: ${totalCanceled} orders cleared before trade execution`); // Additional safety: If orders still exist, use cancel-all if (cleanupResult.summary?.activeOrders > 0) { console.log('🔄 ADDITIONAL CLEANUP: Remaining orders found, using cancel-all...'); const cancelAllResponse = await fetch(`${apiBaseUrl}/api/drift/cancel-all-orders`, { method: 'POST' }); if (cancelAllResponse.ok) { const cancelAllResult = await cancelAllResponse.json(); console.log(`✅ CANCEL-ALL COMPLETE: ${cancelAllResult.totalCanceled || 0} additional orders cleared`); } } } else { console.warn(`⚠️ Pre-trade cleanup failed: ${cleanupResponse.status}`); } // Brief delay to ensure cleanup is processed await new Promise(resolve => setTimeout(resolve, 500)); } catch (cleanupError) { console.warn('⚠️ Pre-trade cleanup error:', cleanupError.message); } // ✅ PROCEED DIRECTLY TO TRADE EXECUTION (Risk management removed) console.log('� PROCEEDING WITH TRADE EXECUTION...'); console.log(` Entry: $${analysis.entry?.price || analysis.currentPrice || 0}`); console.log(` SL: $${stopLoss?.toFixed(2) || 'N/A'}`); console.log(` TP: $${takeProfit?.toFixed(2) || 'N/A'}`); console.log(` Leverage: ${optimalLeverage}x`); // Use the trading API with proper fields for Drift const tradePayload = { symbol: this.config.symbol, side: side, amount: this.config.tradingAmount || 49, // Use available balance leverage: optimalLeverage, // Use AI-calculated optimal leverage stopLoss: stopLoss, takeProfit: takeProfit, useRealDEX: true, // Enable LIVE trading always analysis: analysis // Include analysis for reference }; console.log('📊 TRADE PAYLOAD:', tradePayload); const response = await fetch(`${apiBaseUrl}/api/trading/execute-drift`, { 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; // Log the successful trade for live analysis panel try { const baseUrl = process.env.INTERNAL_API_URL || 'http://localhost:3000'; // Use actual execution data from the trade result let actualEntryPrice = 0; if (result.executionPrice) { actualEntryPrice = result.executionPrice; } else if (result.price) { actualEntryPrice = result.price; } else if (analysis.entry?.price) { actualEntryPrice = analysis.entry.price; } else if (analysis.currentPrice) { actualEntryPrice = analysis.currentPrice; } await fetch(`${baseUrl}/api/automation/live-decisions`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'TRADE_EXECUTED', action: side?.toUpperCase() || 'UNKNOWN', symbol: this.config.symbol, blocked: false, executed: true, confidence: analysis.confidence || 0, entryPrice: actualEntryPrice, stopLoss: stopLoss, takeProfit: takeProfit, leverage: optimalLeverage, amount: tradePayload.amount, reasoning: analysis.reasoning || 'No reasoning provided', aiLeverageReasoning: leverageResult ? leverageResult.reasoning : 'AI leverage calculation not available', txId: result.transactionId || result.signature, timestamp: new Date().toISOString(), cycle: this.stats.totalCycles }) }); } catch (logError) { console.warn('⚠️ Failed to log executed trade:', logError.message); } // Update DCA timestamp to prevent over-execution this.lastDCATime = Date.now(); console.log(`⏰ DCA cooldown activated - Next DCA possible in ${this.dcaCooldownHours} hours`); // 🧠 TRACK SUCCESSFUL TRADE OUTCOME FOR LEARNING await this.trackTradeOutcomeForLearning(result); // Update last decision with execution details if (this.lastDecision) { this.lastDecision.executed = true; this.lastDecision.executionDetails = { side: side, amount: tradePayload.amount, leverage: optimalLeverage, currentPrice: analysis.entry?.price || analysis.currentPrice, stopLoss: stopLoss, takeProfit: takeProfit, aiReasoning: leverageResult ? leverageResult.reasoning : 'AI leverage calculation not available', txId: result.transactionId || result.signature, aiStopLossPercent: analysis.stopLossPercent || 'Not specified' }; } } else { console.log('❌ TRADE FAILED: ' + result.error); // 🧠 TRACK FAILED TRADE OUTCOME FOR LEARNING await this.trackTradeOutcomeForLearning(result); // Update last decision with execution error if (this.lastDecision) { this.lastDecision.executed = false; this.lastDecision.executionError = result.error || 'Unknown execution error'; } } return result; } catch (error) { console.error('❌ TRADE ERROR:', error.message); return { success: false, error: error.message }; } } // Position Scaling DCA - Increase existing position size with adjusted SL/TP async executePositionScaling(analysis, dcaAmount) { try { console.log('🎯 EXECUTING POSITION SCALING DCA...'); console.log(`💰 Adding $${dcaAmount} to existing position with AI-calculated levels`); // Use the position scaling API const baseUrl = process.env.INTERNAL_API_URL || 'http://localhost:3000'; const response = await fetch(`${baseUrl}/api/drift/scale-position`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ dcaAmount: dcaAmount, analysis: analysis // Pass AI analysis for optimal SL/TP levels }) }); const result = await response.json(); if (result.success) { console.log('✅ POSITION SCALING SUCCESSFUL'); console.log(`📊 Old: ${result.scalingResult.originalSize.toFixed(4)} @ $${result.scalingResult.originalEntryPrice.toFixed(4)}`); console.log(`📈 New: ${result.scalingResult.newTotalSize.toFixed(4)} @ $${result.scalingResult.newAveragePrice.toFixed(4)}`); console.log(`🛡️ Stop Loss: $${result.scalingResult.newStopLoss.toFixed(4)}`); console.log(`🎯 Take Profit: $${result.scalingResult.newTakeProfit.toFixed(4)}`); // 🧠 TRACK SUCCESSFUL POSITION SCALING FOR LEARNING await this.trackTradeOutcomeForLearning(result); // Update stats and DCA timestamp this.stats.totalTrades = (this.stats.totalTrades || 0) + 1; this.stats.successfulTrades = (this.stats.successfulTrades || 0) + 1; this.lastDCATime = Date.now(); console.log(`⏰ DCA cooldown activated - Next DCA possible in ${this.dcaCooldownHours} hours`); // Update last decision with scaling details if (this.lastDecision) { this.lastDecision.executed = true; this.lastDecision.executionDetails = { type: 'POSITION_SCALING', dcaAmount: dcaAmount, originalSize: result.scalingResult.originalSize, newTotalSize: result.scalingResult.newTotalSize, originalEntryPrice: result.scalingResult.originalEntryPrice, newAveragePrice: result.scalingResult.newAveragePrice, newStopLoss: result.scalingResult.newStopLoss, newTakeProfit: result.scalingResult.newTakeProfit, usedAILevels: result.scalingResult.usedAILevels, txIds: { dcaTx: result.scalingResult.dcaTxId, stopLossTx: result.scalingResult.stopLossTxId, takeProfitTx: result.scalingResult.takeProfitTxId } }; } } else { console.log('❌ POSITION SCALING FAILED:', result.error); // Update last decision with error if (this.lastDecision) { this.lastDecision.executed = false; this.lastDecision.executionError = result.error || 'Position scaling failed'; } } return result; } catch (error) { console.error('❌ POSITION SCALING ERROR:', error.message); return { success: false, error: error.message }; } } async getStatus() { const baseStatus = { isRunning: this.isRunning, // Changed from isActive to isRunning isActive: this.isRunning, // Keep both for compatibility mode: this.config?.mode || 'SIMULATION', enableTrading: this.config?.enableTrading || false, tradingStatus: this.config?.enableTrading ? 'REAL TRADES' : 'SIMULATED ONLY', symbol: this.config?.symbol || 'SOLUSD', timeframes: this.config?.selectedTimeframes || [], automationType: 'SIMPLE', lastDecision: this.lastDecision, // Include last AI decision for UI display config: this.config, // Include config for debugging ...this.stats }; // Add AI Learning Status try { const learningInsights = await this.getAILearningInsights(); baseStatus.aiLearning = { available: learningInsights.available, systemConfidence: learningInsights.report?.summary?.systemConfidence || 0, totalDecisions: learningInsights.report?.summary?.totalDecisions || 0, successRate: learningInsights.report?.summary?.successRate || 0, phase: this.getAILearningPhase(learningInsights.report?.summary?.totalDecisions || 0) }; } catch (error) { baseStatus.aiLearning = { available: false, error: error.message }; } // Add more descriptive status based on running state if (this.isRunning) { baseStatus.detailedStatus = 'Running - Monitoring for trade opportunities'; baseStatus.nextAction = 'Next analysis cycle in progress'; } else { baseStatus.detailedStatus = 'Stopped - No monitoring active'; baseStatus.nextAction = 'Start automation to begin monitoring'; } return baseStatus; } // Helper method to determine AI learning phase getAILearningPhase(totalDecisions) { if (totalDecisions < 5) return 'INITIAL'; if (totalDecisions < 20) return 'LEARNING'; if (totalDecisions < 50) return 'DEVELOPING'; return 'EXPERT'; } // Get intervals based on trading timeframes (scalping needs faster analysis) getTimeframeBasedIntervals() { const timeframes = this.getSelectedTimeframes(); // Detect if this is scalping (5m, 15m, 30m) const isScalping = timeframes.some(tf => ['5', '5m', '15', '15m', '30', '30m'].includes(tf)); const isDayTrading = timeframes.some(tf => ['60', '1h', '120', '2h'].includes(tf)); const isSwingTrading = timeframes.some(tf => ['240', '4h', '1D', '1d'].includes(tf)); if (isScalping) { console.log('🎯 SCALPING DETECTED: Using faster 10-minute intervals (was 30-90)'); return 10 * 60 * 1000; // 10 minutes for scalping - fast enough for 5m charts } else if (isDayTrading) { console.log('⚡ DAY TRADING DETECTED: Using 20-minute intervals'); return 20 * 60 * 1000; // 20 minutes for day trading } else if (isSwingTrading) { console.log('📈 SWING TRADING DETECTED: Using 45-minute intervals'); return 45 * 60 * 1000; // 45 minutes for swing trading } else { // Unknown/mixed strategy - use moderate interval console.log('📊 MIXED STRATEGY: Using 30-minute intervals'); return 30 * 60 * 1000; // 30 minutes default } } // Get selected timeframes from config getSelectedTimeframes() { return this.config?.timeframes || this.config?.selectedTimeframes || ['1h']; } // Detect trading strategy from timeframes detectStrategy() { const timeframes = this.getSelectedTimeframes(); const isScalping = timeframes.some(tf => ['5', '5m', '15', '15m', '30', '30m'].includes(tf)); const isDayTrading = timeframes.some(tf => ['60', '1h', '120', '2h'].includes(tf)); const isSwingTrading = timeframes.some(tf => ['240', '4h', '1D', '1d'].includes(tf)); if (isScalping) return 'Scalping'; if (isDayTrading) return 'Day Trading'; if (isSwingTrading) return 'Swing Trading'; return 'Mixed'; } // 🧠 AI LEARNING INTEGRATION METHODS /** * Record AI decision for learning system */ async recordAIDecisionForLearning(analysis, decisionContext) { try { if (!this.learner || typeof this.learner.recordDecision !== 'function') { console.log('⚠️ Learning system not available - skipping decision recording'); return null; } const decisionData = { tradeId: `trade_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, symbol: this.config?.symbol || 'SOLUSD', decision: decisionContext.willExecute ? 'EXECUTE_TRADE' : 'HOLD_POSITION', confidence: decisionContext.confidence, recommendation: decisionContext.recommendation, reasoning: analysis.reasoning || analysis.summary || 'AI analysis recommendation', marketConditions: { timeframes: this.config?.selectedTimeframes || ['1h'], strategy: this.detectStrategy(), minConfidenceRequired: decisionContext.minConfidenceRequired }, expectedOutcome: decisionContext.willExecute ? 'PROFITABLE_TRADE' : 'WAIT_BETTER_OPPORTUNITY', aiLevels: { stopLoss: analysis.stopLoss?.price || analysis.stopLoss, takeProfit: analysis.takeProfits?.tp1?.price || analysis.takeProfit, entry: analysis.entry?.price || analysis.currentPrice } }; const decisionId = await this.learner.recordDecision(decisionData); console.log(`🧠 AI Decision recorded for learning: ${decisionData.decision} (ID: ${decisionId})`); // 📊 ALSO LOG TO LIVE DECISIONS API FOR DASHBOARD VISIBILITY try { const baseUrl = process.env.INTERNAL_API_URL || 'http://localhost:3000'; // Extract better entry price from analysis let entryPrice = 0; if (analysis.entry?.price) { entryPrice = analysis.entry.price; } else if (analysis.currentPrice) { entryPrice = analysis.currentPrice; } else if (analysis.entry && typeof analysis.entry === 'number') { entryPrice = analysis.entry; } await fetch(`${baseUrl}/api/automation/live-decisions`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'AI_DECISION', action: decisionData.recommendation?.toUpperCase() || decisionData.decision, symbol: decisionData.symbol, blocked: !decisionContext.willExecute, executed: decisionContext.willExecute, confidence: decisionData.confidence, entryPrice: entryPrice, stopLoss: decisionData.aiLevels.stopLoss, takeProfit: decisionData.aiLevels.takeProfit, reasoning: decisionData.reasoning, timestamp: new Date().toISOString(), cycle: this.stats.totalCycles, learningDecisionId: decisionId }) }); console.log(`📊 AI Decision logged to live-decisions API: ${decisionData.decision} with entry: $${entryPrice}`); } catch (apiError) { console.warn('⚠️ Failed to log decision to live-decisions API:', apiError.message); } // Store decision ID for later outcome tracking if (this.lastDecision) { this.lastDecision.learningDecisionId = decisionId; } return decisionId; } catch (error) { console.error('❌ Error recording AI decision for learning:', error.message); return null; } } /** * Track trade outcome for learning system */ async trackTradeOutcomeForLearning(executionResult, decisionId = null) { try { if (!this.learner || typeof this.learner.assessDecisionOutcome !== 'function') { console.log('⚠️ Learning system not available - skipping outcome tracking'); return; } const targetDecisionId = decisionId || this.lastDecision?.learningDecisionId; if (!targetDecisionId) { console.log('⚠️ No decision ID available for outcome tracking'); return; } const outcomeData = { decisionId: targetDecisionId, actualOutcome: executionResult.success ? 'TRADE_EXECUTED' : 'TRADE_FAILED', timeToOutcome: Date.now() - new Date(this.lastDecision?.timestamp || Date.now()).getTime(), pnlImpact: executionResult.success ? 0 : -10, // Will be updated later with actual P&L executionDetails: executionResult, marketConditions: { timestamp: new Date().toISOString(), symbol: this.config?.symbol || 'SOLUSD' } }; const success = await this.learner.assessDecisionOutcome(outcomeData); if (success) { console.log(`🧠 Trade outcome recorded for learning: ${outcomeData.actualOutcome}`); } } catch (error) { console.error('❌ Error tracking trade outcome for learning:', error.message); } } /** * Get AI learning insights and recommendations */ async getAILearningInsights() { try { if (!this.learner) { return { available: false, message: 'Learning system not initialized' }; } // Check if learning methods are available if (typeof this.learner.generateLearningReport === 'function') { const report = await this.learner.generateLearningReport(); return { available: true, report: report, type: 'FULL_REPORT' }; } else if (typeof this.learner.getLearningStatus === 'function') { const status = await this.learner.getLearningStatus(); return { available: true, report: status, type: 'BASIC_STATUS' }; } else { return { available: false, message: 'Learning methods not available' }; } } catch (error) { console.error('❌ Error getting AI learning insights:', error.message); return { available: false, error: error.message }; } } /** * Use AI learning to improve trade decisions */ async getAILearningRecommendation(analysis) { try { if (!this.learner || typeof this.learner.getSmartRecommendation !== 'function') { console.log('🧠 Smart recommendations not available - using standard analysis'); return null; } const requestData = { symbol: this.config?.symbol || 'SOLUSD', confidence: analysis.confidence || 0, recommendation: analysis.recommendation, marketConditions: { timeframes: this.config?.selectedTimeframes || ['1h'], strategy: this.detectStrategy() }, aiLevels: { stopLoss: analysis.stopLoss?.price || analysis.stopLoss, takeProfit: analysis.takeProfits?.tp1?.price || analysis.takeProfit } }; const learningRec = await this.learner.getSmartRecommendation(requestData); if (learningRec && learningRec.confidence > 0.6) { console.log(`🧠 AI Learning Recommendation: ${learningRec.action} (${(learningRec.confidence * 100).toFixed(1)}% confidence)`); console.log(`📚 Learning Reasoning: ${learningRec.reasoning}`); return learningRec; } return null; } catch (error) { console.error('❌ Error getting AI learning recommendation:', error.message); return null; } } } // Export singleton instance const simpleAutomation = new SimpleAutomation(); export { simpleAutomation };