/** * Position-Aware Smart Automation * * This addresses the user concerns: * 1. Clear visibility of what's happening * 2. Specific stop loss monitoring * 3. Transparent decision making * 4. No black box behavior */ // Enhanced simple automation with position awareness class PositionAwareAutomation { constructor() { this.isRunning = false; this.config = null; this.intervalId = null; this.positionCheckInterval = null; this.stats = { totalCycles: 0, totalTrades: 0, startTime: null, lastActivity: null, status: 'Stopped', networkErrors: 0, consecutiveErrors: 0, lastPositionCheck: null, positionMonitoringActive: false }; } async start(config) { try { if (this.isRunning) { return { success: false, message: 'Automation already running' }; } this.config = config; this.isRunning = true; this.stats.startTime = new Date().toISOString(); this.stats.status = 'Running'; console.log('πŸš€ POSITION-AWARE AUTOMATION STARTING...'); console.log('βœ… AUTOMATION STATUS: isRunning =', this.isRunning); // Check for existing positions first const positionMonitor = await this.checkPositions(); if (positionMonitor.hasPosition) { console.log('πŸ“Š EXISTING POSITION DETECTED:', positionMonitor.position.symbol, positionMonitor.position.side); console.log('🎯 RISK LEVEL:', positionMonitor.riskLevel); console.log('πŸ“ NEXT ACTION:', positionMonitor.nextAction); // Start position monitoring await this.startPositionMonitoring(positionMonitor); } else { console.log('πŸ’° NO POSITIONS - Starting opportunity scanning...'); // Start opportunity scanning await this.startOpportunityScanning(); } return { success: true, message: 'Position-aware automation started', hasPosition: positionMonitor.hasPosition, positionDetails: positionMonitor.position, riskLevel: positionMonitor.riskLevel, nextAction: positionMonitor.nextAction }; } catch (error) { console.error('Failed to start position-aware automation:', error); return { success: false, message: 'Failed to start automation: ' + error.message }; } } async checkPositions() { try { const baseUrl = process.env.INTERNAL_API_URL || 'http://localhost:3000'; const response = await fetch(`${baseUrl}/api/automation/position-monitor`); const data = await response.json(); if (data.success) { this.stats.lastPositionCheck = new Date().toISOString(); return data.monitor; } else { throw new Error('Failed to get position data'); } } catch (error) { console.error('❌ Position check failed:', error); return { hasPosition: false, position: null, riskLevel: 'UNKNOWN', nextAction: 'Retry position check', recommendation: 'ERROR' }; } } async startPositionMonitoring(positionData) { console.log('πŸ›‘οΈ STARTING POSITION MONITORING MODE'); console.log(`⏰ Risk Level: ${positionData.riskLevel}`); this.stats.positionMonitoringActive = true; // Set monitoring frequency based on risk let checkInterval; switch (positionData.riskLevel) { case 'CRITICAL': checkInterval = 30 * 1000; // 30 seconds break; case 'HIGH': checkInterval = 2 * 60 * 1000; // 2 minutes break; case 'MEDIUM': checkInterval = 5 * 60 * 1000; // 5 minutes break; default: checkInterval = 10 * 60 * 1000; // 10 minutes } console.log(`⏰ Position monitoring every ${checkInterval/1000} seconds`); // Start position monitoring loop this.positionCheckInterval = setInterval(async () => { await this.runPositionCheck(); }, checkInterval); // Run first check immediately setTimeout(() => this.runPositionCheck(), 5000); } async startOpportunityScanning() { console.log('πŸ” STARTING OPPORTUNITY SCANNING MODE'); console.log('⏰ Scanning for entries every 10 minutes'); this.stats.positionMonitoringActive = false; // Start opportunity scanning (less frequent when no position) this.intervalId = setInterval(async () => { await this.runOpportunityCheck(); }, 10 * 60 * 1000); // 10 minutes // Run first check after 30 seconds setTimeout(() => this.runOpportunityCheck(), 30000); } async runPositionCheck() { try { if (!this.isRunning) { console.log('⏹️ POSITION CHECK STOPPED: Automation not running'); return; } console.log('πŸ” POSITION CHECK: Monitoring stop loss proximity...'); const positionData = await this.checkPositions(); if (!positionData.hasPosition) { console.log('πŸ“€ POSITION CLOSED: Switching to opportunity scanning...'); // Clear position monitoring if (this.positionCheckInterval) { clearInterval(this.positionCheckInterval); this.positionCheckInterval = null; } // Start opportunity scanning await this.startOpportunityScanning(); return; } console.log(`πŸ“Š Position Status: ${positionData.position.symbol} ${positionData.position.side}`); console.log(`⚠️ Risk Level: ${positionData.riskLevel}`); console.log(`πŸ“ Distance to SL: ${positionData.stopLossProximity?.distancePercent}%`); // Take action based on proximity if (positionData.riskLevel === 'CRITICAL' || positionData.riskLevel === 'HIGH') { console.log('🚨 RUNNING EMERGENCY ANALYSIS...'); await this.runEmergencyAnalysis(positionData); } this.stats.totalCycles++; this.stats.lastActivity = new Date().toISOString(); } catch (error) { console.error('❌ Position check error:', error); this.stats.consecutiveErrors++; } } async runOpportunityCheck() { try { if (!this.isRunning) { console.log('⏹️ OPPORTUNITY CHECK STOPPED: Automation not running'); return; } console.log('πŸ’° OPPORTUNITY CHECK: Scanning for entry signals...'); // Check if position was opened while we were scanning const positionData = await this.checkPositions(); if (positionData.hasPosition) { console.log('πŸ“ˆ NEW POSITION DETECTED: Switching to position monitoring...'); // Clear opportunity scanning if (this.intervalId) { clearInterval(this.intervalId); this.intervalId = null; } // Start position monitoring await this.startPositionMonitoring(positionData); return; } // Run normal analysis for entry opportunities console.log('πŸ”„ Running entry analysis...'); // TODO: Add your normal analysis logic here this.stats.totalCycles++; this.stats.lastActivity = new Date().toISOString(); } catch (error) { console.error('❌ Opportunity check error:', error); this.stats.consecutiveErrors++; } } async runEmergencyAnalysis(positionData) { console.log('🚨 EMERGENCY ANALYSIS: Price approaching stop loss!'); console.log(`πŸ“Š Position: ${positionData.position.side} ${positionData.position.size} at $${positionData.position.entryPrice}`); console.log(`πŸ’° Current PnL: $${positionData.position.unrealizedPnl}`); console.log(`🎯 Distance to SL: ${positionData.stopLossProximity.distancePercent}%`); try { // Run AI analysis to determine market reversal potential const analysis = await this.runAIAnalysisForDCA(positionData); if (analysis && analysis.recommendation === 'DCA_DOUBLE_DOWN') { console.log('🎯 AI DECISION: Market showing reversal signs - DOUBLING DOWN'); console.log(`πŸ“ˆ Confidence: ${analysis.confidence}%`); console.log(`πŸ’° DCA Amount: ${analysis.dcaAmount} SOL`); console.log(`🎯 New Average: $${analysis.newAveragePrice}`); // Execute DCA trade await this.executeDCATradeAction(analysis, positionData); } else if (analysis && analysis.recommendation === 'CLOSE_EARLY') { console.log('πŸ›‘ AI DECISION: No reversal signs - CLOSING EARLY to minimize loss'); console.log(`πŸ“‰ Confidence: ${analysis.confidence}%`); // Execute early close await this.executeEarlyCloseAction(positionData); } else { console.log('⏸️ AI DECISION: HOLD position - unclear signals'); console.log('⏰ Will re-analyze in 30 seconds'); } } catch (error) { console.error('❌ Emergency analysis failed:', error); console.log('⏰ Next check in 30 seconds due to high risk'); } } async runAIAnalysisForDCA(positionData) { console.log('🧠 Running AI DCA Analysis...'); try { // Get fresh market analysis const response = await fetch('http://localhost:3000/api/analysis-optimized', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ symbol: positionData.position.symbol.replace('-PERP', 'USD'), timeframes: ['5', '15', '1h'], layouts: ['ai'], analyze: true, dcaMode: true, // Special DCA analysis mode currentPosition: positionData.position }) }); if (!response.ok) { throw new Error(`Analysis failed: ${response.status}`); } const analysisData = await response.json(); const analysis = analysisData.analysis; if (!analysis) { console.log('❌ No analysis returned'); return null; } // Determine DCA strategy based on AI analysis const dcaDecision = this.evaluateDCAOpportunity(analysis, positionData); return dcaDecision; } catch (error) { console.error('❌ AI DCA analysis failed:', error); return null; } } evaluateDCAOpportunity(analysis, positionData) { const currentPrice = positionData.position.currentPrice; const entryPrice = positionData.position.entryPrice; const unrealizedPnl = positionData.position.unrealizedPnl; const confidence = analysis.confidence || 0; // Calculate price movement from entry const priceMovement = ((currentPrice - entryPrice) / entryPrice) * 100; const isLongPosition = positionData.position.side === 'long'; console.log(`πŸ“Š DCA Evaluation:`); console.log(` Price Movement: ${priceMovement.toFixed(2)}%`); console.log(` AI Confidence: ${confidence}%`); console.log(` Analysis: ${analysis.recommendation}`); // DCA Logic for LONG positions if (isLongPosition) { // Price has dropped significantly (good DCA opportunity) const hasDropped = priceMovement < -2; // 2%+ drop const aiSaysBuy = analysis.recommendation?.toLowerCase().includes('buy'); const highConfidence = confidence > 75; const oversoldSignals = analysis.technicalIndicators?.rsi < 35; // Oversold if (hasDropped && aiSaysBuy && highConfidence) { const dcaAmount = this.calculateDCAAmount(positionData); const newAveragePrice = this.calculateNewAveragePrice( positionData.position.size, entryPrice, dcaAmount, currentPrice ); return { recommendation: 'DCA_DOUBLE_DOWN', confidence: confidence, dcaAmount: dcaAmount, newAveragePrice: newAveragePrice, reasoning: `AI detects reversal: ${analysis.reasoning || 'Strong buy signal'}` }; } } // DCA Logic for SHORT positions if (!isLongPosition) { // Price has risen significantly (good DCA opportunity for shorts) const hasRisen = priceMovement > 2; // 2%+ rise const aiSaysSell = analysis.recommendation?.toLowerCase().includes('sell'); const highConfidence = confidence > 75; const overboughtSignals = analysis.technicalIndicators?.rsi > 65; // Overbought if (hasRisen && aiSaysSell && highConfidence) { const dcaAmount = this.calculateDCAAmount(positionData); const newAveragePrice = this.calculateNewAveragePrice( positionData.position.size, entryPrice, dcaAmount, currentPrice ); return { recommendation: 'DCA_DOUBLE_DOWN', confidence: confidence, dcaAmount: dcaAmount, newAveragePrice: newAveragePrice, reasoning: `AI detects short opportunity: ${analysis.reasoning || 'Strong sell signal'}` }; } } // If no DCA opportunity but low confidence, suggest early close if (confidence < 40 && Math.abs(unrealizedPnl) > 20) { return { recommendation: 'CLOSE_EARLY', confidence: 100 - confidence, // Inverse confidence for closing reasoning: 'Low AI confidence + significant loss suggests early exit' }; } return { recommendation: 'HOLD', confidence: confidence, reasoning: 'No clear DCA or exit signals' }; } calculateDCAAmount(positionData) { // Calculate safe DCA amount (max 50% of current position) const currentSize = positionData.position.size; const maxDCASize = currentSize * 0.5; // Max 50% of current position // Could also factor in available balance, but for now use conservative 50% return Math.min(maxDCASize, 2.0); // Cap at 2 SOL for safety } calculateNewAveragePrice(currentSize, currentEntryPrice, dcaAmount, dcaPrice) { const totalValue = (currentSize * currentEntryPrice) + (dcaAmount * dcaPrice); const totalSize = currentSize + dcaAmount; return totalValue / totalSize; } async executeDCATradeAction(analysis, positionData) { console.log('🎯 EXECUTING DCA TRADE...'); try { const tradeParams = { symbol: positionData.position.symbol, side: positionData.position.side === 'long' ? 'BUY' : 'SELL', amount: analysis.dcaAmount, orderType: 'MARKET', leverage: 10, // Use moderate leverage for DCA stopLoss: 1.0, takeProfit: 3.0, isExecution: true, dcaMode: true, analysis: analysis }; const response = await fetch('http://localhost:3000/api/trading/execute', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(tradeParams) }); const result = await response.json(); if (result.success) { console.log('βœ… DCA TRADE EXECUTED SUCCESSFULLY!'); console.log(`πŸ’° Added ${analysis.dcaAmount} SOL to position`); console.log(`πŸ“Š New Average Price: $${analysis.newAveragePrice.toFixed(4)}`); } else { console.error('❌ DCA trade failed:', result.error); } } catch (error) { console.error('❌ Error executing DCA trade:', error); } } async executeEarlyCloseAction(positionData) { console.log('πŸ›‘ EXECUTING EARLY CLOSE...'); try { const closeParams = { symbol: positionData.position.symbol, side: positionData.position.side === 'long' ? 'SELL' : 'BUY', amount: positionData.position.size, orderType: 'MARKET', isExecution: true, earlyClose: true, reason: 'Emergency early close due to low AI confidence' }; const response = await fetch('http://localhost:3000/api/trading/execute', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(closeParams) }); const result = await response.json(); if (result.success) { console.log('βœ… POSITION CLOSED EARLY'); console.log(`πŸ’° Final P&L: ${positionData.position.unrealizedPnl >= 0 ? '+' : ''}$${positionData.position.unrealizedPnl.toFixed(2)}`); } else { console.error('❌ Early close failed:', result.error); } } catch (error) { console.error('❌ Error executing early close:', error); } } async stop() { try { console.log('πŸ›‘ STOPPING POSITION-AWARE AUTOMATION...'); this.isRunning = false; this.stats.status = 'Stopped'; this.stats.positionMonitoringActive = false; console.log('βœ… AUTOMATION STATUS: isRunning =', this.isRunning); if (this.intervalId) { clearInterval(this.intervalId); this.intervalId = null; console.log('⏹️ Opportunity scanning stopped'); } if (this.positionCheckInterval) { clearInterval(this.positionCheckInterval); this.positionCheckInterval = null; console.log('⏹️ Position monitoring stopped'); } return { success: true, message: 'Position-aware automation stopped successfully' }; } catch (error) { console.error('Failed to stop position-aware automation:', error); return { success: false, message: 'Failed to stop automation: ' + error.message }; } } getStatus() { const baseStatus = { isActive: this.isRunning, 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: 'POSITION_AWARE', ...this.stats }; // Add descriptive status based on current mode if (this.isRunning) { if (this.stats.positionMonitoringActive) { baseStatus.detailedStatus = 'Monitoring active position for stop loss proximity'; baseStatus.nextAction = 'Position risk assessment and monitoring'; } else { baseStatus.detailedStatus = 'Scanning for trading opportunities'; baseStatus.nextAction = 'Entry signal analysis'; } } else { baseStatus.detailedStatus = 'Stopped - No monitoring active'; baseStatus.nextAction = 'Start automation to begin monitoring'; } return baseStatus; } } // Export singleton instance const positionAwareAutomation = new PositionAwareAutomation(); export { positionAwareAutomation };