diff --git a/app/api/batch-analysis/route.js b/app/api/batch-analysis/route.js index 0d88f49..c061441 100644 --- a/app/api/batch-analysis/route.js +++ b/app/api/batch-analysis/route.js @@ -23,6 +23,7 @@ async function storeAnalysisForLearning(symbol, analysis) { await prisma.ai_learning_data.create({ data: { + id: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, // Generate unique ID userId: 'default-user', // Use same default user as ai-learning-status symbol: symbol, timeframe: 'MULTI', // Indicates multi-timeframe batch analysis diff --git a/lib/enhanced-autonomous-risk-manager.js b/lib/enhanced-autonomous-risk-manager.js index 17fbb1b..3c34ad4 100644 --- a/lib/enhanced-autonomous-risk-manager.js +++ b/lib/enhanced-autonomous-risk-manager.js @@ -912,7 +912,7 @@ class EnhancedAutonomousRiskManager { // Generate learning reports periodically setInterval(async () => { if (this.isActive) { - const report = await this.learner.generateLearningReport(); + // const report = await this.learner.generateLearningReport(); // TEMPORARILY DISABLED if (report) { await this.log(`📊 Learning Update: ${report.summary.totalDecisions} decisions, ${(report.summary.systemConfidence * 100).toFixed(1)}% confidence`); } @@ -960,7 +960,7 @@ class EnhancedAutonomousRiskManager { */ async getLearningStatus() { try { - const slReport = await this.learner.generateLearningReport(); + // const slReport = await this.learner.generateLearningReport(); // TEMPORARILY DISABLED const rrPatterns = await this.rrLearner.updateRiskRewardLearning(); return { diff --git a/lib/enhanced-autonomous-risk-manager.js.backup b/lib/enhanced-autonomous-risk-manager.js.backup new file mode 100644 index 0000000..17fbb1b --- /dev/null +++ b/lib/enhanced-autonomous-risk-manager.js.backup @@ -0,0 +1,1051 @@ +/** + * Enhanced Autonomous AI Risk Management System with Complete R/R Learning + * + * This system learns from BOTH stop losses AND take profits to optimize + * risk/reward setups and make smarter position management decisions. + */ + +const SimplifiedStopLossLearner = require('./simplified-stop-loss-learner'); +const SimplifiedRiskRewardLearner = require('./simplified-risk-reward-learner'); +const HttpUtil = require('./http-util'); +const { exec } = require('child_process'); +const util = require('util'); +const execAsync = util.promisify(exec); + +class EnhancedAutonomousRiskManager { + constructor() { + this.isActive = false; + this.learner = new SimplifiedStopLossLearner(); + this.rrLearner = new SimplifiedRiskRewardLearner(); // NEW: Complete R/R learning + this.emergencyThreshold = 1.0; // Will be updated by learning system + this.riskThreshold = 2.0; + this.mediumRiskThreshold = 5.0; + this.pendingDecisions = new Map(); // Track decisions awaiting outcomes + this.activeSetups = new Map(); // Track R/R setups for outcome learning + this.lastAnalysis = null; + this.baseApiUrl = this.detectApiUrl(); // Docker-aware API URL + this.lastScreenshotAnalysis = null; // Track when we last analyzed screenshots + this.screenshotAnalysisThreshold = 3.5; // Only analyze screenshots when < 3.5% from SL (demo: was 3.0) + this.screenshotAnalysisInterval = 2 * 60 * 1000; // Don't analyze more than once every 2 minutes (demo: was 5) + } + + /** + * Detect the correct API URL based on environment + * Returns localhost for host environment, gateway IP for Docker + */ + detectApiUrl() { + try { + // Check if running inside Docker container + const fs = require('fs'); + if (fs.existsSync('/.dockerenv')) { + // Get the default gateway IP from /proc/net/route + try { + const routeData = fs.readFileSync('/proc/net/route', 'utf8'); + const lines = routeData.split('\n'); + for (const line of lines) { + const parts = line.trim().split(/\s+/); + // Look for default route (destination 00000000) + if (parts[1] === '00000000' && parts[2] && parts[2] !== '00000000') { + // Convert hex gateway to IP + const gatewayHex = parts[2]; + const ip = [ + parseInt(gatewayHex.substr(6, 2), 16), + parseInt(gatewayHex.substr(4, 2), 16), + parseInt(gatewayHex.substr(2, 2), 16), + parseInt(gatewayHex.substr(0, 2), 16) + ].join('.'); + return `http://${ip}:9001`; + } + } + // Fallback to known gateway IP + return 'http://192.168.160.1:9001'; + } catch (routeError) { + // Fallback to the known gateway IP for this Docker setup + return 'http://192.168.160.1:9001'; + } + } + + // Check hostname (Docker containers often have specific hostnames) + const os = require('os'); + const hostname = os.hostname(); + if (hostname && hostname.length === 12 && /^[a-f0-9]+$/.test(hostname)) { + // Same gateway detection for hostname-based detection + try { + const routeData = fs.readFileSync('/proc/net/route', 'utf8'); + const lines = routeData.split('\n'); + for (const line of lines) { + const parts = line.trim().split(/\s+/); + if (parts[1] === '00000000' && parts[2] && parts[2] !== '00000000') { + const gatewayHex = parts[2]; + const ip = [ + parseInt(gatewayHex.substr(6, 2), 16), + parseInt(gatewayHex.substr(4, 2), 16), + parseInt(gatewayHex.substr(2, 2), 16), + parseInt(gatewayHex.substr(0, 2), 16) + ].join('.'); + return `http://${ip}:9001`; + } + } + return 'http://192.168.160.1:9001'; + } catch (routeError) { + return 'http://192.168.160.1:9001'; + } + } + + // Default to localhost for host environment + return 'http://localhost:9001'; + } catch (error) { + // Fallback to localhost if detection fails + return 'http://localhost:9001'; + } + } + + /** + * Determine if we should trigger screenshot analysis based on risk level + */ + shouldTriggerScreenshotAnalysis(distancePercent) { + // Only trigger when approaching critical levels + if (distancePercent > this.screenshotAnalysisThreshold) { + return false; + } + + // Don't analyze too frequently + if (this.lastScreenshotAnalysis) { + const timeSinceLastAnalysis = Date.now() - this.lastScreenshotAnalysis.getTime(); + if (timeSinceLastAnalysis < this.screenshotAnalysisInterval) { + return false; + } + } + + return true; + } + + /** + * Request screenshot analysis from the main trading system + */ + async requestScreenshotAnalysis(symbol) { + try { + this.lastScreenshotAnalysis = new Date(); + + await this.log(`📸 Requesting chart analysis for ${symbol} - risk level requires visual confirmation`); + + // Use the enhanced screenshot API with analysis + const response = await HttpUtil.post(`${this.baseApiUrl}/api/enhanced-screenshot`, { + symbol: symbol, + timeframes: ['1h'], // Focus on primary timeframe for speed + layouts: ['ai'], // Only AI layout for faster analysis + analyze: true, + reason: 'RISK_MANAGEMENT_ANALYSIS' + }); + + if (response.success && response.analysis) { + await this.log(`✅ Chart analysis complete: ${response.analysis.recommendation} (${response.analysis.confidence}% confidence)`); + + return { + recommendation: response.analysis.recommendation, + confidence: response.analysis.confidence, + marketSentiment: response.analysis.marketSentiment, + keyLevels: response.analysis.keyLevels, + reasoning: response.analysis.reasoning, + supportNearby: this.detectNearbySupport(response.analysis, symbol), + resistanceNearby: this.detectNearbyResistance(response.analysis, symbol), + technicalStrength: this.assessTechnicalStrength(response.analysis), + timestamp: new Date() + }; + } + + return null; + } catch (error) { + await this.log(`❌ Error in screenshot analysis: ${error.message}`); + return null; + } + } + + /** + * Detect if there's strong support near current price + */ + detectNearbySupport(analysis, symbol) { + if (!analysis.keyLevels?.support) return false; + + // Get current price from last position data + const currentPrice = this.lastAnalysis?.monitor?.position?.currentPrice || 0; + if (!currentPrice) return false; + + // Check if any support level is within 2% of current price + return analysis.keyLevels.support.some(supportLevel => { + const distance = Math.abs(currentPrice - supportLevel) / currentPrice; + return distance < 0.02; // Within 2% + }); + } + + /** + * Detect if there's resistance near current price + */ + detectNearbyResistance(analysis, symbol) { + if (!analysis.keyLevels?.resistance) return false; + + const currentPrice = this.lastAnalysis?.monitor?.position?.currentPrice || 0; + if (!currentPrice) return false; + + return analysis.keyLevels.resistance.some(resistanceLevel => { + const distance = Math.abs(currentPrice - resistanceLevel) / currentPrice; + return distance < 0.02; // Within 2% + }); + } + + /** + * Assess overall technical strength from chart analysis + */ + assessTechnicalStrength(analysis) { + let strength = 'NEUTRAL'; + + if (analysis.confidence > 80 && analysis.marketSentiment === 'BULLISH') { + strength = 'STRONG_BULLISH'; + } else if (analysis.confidence > 80 && analysis.marketSentiment === 'BEARISH') { + strength = 'STRONG_BEARISH'; + } else if (analysis.confidence > 60) { + strength = `MODERATE_${analysis.marketSentiment}`; + } + + return strength; + } async log(message) { + const timestamp = new Date().toISOString(); + console.log(`[${timestamp}] 🤖 Enhanced Risk AI: ${message}`); + } + + /** + * Main analysis function that integrates learning-based decision making + */ + async analyzePosition(monitor) { + try { + if (!monitor || !monitor.hasPosition) { + return { + action: 'NO_ACTION', + reasoning: 'No position to analyze', + confidence: 1.0 + }; + } + + const { position, stopLossProximity } = monitor; + const distance = parseFloat(stopLossProximity.distancePercent); + + // Update thresholds based on learning + await this.updateThresholdsFromLearning(); + + // SMART SCREENSHOT ANALYSIS TRIGGER + // Only analyze screenshots when approaching critical levels + let chartAnalysis = null; + if (this.shouldTriggerScreenshotAnalysis(distance)) { + await this.log(`📸 Triggering screenshot analysis - distance: ${distance}%`); + chartAnalysis = await this.requestScreenshotAnalysis(position.symbol); + } + + // Get AI recommendation based on learned patterns + const smartRecommendation = await this.learner.getSmartRecommendation({ + distanceFromSL: distance, + symbol: position.symbol, + marketConditions: { + price: position.entryPrice, // Current price context + unrealizedPnl: position.unrealizedPnl, + side: position.side + }, + chartAnalysis: chartAnalysis // Include visual analysis if available + }); + + let decision; + + // Enhanced decision logic using learning + if (distance < this.emergencyThreshold) { + decision = await this.handleEmergencyRisk(monitor, smartRecommendation); + } else if (distance < this.riskThreshold) { + decision = await this.handleHighRisk(monitor, smartRecommendation); + } else if (distance < this.mediumRiskThreshold) { + decision = await this.handleMediumRisk(monitor, smartRecommendation); + } else { + decision = await this.handleSafePosition(monitor, smartRecommendation); + } + + // Record this decision for learning + const decisionId = await this.recordDecisionForLearning(monitor, decision, smartRecommendation); + decision.decisionId = decisionId; + + this.lastAnalysis = { monitor, decision, timestamp: new Date() }; + + return decision; + } catch (error) { + await this.log(`❌ Error in position analysis: ${error.message}`); + return { + action: 'ERROR', + reasoning: `Analysis error: ${error.message}`, + confidence: 0.1 + }; + } + } + + async handleEmergencyRisk(monitor, smartRecommendation) { + const { position, stopLossProximity } = monitor; + const distance = parseFloat(stopLossProximity.distancePercent); + + await this.log(`🚨 EMERGENCY: Position ${distance}% from stop loss!`); + + // Use learning-based recommendation if highly confident + if (smartRecommendation.learningBased && smartRecommendation.confidence > 0.8) { + await this.log(`🧠 Using learned strategy: ${smartRecommendation.suggestedAction} (${(smartRecommendation.confidence * 100).toFixed(1)}% confidence)`); + + return { + action: smartRecommendation.suggestedAction, + reasoning: `AI Learning: ${smartRecommendation.reasoning}`, + confidence: smartRecommendation.confidence, + urgency: 'CRITICAL', + learningEnhanced: true, + supportingData: smartRecommendation.supportingData + }; + } + + // Fallback to rule-based emergency logic + return { + action: 'EMERGENCY_EXIT', + reasoning: 'Price critically close to stop loss. Autonomous exit to preserve capital.', + confidence: 0.9, + urgency: 'CRITICAL', + parameters: { + exitPercentage: 100, + maxSlippage: 0.5 + } + }; + } + + async handleHighRisk(monitor, smartRecommendation) { + const { position, stopLossProximity } = monitor; + const distance = parseFloat(stopLossProximity.distancePercent); + + await this.log(`âš ī¸ HIGH RISK: Position ${distance}% from stop loss`); + + // Check if we have recent chart analysis data + const chartAnalysis = smartRecommendation.chartAnalysis; + + // Use chart analysis to make smarter decisions + if (chartAnalysis) { + await this.log(`📊 Using chart analysis: ${chartAnalysis.technicalStrength} sentiment, ${chartAnalysis.confidence}% confidence`); + + // If there's strong support nearby and bullish sentiment, consider holding + if (chartAnalysis.supportNearby && + chartAnalysis.technicalStrength.includes('BULLISH') && + chartAnalysis.confidence > 70 && + position.side === 'long') { + + await this.log(`đŸ›Ąī¸ Strong support detected near ${position.currentPrice} - holding position with tighter stop`); + return { + action: 'TIGHTEN_STOP_LOSS', + reasoning: `Chart shows strong support nearby (${chartAnalysis.reasoning}). Tightening stop instead of exiting.`, + confidence: chartAnalysis.confidence / 100, + urgency: 'HIGH', + chartEnhanced: true, + parameters: { + newStopLossDistance: distance * 0.8 // Tighten by 20% + } + }; + } + + // If chart shows weakness, exit more aggressively + if (chartAnalysis.technicalStrength.includes('BEARISH') && chartAnalysis.confidence > 60) { + await this.log(`📉 Chart shows weakness - executing defensive exit`); + return { + action: 'PARTIAL_EXIT', + reasoning: `Chart analysis shows bearish signals (${chartAnalysis.reasoning}). Reducing exposure.`, + confidence: chartAnalysis.confidence / 100, + urgency: 'HIGH', + chartEnhanced: true, + parameters: { + exitPercentage: 70, // More aggressive exit + keepStopLoss: true + } + }; + } + } + + // Check learning recommendation + if (smartRecommendation.learningBased && smartRecommendation.confidence > 0.7) { + return { + action: smartRecommendation.suggestedAction, + reasoning: `AI Learning: ${smartRecommendation.reasoning}`, + confidence: smartRecommendation.confidence, + urgency: 'HIGH', + learningEnhanced: true + }; + } + + // Enhanced market analysis for high-risk situations + const marketAnalysis = await this.analyzeMarketConditions(position.symbol); + + if (marketAnalysis.trend === 'BULLISH' && position.side === 'LONG') { + return { + action: 'TIGHTEN_STOP_LOSS', + reasoning: 'Market still favorable. Tightening stop loss for better risk management.', + confidence: 0.7, + urgency: 'HIGH', + parameters: { + newStopLossDistance: distance * 0.7 // Tighten by 30% + } + }; + } else { + return { + action: 'PARTIAL_EXIT', + reasoning: 'Market conditions uncertain. Reducing position size to manage risk.', + confidence: 0.75, + urgency: 'HIGH', + parameters: { + exitPercentage: 50, + keepStopLoss: true + } + }; + } + } + + async handleMediumRisk(monitor, smartRecommendation) { + const { position, stopLossProximity } = monitor; + const distance = parseFloat(stopLossProximity.distancePercent); + + await this.log(`🟡 MEDIUM RISK: Position ${distance}% from stop loss`); + + // Learning-based decision for medium risk + if (smartRecommendation.learningBased && smartRecommendation.confidence > 0.6) { + return { + action: smartRecommendation.suggestedAction, + reasoning: `AI Learning: ${smartRecommendation.reasoning}`, + confidence: smartRecommendation.confidence, + urgency: 'MEDIUM', + learningEnhanced: true + }; + } + + // Default medium risk response + return { + action: 'ENHANCED_MONITORING', + reasoning: 'Increased monitoring frequency. Preparing contingency plans.', + confidence: 0.6, + urgency: 'MEDIUM', + parameters: { + monitoringInterval: 30, // seconds + alertThreshold: this.riskThreshold + } + }; + } + + async handleSafePosition(monitor, smartRecommendation) { + const { position } = monitor; + + // Even in safe positions, check for optimization opportunities + if (smartRecommendation.learningBased && smartRecommendation.confidence > 0.8) { + if (smartRecommendation.suggestedAction === 'SCALE_POSITION') { + return { + action: 'SCALE_POSITION', + reasoning: `AI Learning: ${smartRecommendation.reasoning}`, + confidence: smartRecommendation.confidence, + urgency: 'LOW', + learningEnhanced: true + }; + } + } + + return { + action: 'MONITOR', + reasoning: 'Position is safe. Continuing standard monitoring.', + confidence: 0.8, + urgency: 'LOW' + }; + } + + /** + * Record a new risk/reward setup when trade is placed + */ + async recordTradeSetup(tradeData) { + try { + const { tradeId, symbol, entryPrice, stopLoss, takeProfit, leverage, side, aiReasoning } = tradeData; + + const setupId = await this.rrLearner.recordRiskRewardSetup({ + tradeId, + symbol, + entryPrice, + stopLoss, + takeProfit, + leverage: leverage || 1.0, + side, + aiReasoning: aiReasoning || 'Autonomous AI setup', + aiConfidence: 0.8, + expectedOutcome: 'REACH_TAKE_PROFIT' + }); + + if (setupId) { + this.activeSetups.set(tradeId, { + setupId, + tradeData, + timestamp: new Date() + }); + + await this.log(`📊 Recorded R/R setup ${setupId} for trade ${tradeId}: SL=${stopLoss} TP=${takeProfit}`); + } + + return setupId; + } catch (error) { + await this.log(`❌ Error recording trade setup: ${error.message}`); + return null; + } + } + + /** + * Record trade outcome when position closes + */ + async recordTradeOutcome(tradeId, outcomeData) { + try { + const setup = this.activeSetups.get(tradeId); + if (!setup) { + await this.log(`âš ī¸ No setup found for trade ${tradeId}`); + return; + } + + const { exitPrice, exitReason, actualPnL } = outcomeData; + const timeToExit = Math.floor((Date.now() - setup.timestamp.getTime()) / 60000); // minutes + + const outcome = await this.rrLearner.recordTradeOutcome({ + setupId: setup.setupId, + exitPrice, + exitReason, // 'STOP_LOSS', 'TAKE_PROFIT', 'MANUAL_EXIT', 'LIQUIDATION' + actualPnL, + timeToExit, + setupData: setup.tradeData + }); + + if (outcome) { + await this.log(`✅ Recorded outcome for trade ${tradeId}: ${exitReason} - Quality: ${outcome.quality}`); + + // Learn from this outcome + if (outcome.suggestedImprovements.length > 0) { + await this.log(`💡 Improvement suggestions: ${outcome.suggestedImprovements.join(', ')}`); + } + } + + // Remove from active setups + this.activeSetups.delete(tradeId); + + return outcome; + } catch (error) { + await this.log(`❌ Error recording trade outcome: ${error.message}`); + return null; + } + } + + /** + * Get smart risk/reward recommendation for new trade + */ + async getSmartRiskRewardSetup(requestData) { + try { + const recommendation = await this.rrLearner.getSmartRiskRewardRecommendation(requestData); + + await this.log(`đŸŽ¯ Smart R/R recommendation: SL=${recommendation.stopLossDistance?.toFixed(2)}% RR=1:${recommendation.riskRewardRatio.toFixed(2)} (${(recommendation.confidence * 100).toFixed(1)}% confidence)`); + + return recommendation; + } catch (error) { + await this.log(`❌ Error getting R/R recommendation: ${error.message}`); + return { + stopLossDistance: 2.5, + riskRewardRatio: 2.0, + confidence: 0.3, + reasoning: 'Error in recommendation system', + learningBased: false + }; + } + } + async recordDecisionForLearning(monitor, decision, smartRecommendation) { + try { + const { position, stopLossProximity } = monitor; + const distance = parseFloat(stopLossProximity.distancePercent); + + const decisionData = { + tradeId: position.id || `position_${Date.now()}`, + symbol: position.symbol, + decision: decision.action, + distanceFromSL: distance, + reasoning: decision.reasoning, + currentPrice: position.entryPrice, + confidenceScore: decision.confidence, + expectedOutcome: this.predictOutcome(decision.action, distance), + marketConditions: await this.getCurrentMarketConditions(position.symbol), + learningRecommendation: smartRecommendation + }; + + const decisionId = await this.learner.recordDecision(decisionData); + + // Store decision for outcome tracking + this.pendingDecisions.set(decisionId, { + ...decisionData, + timestamp: new Date(), + monitor: monitor + }); + + await this.log(`📝 Recorded decision ${decisionId} for learning: ${decision.action}`); + + return decisionId; + } catch (error) { + await this.log(`❌ Error recording decision for learning: ${error.message}`); + return null; + } + } + + /** + * Assess outcomes of previous decisions and R/R setups + */ + async assessDecisionOutcomes() { + try { + // Assess stop loss decisions + for (const [decisionId, decisionData] of this.pendingDecisions.entries()) { + const timeSinceDecision = Date.now() - decisionData.timestamp.getTime(); + + // Assess after sufficient time has passed (5 minutes minimum) + if (timeSinceDecision > 5 * 60 * 1000) { + const outcome = await this.determineDecisionOutcome(decisionData); + + if (outcome) { + await this.learner.assessDecisionOutcome({ + decisionId, + actualOutcome: outcome.result, + timeToOutcome: Math.floor(timeSinceDecision / 60000), // minutes + pnlImpact: outcome.pnlImpact, + additionalContext: outcome.context + }); + + // Remove from pending decisions + this.pendingDecisions.delete(decisionId); + await this.log(`✅ Assessed SL decision ${decisionId}: ${outcome.result}`); + } + } + } + + // Check for closed positions and assess R/R setups + await this.assessRiskRewardSetups(); + + } catch (error) { + await this.log(`❌ Error assessing decision outcomes: ${error.message}`); + } + } + + /** + * Check for closed positions and assess risk/reward setup outcomes + */ + async assessRiskRewardSetups() { + try { + for (const [tradeId, setup] of this.activeSetups.entries()) { + const timeSinceSetup = Date.now() - setup.timestamp.getTime(); + + // Check if position is still active after reasonable time + if (timeSinceSetup > 10 * 60 * 1000) { // 10 minutes minimum + const positionStatus = await this.checkPositionStatus(setup.tradeData.symbol); + + if (!positionStatus || !positionStatus.hasPosition) { + // Position closed - try to determine outcome + const outcome = await this.determineTradeOutcome(setup); + + if (outcome) { + await this.recordTradeOutcome(tradeId, outcome); + } else { + // If we can't determine outcome, record as manual exit + await this.recordTradeOutcome(tradeId, { + exitPrice: setup.tradeData.entryPrice, // Assume breakeven + exitReason: 'MANUAL_EXIT', + actualPnL: 0 + }); + } + } + } + } + } catch (error) { + await this.log(`❌ Error assessing R/R setups: ${error.message}`); + } + } + + /** + * Determine trade outcome from position monitoring + */ + async determineTradeOutcome(setup) { + try { + // This is a simplified version - in real implementation, you'd check + // trade history, position changes, and execution logs + const currentStatus = await this.getCurrentPositionStatus(setup.tradeData.symbol); + + if (!currentStatus) { + // Position no longer exists - need to determine how it closed + // For demo purposes, simulate random outcomes + const outcomes = ['STOP_LOSS', 'TAKE_PROFIT', 'MANUAL_EXIT']; + const randomOutcome = outcomes[Math.floor(Math.random() * outcomes.length)]; + + let exitPrice = setup.tradeData.entryPrice; + let actualPnL = 0; + + switch (randomOutcome) { + case 'STOP_LOSS': + exitPrice = setup.tradeData.stopLoss; + actualPnL = -Math.abs(setup.tradeData.entryPrice - setup.tradeData.stopLoss); + break; + case 'TAKE_PROFIT': + exitPrice = setup.tradeData.takeProfit; + actualPnL = Math.abs(setup.tradeData.takeProfit - setup.tradeData.entryPrice); + break; + case 'MANUAL_EXIT': + exitPrice = setup.tradeData.entryPrice + (Math.random() - 0.5) * 10; // Random exit + actualPnL = exitPrice - setup.tradeData.entryPrice; + break; + } + + return { + exitPrice, + exitReason: randomOutcome, + actualPnL + }; + } + + return null; // Position still active + } catch (error) { + await this.log(`❌ Error determining trade outcome: ${error.message}`); + return null; + } + } + + async checkPositionStatus(symbol) { + // Check if position is still active + try { + const data = await HttpUtil.get(`${this.baseApiUrl}/api/automation/position-monitor`); + + if (data.success && data.monitor?.hasPosition && data.monitor.position?.symbol === symbol) { + return data.monitor; + } + + return null; + } catch (error) { + return null; + } + } + + async determineDecisionOutcome(decisionData) { + try { + // Get current position status + const currentStatus = await this.getCurrentPositionStatus(decisionData.symbol); + + if (!currentStatus) { + return { + result: 'POSITION_CLOSED', + pnlImpact: 0, + context: { reason: 'Position no longer exists' } + }; + } + + // Compare current situation with when decision was made + const originalDistance = decisionData.distanceFromSL; + const currentDistance = currentStatus.distanceFromSL; + const pnlChange = currentStatus.unrealizedPnl - (decisionData.monitor.position?.unrealizedPnl || 0); + + // Determine if decision was beneficial + if (decisionData.decision === 'EMERGENCY_EXIT' && currentDistance < 0.5) { + return { + result: 'AVOIDED_MAJOR_LOSS', + pnlImpact: Math.abs(pnlChange), // Positive impact + context: { originalDistance, currentDistance } + }; + } + + if (decisionData.decision === 'TIGHTEN_STOP_LOSS' && pnlChange > 0) { + return { + result: 'IMPROVED_PROFIT', + pnlImpact: pnlChange, + context: { originalDistance, currentDistance } + }; + } + + if (decisionData.decision === 'HOLD' && currentDistance > originalDistance) { + return { + result: 'CORRECT_HOLD', + pnlImpact: pnlChange, + context: { distanceImproved: currentDistance - originalDistance } + }; + } + + // Default assessment + return { + result: pnlChange >= 0 ? 'NEUTRAL_POSITIVE' : 'NEUTRAL_NEGATIVE', + pnlImpact: pnlChange, + context: { originalDistance, currentDistance } + }; + } catch (error) { + await this.log(`❌ Error determining decision outcome: ${error.message}`); + return null; + } + } + + async getCurrentPositionStatus(symbol) { + try { + const data = await HttpUtil.get(`${this.baseApiUrl}/api/automation/position-monitor`); + + if (data.success && data.monitor?.hasPosition) { + return { + distanceFromSL: parseFloat(data.monitor.stopLossProximity?.distancePercent || 0), + unrealizedPnl: data.monitor.position?.unrealizedPnl || 0 + }; + } + + return null; + } catch (error) { + return null; + } + } + + async updateThresholdsFromLearning() { + try { + // Get learned optimal thresholds + const patterns = await this.learner.analyzeDecisionPatterns(); + + if (patterns?.distanceOptimization) { + const optimization = patterns.distanceOptimization; + + if (optimization.emergencyRange?.optimalThreshold) { + this.emergencyThreshold = optimization.emergencyRange.optimalThreshold; + } + if (optimization.highRiskRange?.optimalThreshold) { + this.riskThreshold = optimization.highRiskRange.optimalThreshold; + } + if (optimization.mediumRiskRange?.optimalThreshold) { + this.mediumRiskThreshold = optimization.mediumRiskRange.optimalThreshold; + } + + await this.log(`🔄 Updated thresholds from learning: Emergency=${this.emergencyThreshold.toFixed(2)}%, Risk=${this.riskThreshold.toFixed(2)}%, Medium=${this.mediumRiskThreshold.toFixed(2)}%`); + } + } catch (error) { + await this.log(`❌ Error updating thresholds from learning: ${error.message}`); + } + } + + predictOutcome(action, distance) { + // Predict what we expect to happen based on the action + const predictions = { + 'EMERGENCY_EXIT': 'AVOID_MAJOR_LOSS', + 'PARTIAL_EXIT': 'REDUCE_RISK', + 'TIGHTEN_STOP_LOSS': 'BETTER_RISK_REWARD', + 'SCALE_POSITION': 'INCREASED_PROFIT', + 'HOLD': 'MAINTAIN_POSITION', + 'ENHANCED_MONITORING': 'EARLY_WARNING' + }; + + return predictions[action] || 'UNKNOWN_OUTCOME'; + } + + async analyzeMarketConditions(symbol) { + // Enhanced market analysis for better decision making + try { + const data = await HttpUtil.get(`${this.baseApiUrl}/api/automation/position-monitor`); + + if (data.success && data.monitor?.position) { + const pnl = data.monitor.position.unrealizedPnl; + const trend = pnl > 0 ? 'BULLISH' : pnl < -1 ? 'BEARISH' : 'SIDEWAYS'; + + return { + trend, + strength: Math.abs(pnl), + timeOfDay: new Date().getHours(), + volatility: Math.random() * 0.1 // Mock volatility + }; + } + } catch (error) { + // Fallback analysis + } + + return { + trend: 'UNKNOWN', + strength: 0, + timeOfDay: new Date().getHours(), + volatility: 0.05 + }; + } + + async getCurrentMarketConditions(symbol) { + const conditions = await this.analyzeMarketConditions(symbol); + return { + ...conditions, + dayOfWeek: new Date().getDay(), + timestamp: new Date().toISOString() + }; + } + + /** + * Enhanced Beach Mode with learning integration + */ + async beachMode() { + await this.log('đŸ–ī¸ ENHANCED BEACH MODE: Autonomous operation with AI learning'); + this.isActive = true; + + // Main monitoring loop + const monitoringLoop = async () => { + if (!this.isActive) return; + + try { + // Check current positions + const data = await HttpUtil.get(`${this.baseApiUrl}/api/automation/position-monitor`); + + if (data.success) { + const decision = await this.analyzePosition(data.monitor); + await this.executeDecision(decision); + } + + // Assess outcomes of previous decisions + await this.assessDecisionOutcomes(); + + } catch (error) { + await this.log(`Error in beach mode: ${error.message}`); + } + + // Schedule next check + if (this.isActive) { + setTimeout(monitoringLoop, 60000); // Check every minute + } + }; + + // Start monitoring + monitoringLoop(); + + // Generate learning reports periodically + setInterval(async () => { + if (this.isActive) { + const report = await this.learner.generateLearningReport(); + if (report) { + await this.log(`📊 Learning Update: ${report.summary.totalDecisions} decisions, ${(report.summary.systemConfidence * 100).toFixed(1)}% confidence`); + } + } + }, 15 * 60 * 1000); // Every 15 minutes + } + + async executeDecision(decision) { + await this.log(`đŸŽ¯ Executing decision: ${decision.action} - ${decision.reasoning} (Confidence: ${(decision.confidence * 100).toFixed(1)}%)`); + + // Add learning enhancement indicators + if (decision.learningEnhanced) { + await this.log(`🧠 Decision enhanced by AI learning system`); + } + + // Implementation would depend on your trading API + switch (decision.action) { + case 'EMERGENCY_EXIT': + await this.log('🚨 Implementing emergency exit protocol'); + break; + case 'PARTIAL_EXIT': + await this.log('📉 Executing partial position closure'); + break; + case 'TIGHTEN_STOP_LOSS': + await this.log('đŸŽ¯ Adjusting stop loss parameters'); + break; + case 'SCALE_POSITION': + await this.log('📈 Scaling position size'); + break; + case 'ENHANCED_MONITORING': + await this.log('đŸ‘ī¸ Activating enhanced monitoring'); + break; + default: + await this.log(`â„šī¸ Monitoring: ${decision.reasoning}`); + } + } + + stop() { + this.isActive = false; + this.log('🛑 Enhanced autonomous risk management stopped'); + } + + /** + * Get comprehensive learning system status including R/R insights + */ + async getLearningStatus() { + try { + const slReport = await this.learner.generateLearningReport(); + const rrPatterns = await this.rrLearner.updateRiskRewardLearning(); + + return { + isLearning: true, + stopLossLearning: { + totalDecisions: this.pendingDecisions.size + (slReport?.summary?.totalDecisions || 0), + systemConfidence: slReport?.summary?.systemConfidence || 0.3, + pendingAssessments: this.pendingDecisions.size, + insights: slReport?.insights + }, + riskRewardLearning: { + activeSetups: this.activeSetups.size, + totalSetups: rrPatterns?.stopLossPatterns?.length || 0, + stopLossPatterns: rrPatterns?.stopLossPatterns || [], + takeProfitPatterns: rrPatterns?.takeProfitPatterns || [], + optimalRatios: rrPatterns?.optimalRatios || [], + learningQuality: this.assessRRLearningQuality(rrPatterns) + }, + currentThresholds: { + emergency: this.emergencyThreshold, + risk: this.riskThreshold, + mediumRisk: this.mediumRiskThreshold + }, + lastAnalysis: this.lastAnalysis, + systemMaturity: this.calculateSystemMaturity(slReport, rrPatterns), + beachModeReady: this.isSystemReadyForBeachMode(slReport, rrPatterns) + }; + } catch (error) { + return { + isLearning: false, + error: error.message, + stopLossLearning: { totalDecisions: 0, systemConfidence: 0.1 }, + riskRewardLearning: { activeSetups: 0, totalSetups: 0 } + }; + } + } + + assessRRLearningQuality(rrPatterns) { + if (!rrPatterns) return 'INSUFFICIENT_DATA'; + + const totalPatterns = (rrPatterns.stopLossPatterns?.length || 0) + + (rrPatterns.takeProfitPatterns?.length || 0); + + if (totalPatterns >= 10) return 'HIGH_QUALITY'; + if (totalPatterns >= 5) return 'MEDIUM_QUALITY'; + if (totalPatterns >= 2) return 'LOW_QUALITY'; + return 'INSUFFICIENT_DATA'; + } + + calculateSystemMaturity(slReport, rrPatterns) { + const slDecisions = slReport?.summary?.totalDecisions || 0; + const rrSetups = rrPatterns?.optimalRatios?.length || 0; + + const totalLearningPoints = slDecisions + (rrSetups * 2); // R/R setups worth 2x + + if (totalLearningPoints >= 100) return 'EXPERT'; + if (totalLearningPoints >= 50) return 'ADVANCED'; + if (totalLearningPoints >= 20) return 'INTERMEDIATE'; + if (totalLearningPoints >= 10) return 'NOVICE'; + return 'BEGINNER'; + } + + isSystemReadyForBeachMode(slReport, rrPatterns) { + const slConfidence = slReport?.summary?.systemConfidence || 0; + const rrQuality = this.assessRRLearningQuality(rrPatterns); + + return slConfidence > 0.6 && ['HIGH_QUALITY', 'MEDIUM_QUALITY'].includes(rrQuality); + } +} + +// Export for use in other modules +module.exports = EnhancedAutonomousRiskManager; + +// Direct execution for testing +if (require.main === module) { + const riskManager = new EnhancedAutonomousRiskManager(); + + console.log('🤖 Enhanced Autonomous Risk Manager with AI Learning'); + console.log('🧠 Now learning from every decision to become smarter!'); + console.log('đŸ–ī¸ Perfect for beach mode - gets better while you relax!'); + + riskManager.beachMode(); + + process.on('SIGINT', () => { + riskManager.stop(); + process.exit(0); + }); +} diff --git a/next.config.ts b/next.config.ts index adec6b4..cec0b4a 100644 --- a/next.config.ts +++ b/next.config.ts @@ -3,9 +3,7 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { /* config options here */ output: 'standalone', - experimental: { - serverComponentsExternalPackages: ['puppeteer-core'] - }, + serverExternalPackages: ['puppeteer-core'], transpilePackages: ['next-font'], eslint: { ignoreDuringBuilds: true,