import { promises as fs } from 'fs' import path from 'path' import OpenAI from 'openai' import { ScreenshotBatch } from './enhanced-screenshot-batch' export interface BatchAnalysisResult { symbol: string timeframes: string[] marketSentiment: 'BULLISH' | 'BEARISH' | 'NEUTRAL' overallRecommendation: 'BUY' | 'SELL' | 'HOLD' confidence: number multiTimeframeAnalysis: { [timeframe: string]: { sentiment: 'BULLISH' | 'BEARISH' | 'NEUTRAL' strength: number keyLevels: { support: number[] resistance: number[] } indicators: { rsi?: string macd?: string ema?: string vwap?: string obv?: string stochRsi?: string } } } consensus: { direction: 'BUY' | 'SELL' | 'HOLD' confidence: number reasoning: string conflictingSignals?: string[] } tradingSetup?: { entry: { price: number buffer?: string rationale: string } stopLoss: { price: number rationale: string } takeProfits: { tp1: { price: number description: string } tp2: { price: number description: string } } riskToReward: string timeframeRisk: { assessment: string leverageRecommendation: string } } } export class BatchAIAnalysisService { private openai: OpenAI constructor() { if (!process.env.OPENAI_API_KEY) { throw new Error('OPENAI_API_KEY environment variable is required') } this.openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }) } /** * Analyze multiple screenshots across different timeframes in a single AI call * This is much more efficient than individual calls */ async analyzeMultipleTimeframes(batches: ScreenshotBatch[]): Promise { console.log(`🤖 Starting batch AI analysis for ${batches.length} screenshots`) try { // Group batches by timeframe for organization const timeframeGroups = this.groupBatchesByTimeframe(batches) // Convert screenshots to base64 for OpenAI const imageMessages = await Promise.all( batches.map(async (batch) => { let imagePath: string if (path.isAbsolute(batch.filepath)) { imagePath = batch.filepath } else { const screenshotsDir = path.join(process.cwd(), 'screenshots') imagePath = path.join(screenshotsDir, batch.filepath) } const imageBuffer = await fs.readFile(imagePath) const base64Image = imageBuffer.toString('base64') return { type: "image_url" as const, image_url: { url: `data:image/png;base64,${base64Image}`, detail: "high" as const } } }) ) // Create comprehensive analysis prompt const prompt = this.createBatchAnalysisPrompt(batches, timeframeGroups) const messages = [ { role: "user" as const, content: [ { type: "text" as const, text: prompt }, ...imageMessages ] } ] console.log(`🤖 Sending ${batches.length} screenshots to OpenAI for comprehensive multi-timeframe analysis...`) const response = await this.openai.chat.completions.create({ model: "gpt-4o-mini", messages: messages, max_tokens: 3000, temperature: 0.1 }) const content = response.choices[0]?.message?.content if (!content) { throw new Error('No response from OpenAI') } console.log('🔍 Raw OpenAI response:', content.substring(0, 200) + '...') // Extract JSON from response const jsonMatch = content.match(/\{[\s\S]*\}/) if (!jsonMatch) { throw new Error('No JSON found in response') } const analysis = JSON.parse(jsonMatch[0]) as BatchAnalysisResult console.log('✅ Batch multi-timeframe analysis parsed successfully') return analysis } catch (error: any) { console.error('❌ Batch AI analysis failed:', error.message) console.error('Full error details:', error) throw error } } /** * Group screenshot batches by timeframe for better organization */ private groupBatchesByTimeframe(batches: ScreenshotBatch[]): { [timeframe: string]: ScreenshotBatch[] } { const groups: { [timeframe: string]: ScreenshotBatch[] } = {} for (const batch of batches) { if (!groups[batch.timeframe]) { groups[batch.timeframe] = [] } groups[batch.timeframe].push(batch) } return groups } /** * Create comprehensive prompt for multi-timeframe analysis */ private createBatchAnalysisPrompt(batches: ScreenshotBatch[], timeframeGroups: { [timeframe: string]: ScreenshotBatch[] }): string { const symbol = batches[0]?.symbol || 'Unknown' const timeframes = Object.keys(timeframeGroups).sort() const layoutInfo = this.getLayoutInfo(batches) return `You are a professional trading assistant analyzing multiple TradingView charts across different timeframes for ${symbol}. **ANALYSIS SCOPE:** - Symbol: ${symbol} - Timeframes: ${timeframes.join(', ')} - Layouts: ${layoutInfo} - Total Screenshots: ${batches.length} **MULTI-TIMEFRAME ANALYSIS FRAMEWORK:** **Higher Timeframes (4h, 1d)**: Determine overall trend direction and major structure **Medium Timeframes (1h, 2h)**: Identify swing setups and intermediate levels **Lower Timeframes (5m, 15m, 30m)**: Find precise entry points and scalping opportunities **TECHNICAL ANALYSIS INDICATORS:** **RSI (Relative Strength Index):** - Oversold (<30): Potential bounce/reversal opportunity - Overbought (>70): Potential rejection/correction - Divergences: Price vs RSI divergence indicates momentum shifts **MACD (Moving Average Convergence Divergence):** - Signal Line Cross: Momentum shift confirmation - Histogram: Momentum strength and direction - Zero Line: Trend direction confirmation **EMAs (Exponential Moving Averages):** - Price above EMAs: Bullish bias - Price below EMAs: Bearish bias - EMA crossovers: Trend change signals **VWAP (Volume Weighted Average Price):** - Price above VWAP: Bullish sentiment - Price below VWAP: Bearish sentiment - VWAP as dynamic support/resistance **OBV (On-Balance Volume):** - Rising OBV + Rising Price: Healthy uptrend - Falling OBV + Falling Price: Healthy downtrend - Divergences: Volume vs price momentum misalignment **Stochastic RSI:** - Oversold (below 20): Potential bounce - Overbought (above 80): Potential reversal - K/D line crossovers: Entry/exit signals **MULTI-TIMEFRAME CONSENSUS RULES:** 1. **Trend Alignment**: Higher timeframes determine bias, lower timeframes find entries 2. **Confluence**: Multiple indicators and timeframes agreeing increases confidence 3. **Divergence Detection**: Conflicting signals across timeframes (note these carefully) 4. **Risk Assessment**: Shorter timeframes = higher risk, longer timeframes = lower risk **PROVIDE COMPREHENSIVE JSON ANALYSIS:** { "symbol": "${symbol}", "timeframes": ${JSON.stringify(timeframes)}, "marketSentiment": "BULLISH|BEARISH|NEUTRAL", "overallRecommendation": "BUY|SELL|HOLD", "confidence": 85, "multiTimeframeAnalysis": { ${timeframes.map(tf => `"${tf}": { "sentiment": "BULLISH|BEARISH|NEUTRAL", "strength": 75, "keyLevels": { "support": [123.45, 120.00], "resistance": [130.00, 135.50] }, "indicators": { "rsi": "RSI analysis for ${tf}", "macd": "MACD analysis for ${tf}", "ema": "EMA analysis for ${tf}", "vwap": "VWAP analysis for ${tf}", "obv": "OBV analysis for ${tf}", "stochRsi": "Stoch RSI analysis for ${tf}" } }`).join(',\n ')} }, "consensus": { "direction": "BUY|SELL|HOLD", "confidence": 80, "reasoning": "Detailed explanation of why timeframes agree/disagree", "conflictingSignals": ["List any conflicting signals between timeframes"] }, "tradingSetup": { "entry": { "price": 125.50, "buffer": "±0.2%", "rationale": "Confluence of support and indicator signals" }, "stopLoss": { "price": 122.00, "rationale": "Below key support with structure break" }, "takeProfits": { "tp1": { "price": 130.00, "description": "First resistance confluence" }, "tp2": { "price": 135.50, "description": "Major resistance extension" } }, "riskToReward": "1:3.2", "timeframeRisk": { "assessment": "Medium risk - multiple timeframe alignment", "leverageRecommendation": "2-3x max for swing setup" } } } Analyze all provided screenshots and return ONLY the JSON response with comprehensive multi-timeframe analysis.` } /** * Get layout information from batches */ private getLayoutInfo(batches: ScreenshotBatch[]): string { const layouts = [...new Set(batches.map(b => b.layout))] const layoutDescriptions = layouts.map(layout => { switch (layout) { case 'ai': return 'AI Layout (RSI + EMAs + MACD)' case 'diy': return 'DIY Layout (Stochastic RSI + VWAP + OBV)' default: return `${layout} Layout` } }) return layoutDescriptions.join(' and ') } } export const batchAIAnalysisService = new BatchAIAnalysisService()