import { superiorScreenshotService } from './superior-screenshot-service' import { aiAnalysisService } from './ai-analysis' import { automatedCleanupService } from './automated-cleanup-service' import aggressiveCleanup from './aggressive-cleanup' export interface TradingConfig { symbol: string timeframes: string[] layouts: string[] intervalMs: number // How often to run analysis maxCycles?: number // Optional limit for testing } export class AutoTradingService { private isRunning = false private currentCycle = 0 private config: TradingConfig | null = null async start(config: TradingConfig) { if (this.isRunning) { console.log('āš ļø Trading service already running') return } this.isRunning = true this.config = config this.currentCycle = 0 console.log('šŸš€ Starting automated trading service with robust cleanup...') console.log('šŸ”§ Config:', config) // Start background cleanup service automatedCleanupService.start(30000) // Every 30 seconds // Start aggressive cleanup system aggressiveCleanup.startPeriodicCleanup() try { while (this.isRunning && (!config.maxCycles || this.currentCycle < config.maxCycles)) { this.currentCycle++ console.log(`\nšŸ”„ === TRADING CYCLE ${this.currentCycle} ===`) await this.runTradingCycle(config) if (this.isRunning) { console.log(`ā³ Waiting ${config.intervalMs/1000} seconds until next cycle...`) await new Promise(resolve => setTimeout(resolve, config.intervalMs)) } } if (config.maxCycles && this.currentCycle >= config.maxCycles) { console.log(`āœ… Completed ${this.currentCycle} cycles (reached max limit)`) } } catch (error) { console.error('āŒ Trading service error:', error) } finally { await this.stop() } } async stop() { console.log('šŸ›‘ Stopping automated trading service...') this.isRunning = false // Stop cleanup services automatedCleanupService.stop() aggressiveCleanup.stop() // Force cleanup all browser sessions try { await superiorScreenshotService.cleanup() await aggressiveCleanup.forceCleanup() console.log('āœ… Trading service stopped and cleaned up') } catch (cleanupError) { console.error('āŒ Error during final cleanup:', cleanupError) } } private async runTradingCycle(config: TradingConfig): Promise { console.log(`šŸ”„ Running trading cycle ${this.currentCycle}...`) try { console.log(`\nšŸ“Š Processing ${config.symbol} with ${config.timeframes.length} timeframes...`) // Determine trading strategy based on timeframes for intelligent parallel capture const timeframeSet = new Set(config.timeframes) let preset: 'scalp' | 'day-trading' | 'swing-trading' | 'custom' = 'custom' // Detect strategy based on timeframe patterns if (timeframeSet.has('5') && timeframeSet.has('15') && timeframeSet.has('30') && config.timeframes.length === 3) { preset = 'scalp' console.log('šŸŽÆ Detected: SCALP trading strategy (5m, 15m, 30m)') } else if (timeframeSet.has('60') && timeframeSet.has('120') && config.timeframes.length === 2) { preset = 'day-trading' console.log('šŸŽÆ Detected: DAY TRADING strategy (1h, 2h)') } else if (timeframeSet.has('240') && timeframeSet.has('1D') && config.timeframes.length === 2) { preset = 'swing-trading' console.log('šŸŽÆ Detected: SWING TRADING strategy (4h, 1d)') } else { preset = 'custom' console.log('šŸŽÆ Using: CUSTOM timeframe configuration') } // Capture screenshots using superior parallel technique let screenshots: any[] = [] let allResults: any[] = [] if (preset === 'custom') { // Custom timeframes - use parallel capture with custom preset console.log('šŸš€ Using superior parallel capture with custom timeframes...') allResults = await superiorScreenshotService.captureParallel({ symbol: config.symbol, preset: 'custom', timeframes: config.timeframes, layouts: config.layouts, analyze: false }) } else { // Standard preset - use optimized preset method console.log(`šŸš€ Using superior parallel capture with ${preset} preset...`) allResults = await superiorScreenshotService.captureParallel({ symbol: config.symbol, preset: preset, layouts: config.layouts, analyze: false }) } // Extract successful screenshots for analysis screenshots = allResults .filter(result => result.success && result.screenshots) .flatMap(result => result.screenshots || []) if (screenshots.length > 0) { console.log(`āœ… Superior parallel capture completed: ${screenshots.length} screenshots`) // Process results by timeframe for detailed analysis for (const result of allResults) { if (!result.success) { console.error(`āŒ Failed to capture ${result.timeframeName}: ${result.error}`) continue } if (!result.screenshots || result.screenshots.length === 0) { console.warn(`āš ļø No screenshots for ${result.timeframeName}`) continue } try { console.log(`\nšŸ¤– Analyzing ${result.timeframeName} (${result.screenshots.length} screenshots)...`) let analysis = null if (result.screenshots.length === 1) { analysis = await aiAnalysisService.analyzeScreenshot(result.screenshots[0]) } else if (result.screenshots.length > 1) { analysis = await aiAnalysisService.analyzeMultipleScreenshots(result.screenshots) } if (analysis) { console.log(`āœ… Analysis completed for ${result.timeframeName}`) console.log(`šŸ“ˆ Sentiment: ${analysis.marketSentiment || 'Unknown'}`) console.log(`šŸŽÆ Recommendation: ${analysis.recommendation}, Confidence: ${analysis.confidence}%`) // Process trading logic based on analysis await this.processAnalysisForTrading(analysis, config.symbol, result.timeframeName) } else { console.warn(`āš ļø No analysis returned for ${result.timeframeName}`) } } catch (analysisError) { console.error(`āŒ Analysis failed for ${result.timeframeName}:`, analysisError) } } } else { console.error(`āŒ No screenshots captured using superior parallel technique`) } } catch (error) { console.error(`āŒ Error in trading cycle:`, error) } console.log(`āœ… Trading cycle ${this.currentCycle} completed`) // Run post-cycle cleanup to ensure no browser processes are left running try { await aggressiveCleanup.runPostAnalysisCleanup() } catch (cleanupError) { console.error('āŒ Error in post-cycle cleanup:', cleanupError) } } private async processAnalysisForTrading(analysis: any, symbol: string, timeframe: string): Promise { try { console.log(`šŸŽÆ Processing trading analysis for ${symbol} ${timeframe}...`) // Extract key trading signals from analysis const sentiment = analysis.marketSentiment const confidence = analysis.confidence || 0 const recommendation = analysis.recommendation console.log(`šŸ“Š Sentiment: ${sentiment}, Recommendation: ${recommendation}, Confidence: ${confidence}%`) if (analysis.keyLevels) { console.log(`šŸ“ˆ Support levels: ${analysis.keyLevels.support.join(', ')}`) console.log(`šŸ“‰ Resistance levels: ${analysis.keyLevels.resistance.join(', ')}`) } // Trading decision logic if (confidence >= 70) { if (sentiment === 'BULLISH' && recommendation === 'BUY') { console.log('🟢 HIGH CONFIDENCE BULLISH - Consider long position') // await this.executeLongTrade(symbol, timeframe, analysis) } else if (sentiment === 'BEARISH' && recommendation === 'SELL') { console.log('šŸ”“ HIGH CONFIDENCE BEARISH - Consider short position') // await this.executeShortTrade(symbol, timeframe, analysis) } } else if (confidence >= 50) { console.log('🟔 MODERATE CONFIDENCE - Monitor for confirmation') } else { console.log('⚪ LOW CONFIDENCE - Hold current positions') } } catch (error) { console.error('āŒ Error processing trading analysis:', error) } } // Example trading execution methods (implement with your preferred exchange) private async executeLongTrade(symbol: string, timeframe: string, analysis: any): Promise { console.log(`🟢 Executing LONG trade for ${symbol} based on ${timeframe} analysis`) // Implement actual trading logic here // This could use Drift Protocol, Jupiter DEX, or other trading interfaces } private async executeShortTrade(symbol: string, timeframe: string, analysis: any): Promise { console.log(`šŸ”“ Executing SHORT trade for ${symbol} based on ${timeframe} analysis`) // Implement actual trading logic here } // Status methods getStatus() { return { isRunning: this.isRunning, currentCycle: this.currentCycle, config: this.config } } getCurrentCycle(): number { return this.currentCycle } isServiceRunning(): boolean { return this.isRunning } } // Example usage configurations export const TRADING_CONFIGS = { // Scalping configuration - frequent analysis of short timeframes scalping: { symbol: 'SOLUSD', timeframes: ['5m', '15m', '30m'], // Updated to match frontend: 5m, 15m, 30m layouts: ['ai', 'diy'], intervalMs: 5 * 60 * 1000, // Every 5 minutes maxCycles: 100 // Limit for testing }, // Day trading configuration - moderate frequency on intraday timeframes dayTrading: { symbol: 'SOLUSD', timeframes: ['1h', '2h'], // Updated to match frontend: 1h, 2h layouts: ['ai', 'diy'], intervalMs: 30 * 60 * 1000, // Every 30 minutes maxCycles: 50 // Limit for testing }, // Swing trading configuration - less frequent analysis of longer timeframes swingTrading: { symbol: 'SOLUSD', timeframes: ['4h', '1d'], // Matches frontend: 4h, 1d layouts: ['ai', 'diy'], intervalMs: 2 * 60 * 60 * 1000, // Every 2 hours maxCycles: 24 // Limit for testing } } // Singleton instance export const autoTradingService = new AutoTradingService() // Example startup function export async function startTradingBot(configName: keyof typeof TRADING_CONFIGS = 'dayTrading') { const config = TRADING_CONFIGS[configName] if (!config) { throw new Error(`Unknown trading configuration: ${configName}`) } console.log(`šŸš€ Starting trading bot with ${configName} configuration`) await autoTradingService.start(config) } // Graceful shutdown export async function stopTradingBot() { console.log('šŸ›‘ Stopping trading bot...') await autoTradingService.stop() }