diff --git a/app/api/drift/consolidate-position/route.js b/app/api/drift/consolidate-position/route.js index b94902f..f749d2b 100644 --- a/app/api/drift/consolidate-position/route.js +++ b/app/api/drift/consolidate-position/route.js @@ -10,7 +10,7 @@ export async function POST(request) { console.log(`AI Analysis: ${analysis ? 'Provided - Using AI optimal levels' : 'Not provided - Using adaptive levels'}`); // Get current position data - const positionsResponse = await fetch('http://localhost:9001/api/drift/positions'); + const positionsResponse = await fetch('http://localhost:3000/api/drift/positions'); const positionsData = await positionsResponse.json(); if (!positionsData.success || !positionsData.positions.length) { diff --git a/app/api/drift/scale-position/route.js b/app/api/drift/scale-position/route.js index 80a1273..3d21183 100644 --- a/app/api/drift/scale-position/route.js +++ b/app/api/drift/scale-position/route.js @@ -29,7 +29,7 @@ export async function POST(request) { console.log(`πŸ’° Adding $${dcaAmount} to existing position`); // 1. Get current position - const positionResponse = await fetch(`${process.env.INTERNAL_API_URL || 'http://localhost:9001'}/api/drift/positions`); + const positionResponse = await fetch(`${process.env.INTERNAL_API_URL || 'http://localhost:3000'}/api/drift/positions`); const positionData = await positionResponse.json(); if (!positionData.success || positionData.positions.length === 0) { @@ -86,7 +86,7 @@ export async function POST(request) { // 5. Cancel existing stop loss and take profit orders console.log('🧹 Canceling existing SL/TP orders...'); try { - const ordersResponse = await fetch(`${process.env.INTERNAL_API_URL || 'http://localhost:9001'}/api/drift/orders`); + const ordersResponse = await fetch(`${process.env.INTERNAL_API_URL || 'http://localhost:3000'}/api/drift/orders`); const ordersData = await ordersResponse.json(); if (ordersData.success && ordersData.orders.length > 0) { diff --git a/lib/position-consolidator.js b/lib/position-consolidator.js index 78c3533..b3dc4fd 100644 --- a/lib/position-consolidator.js +++ b/lib/position-consolidator.js @@ -243,7 +243,7 @@ class PositionConsolidator { */ static async cancelAllOrders() { try { - const response = await fetch('http://localhost:9001/api/drift/cancel-all-orders', { + const response = await fetch('http://localhost:3000/api/drift/cancel-all-orders', { method: 'POST', headers: { 'Content-Type': 'application/json' } }); @@ -262,7 +262,7 @@ class PositionConsolidator { */ static async placeConsolidatedOrder(orderParams) { try { - const response = await fetch('http://localhost:9001/api/drift/place-order', { + const response = await fetch('http://localhost:3000/api/drift/place-order', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ @@ -297,7 +297,7 @@ class PositionConsolidator { */ static async getCurrentPosition() { try { - const response = await fetch('http://localhost:9001/api/drift/positions'); + const response = await fetch('http://localhost:3000/api/drift/positions'); const result = await response.json(); if (result.success && result.positions.length > 0) { diff --git a/lib/simple-automation.js b/lib/simple-automation.js index ef87f14..30aa2ac 100644 --- a/lib/simple-automation.js +++ b/lib/simple-automation.js @@ -123,13 +123,15 @@ class SimpleAutomation { console.log('MODE: ' + (config.mode || 'SIMULATION')); // Start dynamic monitoring cycle with risk-based intervals - this.currentInterval = 10 * 60 * 1000; // Start with 10 minutes + console.log('πŸš€ STARTING: Dynamic monitoring with scalping optimization'); + this.currentInterval = 30 * 1000; // Start with 30 seconds for immediate analysis this.startDynamicMonitoring(); - // First cycle after 30 seconds + // First cycle after 5 seconds (immediate for scalping) setTimeout(() => { + console.log('πŸ”₯ IMMEDIATE CYCLE: Starting first analysis cycle'); this.runCycle(); - }, 30000); + }, 5000); return { success: true, @@ -189,26 +191,50 @@ class SimpleAutomation { this.intervalId = setTimeout(runMonitoringCycle, this.currentInterval); } - // Determine next interval based on risk level + // Determine next interval based on risk level and position status async getNextInterval() { try { - // Check position monitor for current risk level - const baseUrl = process.env.INTERNAL_API_URL || 'http://localhost:9001'; - const response = await fetch(`${baseUrl}/api/automation/position-monitor`); if (response.ok) { + // 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(); - // Risk-based multipliers for fine-tuning + // 🚨 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 (5minβ†’2.5min for scalping) + riskMultiplier = 0.5; // 50% faster when critical break; case 'HIGH': - riskMultiplier = 0.7; // 30% faster when high risk (10minβ†’7min for scalping) + riskMultiplier = 0.7; // 30% faster when high risk break; case 'MEDIUM': riskMultiplier = 1.0; // Normal speed @@ -218,18 +244,19 @@ class SimpleAutomation { break; case 'NONE': default: - riskMultiplier = 1.0; // Normal speed when no position + // 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} | Strategy: ${this.detectStrategy()} | Interval: ${finalMinutes} min`); + 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 ${intervalMinutes} minutes`); + console.log(`πŸ“Š DYNAMIC INTERVAL: Risk level ${riskLevel} β†’ Next analysis in ${finalMinutes} minutes`); this.currentInterval = intervalMs; return intervalMs; @@ -291,66 +318,139 @@ class SimpleAutomation { } async performAnalysis() { - console.log(`πŸ“Š TRUE PARALLEL ANALYSIS: Starting simultaneous analysis for ${this.config.selectedTimeframes.length} timeframes...`); - console.log(`πŸš€ This will capture ${this.config.selectedTimeframes.length * 2} screenshots in parallel (${this.config.selectedTimeframes.length} timeframes Γ— 2 layouts)`); + console.log(`πŸ“Š ANALYSIS CYCLE: Starting analysis for ${this.config.selectedTimeframes.length} timeframes...`); try { - // Use correct internal port for server-side API calls - const baseUrl = process.env.INTERNAL_API_URL || 'http://localhost:9001'; - 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, // All timeframes at once! - layouts: ['ai', 'diy'], - analyze: true - }) - }); - - if (!response.ok) { - console.warn(`⚠️ BATCH API ERROR: ${response.status}, falling back to sequential...`); - return this.performSequentialAnalysis(); - } - - const result = await response.json(); + // 🚨 STEP 1: Check position monitor FIRST to determine market status + const baseUrl = process.env.INTERNAL_API_URL || 'http://localhost:3000'; - if (result.success && result.analysis) { - // Reset consecutive error counter on success - this.stats.consecutiveErrors = 0; + 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`); - console.log(`βœ… PARALLEL ANALYSIS COMPLETE: ${result.totalScreenshots} screenshots captured`); - console.log(`πŸ“Š COMBINED Recommendation: ${result.analysis.recommendation}`); - console.log(`🎯 COMBINED Confidence: ${result.analysis.confidence}%`); - console.log(`⏰ Timeframes analyzed: ${result.timeframes.join(', ')}`); - - // Check if we should execute a trade based on combined analysis - if (this.shouldExecuteTrade(result.analysis)) { - console.log('πŸ’° TRADE SIGNAL: Executing trade...'); - await this.executeTrade(result.analysis); + 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.log('πŸ“ˆ SIGNAL: Combined analysis complete, no trade executed'); + 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'); + + // Clean up any remaining orders first + if (activeOrders > 0) { + console.log('🧹 CLEANUP: Canceling remaining orders before new entry...'); + try { + const cleanupResponse = await fetch(`${baseUrl}/api/drift/cleanup-orders`, { + method: 'POST' + }); + if (cleanupResponse.ok) { + const cleanupResult = await cleanupResponse.json(); + console.log(`βœ… CLEANUP COMPLETE: ${cleanupResult.summary?.totalCanceled || 0} orders canceled`); + } else { + console.warn(`⚠️ Cleanup API error: ${cleanupResponse.status}`); + } + } catch (cleanupError) { + console.warn('⚠️ Order cleanup failed:', cleanupError.message); + } } - return; + // For scalping, if no position, we ALWAYS analyze for immediate re-entry + if (recommendation === 'START_TRADING' || !hasPosition) { + console.log('πŸš€ IMMEDIATE ANALYSIS: Market is clear, scanning for entry opportunities...'); + // Continue with analysis below + } } else { - console.warn('⚠️ BATCH ANALYSIS: No valid data, falling back to sequential...'); + 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 (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) { - // Track network errors - this.stats.networkErrors++; + // Main try-catch for the entire performAnalysis method this.stats.consecutiveErrors++; + console.error('❌ ANALYSIS ERROR:', error.message); - console.error(`❌ PARALLEL ANALYSIS FAILED (Network Error #${this.stats.networkErrors}):`, error.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.`); + // Fallback to sequential if all else fails + try { + return this.performSequentialAnalysis(); + } catch (fallbackError) { + console.error('❌ SEQUENTIAL ANALYSIS ALSO FAILED:', fallbackError.message); } - - console.log(`πŸ”„ FALLBACK: Using sequential analysis...`); - return this.performSequentialAnalysis(); } } @@ -366,7 +466,7 @@ class SimpleAutomation { console.log(`πŸ“Š ANALYZING: ${timeframe} timeframe...`); // Use the enhanced screenshot API for each timeframe - const baseUrl = process.env.INTERNAL_API_URL || 'http://localhost:9001'; + 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' }, @@ -457,28 +557,63 @@ class SimpleAutomation { } shouldExecuteTrade(analysis) { - // Always allow trade execution - the useRealDEX flag determines if it's real or simulated - console.log(`οΏ½ TRADE MODE: ${this.config.mode || 'SIMULATION'} - Trading ${this.config.enableTrading ? 'ENABLED' : 'DISABLED'}`); + console.log(`🎯 TRADE MODE: ${this.config.mode || 'SIMULATION'} - Trading ${this.config.enableTrading ? 'ENABLED' : 'DISABLED'}`); const recommendation = analysis.recommendation?.toLowerCase() || ''; const confidence = analysis.confidence || 0; - // Strategy-specific confidence requirements - let minConfidence = 75; - if (this.config.selectedTimeframes?.includes('5') || this.config.selectedTimeframes?.includes('15')) { - minConfidence = 80; // Higher confidence for scalping + // 🚨 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'); + } + + // 🎯 AGGRESSIVE SCALPING CONFIDENCE when NO POSITION + let minConfidence = 75; // Default confidence + + if (!hasActivePosition) { + // NO POSITION = Lower confidence threshold for faster re-entry + if (this.config.selectedTimeframes?.includes('5m')) { + minConfidence = 65; // Very aggressive for 5m scalping + console.log('πŸƒβ€β™‚οΈ SCALPING MODE: Using aggressive 65% confidence (no position)'); + } else if (this.config.selectedTimeframes?.includes('15m')) { + minConfidence = 70; // Aggressive for 15m scalping + console.log('⚑ SCALPING MODE: Using aggressive 70% confidence (no position)'); + } 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'); + const isClearDirection = recommendation.includes('buy') || recommendation.includes('sell') || + recommendation.includes('long') || recommendation.includes('short'); - console.log('🎯 TRADE DECISION: ' + recommendation + ' (' + confidence + '%) - Min: ' + minConfidence + '%'); + console.log(`🎯 TRADE DECISION: ${recommendation} (${confidence}%) vs Required: ${minConfidence}%`); + console.log(`βœ… Will Execute: ${isHighConfidence && isClearDirection ? 'YES' : 'NO'}`); // 🧠 RECORD AI DECISION FOR LEARNING this.recordAIDecisionForLearning(analysis, { recommendation, confidence, minConfidenceRequired: minConfidence, + hasActivePosition, willExecute: isHighConfidence && isClearDirection }); @@ -488,11 +623,12 @@ class SimpleAutomation { recommendation: analysis.recommendation || 'HOLD', confidence: confidence, minConfidenceRequired: minConfidence, + hasActivePosition: hasActivePosition, reasoning: analysis.reasoning || analysis.summary || 'No detailed reasoning available', - executed: false, // Will be updated if trade is executed + executed: false, executionDetails: null, executionError: null, - learningRecorded: true // Indicate learning system recorded this + learningRecorded: true }; return isHighConfidence && isClearDirection; @@ -504,7 +640,7 @@ class SimpleAutomation { 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:9001'; + const apiBaseUrl = process.env.INTERNAL_API_URL || 'http://localhost:3000'; const existingPositions = await fetch(`${apiBaseUrl}/api/drift/positions`); const positionsData = await existingPositions.json(); @@ -623,9 +759,8 @@ class SimpleAutomation { let availableBalance = 49; // fallback try { - const baseUrl = process.env.INTERNAL_API_URL || 'http://localhost:9001'; - console.log('πŸ”§ DEBUG: Fetching balance from:', baseUrl); - const balanceResponse = await fetch(`${baseUrl}/api/drift/balance`); + 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; @@ -680,8 +815,7 @@ class SimpleAutomation { console.log('πŸ“Š TRADE PAYLOAD:', tradePayload); - const baseUrl = process.env.INTERNAL_API_URL || 'http://localhost:9001'; - const response = await fetch(`${baseUrl}/api/trading/execute-drift`, { + const response = await fetch(`${apiBaseUrl}/api/trading/execute-drift`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(tradePayload) @@ -743,7 +877,7 @@ class SimpleAutomation { 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:9001'; + 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' },