MAJOR ENHANCEMENT: Transform basic AI analysis into professional trading desk precision - Execution zones (low/high/optimal) instead of single entry prices - Slippage buffer calculations with exact values - Detailed indicator roadmap (RSI, MACD, VWAP, OBV expectations at entry/TP1/TP2) - Leverage guidance based on timeframe (5m=10x+, 1H=3-5x, 4H+=1-3x) - Complete journal templates pre-filled with trade data - Scenario management (invalidation rules, alternatives, counter-trends) - Psychology coaching reminders and discipline notes - Risk-to-reward calculations with exact reasoning - Enhanced AnalysisResult interface with 8 new professional fields - Single screenshot analysis now uses trading desk precision prompts - Multiple screenshot analysis includes cross-layout consensus validation - Response parsing updated to handle all new professional fields - Backward compatibility maintained for existing integrations - No vague recommendations - exact levels with rationale - Confirmation triggers specify exact signals to wait for - Indicator expectations detailed for each target level - Alternative scenarios planned (tighter stops, scaled entries) - Position sizing recommendations based on timeframe risk - Professional trading language throughout - Interface enhancements complete - Ready for real-world testing via automation interface - Expected to transform user experience from basic TA to professional setup Based on user example analysis showing professional trading desk precision. Implements all requested improvements for actionable, specific trading guidance.
1068 lines
38 KiB
TypeScript
1068 lines
38 KiB
TypeScript
import OpenAI from 'openai'
|
|
import fs from 'fs/promises'
|
|
import path from 'path'
|
|
import { enhancedScreenshotService, ScreenshotConfig } from './enhanced-screenshot'
|
|
import { TradingViewCredentials } from './tradingview-automation'
|
|
import { progressTracker } from './progress-tracker'
|
|
|
|
const openai = new OpenAI({
|
|
apiKey: process.env.OPENAI_API_KEY,
|
|
})
|
|
|
|
export interface AnalysisResult {
|
|
summary: string
|
|
marketSentiment: 'BULLISH' | 'BEARISH' | 'NEUTRAL'
|
|
keyLevels: {
|
|
support: number[]
|
|
resistance: number[]
|
|
}
|
|
recommendation: 'BUY' | 'SELL' | 'HOLD'
|
|
confidence: number // 0-100
|
|
reasoning: string
|
|
// Enhanced trading analysis (optional)
|
|
entry?: {
|
|
price: number
|
|
buffer?: string
|
|
rationale: string
|
|
// Professional execution zone
|
|
zone?: {
|
|
low: number
|
|
high: number
|
|
optimal: number
|
|
}
|
|
slippageBuffer?: number
|
|
executionInstructions?: string
|
|
}
|
|
stopLoss?: {
|
|
price: number
|
|
rationale: string
|
|
}
|
|
takeProfits?: {
|
|
tp1?: {
|
|
price: number
|
|
description: string
|
|
rsiExpectation?: string
|
|
obvExpectation?: string
|
|
}
|
|
tp2?: {
|
|
price: number
|
|
description: string
|
|
rsiExpectation?: string
|
|
obvExpectation?: string
|
|
}
|
|
}
|
|
riskToReward?: string
|
|
confirmationTrigger?: string
|
|
// Professional Trading Desk Features
|
|
leverageGuidance?: {
|
|
timeframe: string
|
|
suggestedLeverage: string
|
|
positionSizePercent: string
|
|
reasoning: string
|
|
riskLevel: 'CONSERVATIVE' | 'MODERATE' | 'AGGRESSIVE'
|
|
}
|
|
indicatorRoadmap?: {
|
|
rsi?: {
|
|
atEntry: string
|
|
atTP1: string
|
|
atTP2?: string
|
|
invalidation: string
|
|
warningSignals: string
|
|
}
|
|
obv?: {
|
|
atEntry: string
|
|
atTP1: string
|
|
atTP2?: string
|
|
invalidation: string
|
|
warningSignals: string
|
|
}
|
|
vwap?: {
|
|
atEntry: string
|
|
invalidation: string
|
|
confirmationSignal: string
|
|
}
|
|
macd?: {
|
|
atEntry: string
|
|
expectedBehavior: string
|
|
invalidation: string
|
|
}
|
|
}
|
|
journalTemplate?: {
|
|
preFilledData: {
|
|
asset: string
|
|
entry: number
|
|
stopLoss: number
|
|
tp1: number
|
|
tp2?: number
|
|
riskReward: string
|
|
setupType: string
|
|
}
|
|
executionTracking: {
|
|
confirmationReceived: string
|
|
slippageExpected: string
|
|
emotionalState: string
|
|
executionNotes: string
|
|
}
|
|
postTradeAnalysis: {
|
|
didFollowPlan: string
|
|
lessonsLearned: string
|
|
nextTimeImprovement: string
|
|
}
|
|
}
|
|
scenarioManagement?: {
|
|
invalidation: {
|
|
priceLevel: number
|
|
reasoning: string
|
|
immediateAction: string
|
|
nextOpportunity?: string
|
|
}
|
|
alternatives: {
|
|
tighterStopOption?: string
|
|
scaledEntryOption?: string
|
|
counterTrendSetup?: string
|
|
betterRiskReward?: string
|
|
}
|
|
livePositionGuidance?: {
|
|
currentSituation?: string
|
|
immediateRisk?: string
|
|
optimalAction?: string
|
|
emergencyExit?: string
|
|
}
|
|
}
|
|
psychologyCoaching?: {
|
|
mindsetReminder: string
|
|
emotionalCheck: string
|
|
disciplineNote: string
|
|
riskManagementReminder: string
|
|
}
|
|
// AI-optimized risk management
|
|
optimalRiskManagement?: {
|
|
stopLossPercent: number // AI-recommended stop loss percentage
|
|
takeProfitPercent: number // AI-recommended take profit percentage
|
|
riskRewardRatio: number // Expected risk/reward ratio
|
|
reasoning: string // Why these percentages are optimal
|
|
marketVolatility: 'LOW' | 'MEDIUM' | 'HIGH' // Current volatility assessment
|
|
timeHorizon: 'SCALP' | 'INTRADAY' | 'SWING' // Expected trade duration
|
|
}
|
|
indicatorAnalysis?: {
|
|
rsi?: string
|
|
vwap?: string
|
|
obv?: string
|
|
macd?: string
|
|
crossLayoutConsensus?: string
|
|
}
|
|
layoutComparison?: {
|
|
aiLayout?: string
|
|
diyLayout?: string
|
|
consensus?: string
|
|
divergences?: string
|
|
}
|
|
timeframeRisk?: {
|
|
assessment?: string
|
|
positionSize?: string
|
|
leverageRecommendation?: string
|
|
}
|
|
alternatives?: {
|
|
tigherStopOption?: string
|
|
scaledEntry?: string
|
|
invalidationScenario?: string
|
|
}
|
|
}
|
|
|
|
export class AIAnalysisService {
|
|
private lastApiCall: number = 0
|
|
async analyzeScreenshot(filenameOrPath: string): Promise<AnalysisResult | null> {
|
|
try {
|
|
let imagePath: string
|
|
|
|
// Check if it's already a full path or just a filename
|
|
if (path.isAbsolute(filenameOrPath)) {
|
|
// It's already a full path
|
|
imagePath = filenameOrPath
|
|
} else {
|
|
// It's just a filename, construct the full path
|
|
const screenshotsDir = path.join(process.cwd(), 'screenshots')
|
|
imagePath = path.join(screenshotsDir, filenameOrPath)
|
|
}
|
|
|
|
// Read image file
|
|
const imageBuffer = await fs.readFile(imagePath)
|
|
const base64Image = imageBuffer.toString('base64')
|
|
|
|
const prompt = `You are now a professional trading assistant. You behave with the precision and decisiveness of a top proprietary desk trader. No vagueness, no fluff.
|
|
|
|
**WHEN GIVING A TRADE SETUP:**
|
|
Be 100% SPECIFIC. Provide:
|
|
|
|
1. **TIMEFRAME RISK ASSESSMENT**:
|
|
- Lower timeframes = higher risk, higher leverage (5min scalp: 10x+ leverage, tight stops)
|
|
- Higher timeframes = lower risk, lower leverage (4H: 2-3x leverage, wider stops)
|
|
- Position sizing: Less money on lower timeframes, more on higher timeframes
|
|
|
|
**TECHNICAL ANALYSIS FUNDAMENTALS:**
|
|
|
|
**RSI (Relative Strength Index):**
|
|
- Measures momentum on 0-100 scale
|
|
- OVERBOUGHT: Above 70 (potential sell signal)
|
|
- OVERSOLD: Below 30 (potential buy signal)
|
|
- NEUTRAL: 30-70 range
|
|
- ⚠️ CRITICAL: Read visual line position, not numerical value when they conflict
|
|
|
|
**MACD (Moving Average Convergence Divergence):**
|
|
- BULLISH CROSSOVER: MACD line crosses ABOVE signal line
|
|
- BEARISH CROSSOVER: MACD line crosses BELOW signal line
|
|
- HISTOGRAM: Green bars = bullish momentum, Red bars = bearish momentum
|
|
- ZERO LINE: Above = bullish trend, Below = bearish trend
|
|
|
|
**EMAs (Exponential Moving Averages):**
|
|
- EMA 9 (Yellow): Short-term trend
|
|
- EMA 20 (Orange): Medium-term trend
|
|
- EMA 50 (Blue): Intermediate trend
|
|
- EMA 200 (Red): Long-term trend
|
|
- BULLISH STACK: 9 > 20 > 50 > 200
|
|
- BEARISH STACK: 9 < 20 < 50 < 200
|
|
|
|
**Stochastic RSI:**
|
|
- OVERBOUGHT: Above 80
|
|
- OVERSOLD: Below 20
|
|
- BULLISH SIGNAL: %K crosses above %D in oversold territory
|
|
- BEARISH SIGNAL: %K crosses below %D in overbought territory
|
|
|
|
**VWAP (Volume Weighted Average Price):**
|
|
- Above VWAP = Bullish sentiment
|
|
- Below VWAP = Bearish sentiment
|
|
- RECLAIM: Price moves back above VWAP (bullish)
|
|
- REJECTION: Price fails at VWAP (bearish)
|
|
|
|
**OBV (On-Balance Volume):**
|
|
- Rising OBV = Volume supporting upward price movement
|
|
- Falling OBV = Volume supporting downward price movement
|
|
- DIVERGENCE: OBV direction differs from price (warning signal)
|
|
|
|
**LAYOUT IDENTIFICATION:**
|
|
|
|
**AI Layout (RSI + MACD + EMAs):**
|
|
- TOP: RSI indicator (14-period momentum oscillator)
|
|
- MIDDLE: EMAs (9,20,50,200) + ATR Bands + SVP
|
|
- BOTTOM: MACD indicator with histogram
|
|
- Focus: Momentum + Trend Analysis
|
|
|
|
**DIY Layout (Stochastic RSI + VWAP + OBV):**
|
|
- TOP: Stochastic RSI (more sensitive momentum)
|
|
- MIDDLE: VWAP + Smart Money Concepts
|
|
- BOTTOM: OBV (volume flow analysis)
|
|
- Focus: Volume + Institutional Flow Analysis
|
|
|
|
**PROFESSIONAL TRADING REQUIREMENTS:**
|
|
|
|
2. **ENTRY**
|
|
- Exact price level with execution zone (high/low/optimal)
|
|
- Slippage buffer (±0.25, ±0.50, etc.)
|
|
- Rationale: e.g., "Rejection from 15 EMA + VWAP confluence near intraday supply"
|
|
- Execution instructions: What to wait for before entering
|
|
|
|
3. **STOP-LOSS (SL)**
|
|
- Exact level (not arbitrary)
|
|
- Explain *why* it's there: "Above VWAP + failed breakout zone"
|
|
|
|
4. **TAKE PROFITS**
|
|
- TP1: Immediate structure (ex: previous low at $149.20)
|
|
- TP2: Extended target if momentum continues (e.g., $148.00)
|
|
- Mention **expected RSI/OBV behavior** at each TP zone
|
|
|
|
5. **RISK-TO-REWARD**
|
|
- Show R:R. Ex: "1:2.5 — Risking $X to potentially gain $Y"
|
|
|
|
6. **CONFIRMATION TRIGGER**
|
|
- Exact signal to wait for: e.g., "Bearish engulfing candle on rejection from VWAP zone"
|
|
- OBV: "Must be making lower highs + dropping below 30min average"
|
|
- RSI: "Should remain under 50 on rejection. Overbought ≥70 = wait"
|
|
|
|
7. **INDICATOR ROADMAP** - tell me:
|
|
- **RSI**: If RSI crosses above 70 while price is under resistance → *wait*
|
|
- **VWAP**: If price retakes VWAP with bullish momentum → *consider invalidation*
|
|
- **OBV**: If OBV starts climbing while price stays flat → *early exit or reconsider bias*
|
|
- **MACD**: Expected behavior at entry and targets
|
|
|
|
8. **ALTERNATIVES**
|
|
- If SL is far, offer tighter SL alternative or scaled entry near next level
|
|
- Suggest re-entry if original setup invalidates but price reaches better location
|
|
- Counter-trend opportunities if main setup fails
|
|
|
|
9. **LEVERAGE & POSITION SIZING**
|
|
- Based on timeframe: 5m = 10x+, 1H = 3-5x, 4H+ = 1-3x
|
|
- Position size percentage recommendation
|
|
- Risk level assessment (CONSERVATIVE/MODERATE/AGGRESSIVE)
|
|
|
|
10. **PSYCHOLOGY COACHING**
|
|
- Give firm reminders when emotions cloud judgment
|
|
- Reframe mindset if revenge trading, fearful, or hesitant to execute
|
|
- Discipline notes and risk management reminders
|
|
|
|
11. **JOURNAL TEMPLATE**
|
|
- Pre-filled trade data ready for journaling
|
|
- Execution tracking fields
|
|
- Post-trade analysis framework
|
|
|
|
**TIMEFRAME RISK ASSESSMENT:**
|
|
- **1m-15m**: High risk, 10x+ leverage, tight stops, scalping setups
|
|
- **1H-4H**: Medium risk, 3-5x leverage, moderate stops, swing setups
|
|
- **1D+**: Low risk, 1-2x leverage, wide stops, position setups
|
|
|
|
**ANALYSIS REQUIREMENTS:**
|
|
|
|
1. **IDENTIFY LAYOUT TYPE**: AI Layout (RSI/MACD/EMAs) or DIY Layout (Stoch RSI/VWAP/OBV)
|
|
|
|
2. **MOMENTUM ASSESSMENT**:
|
|
- Check primary momentum indicator (RSI or Stochastic RSI)
|
|
- Look for overbought/oversold conditions
|
|
- Identify momentum divergences
|
|
|
|
3. **TREND CONFIRMATION**:
|
|
- EMA alignment and price position (AI Layout)
|
|
- VWAP position and smart money zones (DIY Layout)
|
|
- Determine trend direction and strength
|
|
|
|
4. **VOLUME ANALYSIS**:
|
|
- MACD histogram momentum (AI Layout)
|
|
- OBV volume flow confirmation (DIY Layout)
|
|
- Volume should confirm price movements
|
|
|
|
5. **PRECISE TRADING LEVELS**:
|
|
- **ENTRY**: Exact execution zone with buffer and technical rationale
|
|
- **STOP LOSS**: Exact level with clear reasoning
|
|
- **TAKE PROFITS**: TP1 (structure) and TP2 (extension) with indicator expectations
|
|
- **RISK/REWARD**: Calculate R:R ratio
|
|
|
|
6. **CONFIRMATION TRIGGERS**: Specific signals to wait for before entry
|
|
|
|
NEVER be vague — always define the level, the behavior, and the action.
|
|
|
|
Provide your analysis in this exact JSON format:
|
|
|
|
{
|
|
"layoutDetected": "AI Layout|DIY Layout",
|
|
"summary": "Professional trading desk analysis with precise execution instructions",
|
|
"marketSentiment": "BULLISH|BEARISH|NEUTRAL",
|
|
"keyLevels": {
|
|
"support": [visible support price levels as numbers],
|
|
"resistance": [visible resistance price levels as numbers]
|
|
},
|
|
"recommendation": "BUY|SELL|HOLD",
|
|
"confidence": 85,
|
|
"reasoning": "Technical analysis reasoning based on established TA principles and indicator confluence",
|
|
"entry": {
|
|
"price": 150.50,
|
|
"zone": {
|
|
"low": 150.20,
|
|
"high": 150.80,
|
|
"optimal": 150.50
|
|
},
|
|
"slippageBuffer": 0.25,
|
|
"rationale": "Specific technical reasoning based on indicator confluence",
|
|
"executionInstructions": "Wait for bearish engulfing candle on rejection from VWAP zone"
|
|
},
|
|
"stopLoss": {
|
|
"price": 148.00,
|
|
"rationale": "Above VWAP + failed breakout zone - hard invalidation level"
|
|
},
|
|
"takeProfits": {
|
|
"tp1": {
|
|
"price": 152.00,
|
|
"description": "Previous low structure - immediate target",
|
|
"rsiExpectation": "RSI should dip near 30 oversold but hold without strong divergence",
|
|
"obvExpectation": "OBV should continue lower lows confirming distribution"
|
|
},
|
|
"tp2": {
|
|
"price": 154.00,
|
|
"description": "Extended flush target at prior liquidity sweep",
|
|
"rsiExpectation": "RSI may show bullish divergence warning of bounce",
|
|
"obvExpectation": "OBV flattening could signal exhaustion"
|
|
}
|
|
},
|
|
"riskToReward": "1:2.5 — Risking $2.50 to potentially gain $6.25",
|
|
"confirmationTrigger": "Bearish engulfing candle on rejection from $150.50-150.80 zone",
|
|
"leverageGuidance": {
|
|
"timeframe": "30m",
|
|
"suggestedLeverage": "5x-8x",
|
|
"positionSizePercent": "1-2%",
|
|
"reasoning": "Medium timeframe allows moderate leverage with controlled risk",
|
|
"riskLevel": "MODERATE"
|
|
},
|
|
"indicatorRoadmap": {
|
|
"rsi": {
|
|
"atEntry": "Should remain under 50 on rejection",
|
|
"atTP1": "Expected to dip near 30 without strong divergence",
|
|
"atTP2": "May show bullish divergence warning of bounce",
|
|
"invalidation": "If crosses above 70 while price under resistance - wait",
|
|
"warningSignals": "Divergence with price action suggests momentum shift"
|
|
},
|
|
"obv": {
|
|
"atEntry": "Must be making lower highs + dropping below 30min average",
|
|
"atTP1": "Should continue lower lows confirming distribution",
|
|
"atTP2": "Flattening could signal selling exhaustion",
|
|
"invalidation": "If starts climbing while price stays flat - early exit",
|
|
"warningSignals": "Volume divergence suggests institutional accumulation"
|
|
},
|
|
"vwap": {
|
|
"atEntry": "Price should reject from VWAP resistance",
|
|
"invalidation": "If price retakes VWAP with bullish momentum",
|
|
"confirmationSignal": "Rejection wick from VWAP zone"
|
|
},
|
|
"macd": {
|
|
"atEntry": "Should show bearish crossover or histogram declining",
|
|
"expectedBehavior": "Continued bearish momentum through targets",
|
|
"invalidation": "Bullish crossover above signal line"
|
|
}
|
|
},
|
|
"journalTemplate": {
|
|
"preFilledData": {
|
|
"asset": "SOLUSD",
|
|
"entry": 150.50,
|
|
"stopLoss": 148.00,
|
|
"tp1": 152.00,
|
|
"tp2": 154.00,
|
|
"riskReward": "1:2.5",
|
|
"setupType": "VWAP rejection + momentum continuation"
|
|
},
|
|
"executionTracking": {
|
|
"confirmationReceived": "Did you wait for bearish engulfing candle?",
|
|
"slippageExpected": "±0.25 acceptable",
|
|
"emotionalState": "Calm / FOMO / Hesitant / Revenge-trading?",
|
|
"executionNotes": "Entry timing and fill quality"
|
|
},
|
|
"postTradeAnalysis": {
|
|
"didFollowPlan": "Followed entry rules and exit strategy?",
|
|
"lessonsLearned": "Key takeaways from this trade",
|
|
"nextTimeImprovement": "What to do better next trade"
|
|
}
|
|
},
|
|
"scenarioManagement": {
|
|
"invalidation": {
|
|
"priceLevel": 148.00,
|
|
"reasoning": "Above VWAP + failed breakdown - trend shifting bullish",
|
|
"immediateAction": "Cut position immediately, reassess bias",
|
|
"nextOpportunity": "Wait for retest of breakdown level for new short"
|
|
},
|
|
"alternatives": {
|
|
"tighterStopOption": "Use $149.20 stop if want tighter risk (1:1.5 R:R)",
|
|
"scaledEntryOption": "Scale in 50% at $150.50, 50% at $150.80 rejection",
|
|
"counterTrendSetup": "Long scalp at $147.80-148.20 if liquidity sweep with RSI divergence",
|
|
"betterRiskReward": "Wait for deeper retracement to $149.00 for 1:3 R:R"
|
|
}
|
|
},
|
|
"psychologyCoaching": {
|
|
"mindsetReminder": "Missing a move is better than revenge-trading a bad entry",
|
|
"emotionalCheck": "Are you trading from FOMO or following your plan?",
|
|
"disciplineNote": "Stick to your $150.50-150.80 rejection zone - discipline > FOMO",
|
|
"riskManagementReminder": "This is scalp/swing hybrid - take profits aggressively, don't dream of trend reversal"
|
|
}
|
|
}
|
|
|
|
Return only the JSON object with your professional trading analysis.`
|
|
|
|
const response = await openai.chat.completions.create({
|
|
model: "gpt-4o-mini", // Cost-effective vision model
|
|
messages: [
|
|
{
|
|
role: "user",
|
|
content: [
|
|
{ type: "text", text: prompt },
|
|
{
|
|
type: "image_url",
|
|
image_url: {
|
|
url: `data:image/png;base64,${base64Image}`,
|
|
detail: "low" // Reduce token usage
|
|
}
|
|
}
|
|
]
|
|
}
|
|
],
|
|
max_tokens: 1024,
|
|
temperature: 0.1
|
|
})
|
|
|
|
const content = response.choices[0]?.message?.content
|
|
if (!content) return null
|
|
|
|
console.log('AI response content:', content)
|
|
|
|
// Extract JSON from response
|
|
const match = content.match(/\{[\s\S]*\}/)
|
|
if (!match) {
|
|
console.error('No JSON found in response. Full content:', content)
|
|
return null
|
|
}
|
|
|
|
const json = match[0]
|
|
console.log('Raw JSON from AI:', json)
|
|
|
|
let result
|
|
try {
|
|
result = JSON.parse(json)
|
|
console.log('Parsed result:', result)
|
|
} catch (parseError) {
|
|
console.error('Failed to parse JSON:', parseError)
|
|
console.error('Raw JSON that failed:', json)
|
|
return null
|
|
}
|
|
|
|
// Sanitize the result to ensure no nested objects cause React issues
|
|
const sanitizedResult = {
|
|
summary: typeof result.summary === 'string' ? result.summary : String(result.summary || ''),
|
|
marketSentiment: result.marketSentiment || 'NEUTRAL',
|
|
keyLevels: {
|
|
support: Array.isArray(result.keyLevels?.support) ? result.keyLevels.support : [],
|
|
resistance: Array.isArray(result.keyLevels?.resistance) ? result.keyLevels.resistance : []
|
|
},
|
|
recommendation: result.recommendation || 'HOLD',
|
|
confidence: typeof result.confidence === 'number' ? result.confidence : 0,
|
|
reasoning: typeof result.reasoning === 'string' ? result.reasoning : String(result.reasoning || 'Basic technical analysis'),
|
|
...(result.entry && { entry: result.entry }),
|
|
...(result.stopLoss && { stopLoss: result.stopLoss }),
|
|
...(result.takeProfits && { takeProfits: result.takeProfits }),
|
|
...(result.riskToReward && { riskToReward: String(result.riskToReward) }),
|
|
...(result.confirmationTrigger && { confirmationTrigger: String(result.confirmationTrigger) }),
|
|
// Professional Trading Desk Features
|
|
...(result.leverageGuidance && { leverageGuidance: result.leverageGuidance }),
|
|
...(result.indicatorRoadmap && { indicatorRoadmap: result.indicatorRoadmap }),
|
|
...(result.journalTemplate && { journalTemplate: result.journalTemplate }),
|
|
...(result.scenarioManagement && { scenarioManagement: result.scenarioManagement }),
|
|
...(result.psychologyCoaching && { psychologyCoaching: result.psychologyCoaching }),
|
|
// Legacy fields for backward compatibility
|
|
...(result.indicatorAnalysis && { indicatorAnalysis: result.indicatorAnalysis }),
|
|
...(result.optimalRiskManagement && { optimalRiskManagement: result.optimalRiskManagement }),
|
|
...(result.timeframeRisk && { timeframeRisk: result.timeframeRisk }),
|
|
...(result.alternatives && { alternatives: result.alternatives })
|
|
}
|
|
|
|
// Optionally: validate result structure here
|
|
return sanitizedResult as AnalysisResult
|
|
} catch (e) {
|
|
console.error('AI analysis error:', e)
|
|
return null
|
|
}
|
|
}
|
|
|
|
async analyzeMultipleScreenshots(filenamesOrPaths: string[]): Promise<AnalysisResult | null> {
|
|
try {
|
|
// Read all image files and convert to base64
|
|
const images = await Promise.all(
|
|
filenamesOrPaths.map(async (filenameOrPath) => {
|
|
let imagePath: string
|
|
|
|
// Check if it's already a full path or just a filename
|
|
if (path.isAbsolute(filenameOrPath)) {
|
|
// It's already a full path
|
|
imagePath = filenameOrPath
|
|
} else {
|
|
// It's just a filename, construct the full path
|
|
const screenshotsDir = path.join(process.cwd(), 'screenshots')
|
|
imagePath = path.join(screenshotsDir, filenameOrPath)
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|
|
})
|
|
)
|
|
|
|
const layoutInfo = filenamesOrPaths.map(f => {
|
|
const filename = path.basename(f) // Extract filename from path
|
|
if (filename.includes('_ai_')) return 'AI Layout'
|
|
if (f.includes('_diy_') || f.includes('_Diy module_')) return 'DIY Module Layout'
|
|
return 'Unknown Layout'
|
|
}).join(' and ')
|
|
|
|
const prompt = `You are now a professional trading assistant. You behave with the precision and decisiveness of a top proprietary desk trader. No vagueness, no fluff.
|
|
|
|
I'm providing you with ${filenamesOrPaths.length} TradingView chart screenshots from different layouts: ${layoutInfo}.
|
|
|
|
**WHEN GIVING A TRADE SETUP:**
|
|
Be 100% SPECIFIC with MULTI-LAYOUT CONSENSUS:
|
|
|
|
1. **CROSS-LAYOUT VALIDATION**:
|
|
- Compare momentum signals between layouts (RSI vs Stochastic RSI)
|
|
- Confirm trend direction with both EMA stack and VWAP positioning
|
|
- Volume confirmation: MACD histogram vs OBV flow agreement
|
|
- ONLY trade when layouts show consensus - avoid conflicting signals
|
|
|
|
2. **TIMEFRAME RISK ASSESSMENT**:
|
|
- Lower timeframes = higher risk, higher leverage (5min scalp: 10x+ leverage, tight stops)
|
|
- Higher timeframes = lower risk, lower leverage (4H: 2-3x leverage, wider stops)
|
|
- Position sizing: Less money on lower timeframes, more on higher timeframes
|
|
|
|
**TECHNICAL ANALYSIS FUNDAMENTALS:**
|
|
|
|
**RSI (Relative Strength Index):**
|
|
- OVERBOUGHT: Above 70 (potential sell signal)
|
|
- OVERSOLD: Below 30 (potential buy signal)
|
|
- NEUTRAL: 30-70 range
|
|
- ⚠️ CRITICAL: Read visual line position, not numerical value when they conflict
|
|
|
|
**MACD (Moving Average Convergence Divergence):**
|
|
- BULLISH CROSSOVER: MACD line crosses ABOVE signal line
|
|
- BEARISH CROSSOVER: MACD line crosses BELOW signal line
|
|
- HISTOGRAM: Green bars = bullish momentum, Red bars = bearish momentum
|
|
- ZERO LINE: Above = bullish trend, Below = bearish trend
|
|
|
|
**EMAs (Exponential Moving Averages):**
|
|
- EMA 9 (Yellow): Short-term trend
|
|
- EMA 20 (Orange): Medium-term trend
|
|
- EMA 50 (Blue): Intermediate trend
|
|
- EMA 200 (Red): Long-term trend
|
|
- BULLISH STACK: 9 > 20 > 50 > 200
|
|
- BEARISH STACK: 9 < 20 < 50 < 200
|
|
|
|
**Stochastic RSI:**
|
|
- OVERBOUGHT: Above 80
|
|
- OVERSOLD: Below 20
|
|
- BULLISH SIGNAL: %K crosses above %D in oversold territory
|
|
- BEARISH SIGNAL: %K crosses below %D in overbought territory
|
|
|
|
**VWAP (Volume Weighted Average Price):**
|
|
- Above VWAP = Bullish sentiment
|
|
- Below VWAP = Bearish sentiment
|
|
- RECLAIM: Price moves back above VWAP (bullish)
|
|
- REJECTION: Price fails at VWAP (bearish)
|
|
|
|
**OBV (On-Balance Volume):**
|
|
- Rising OBV = Volume supporting upward price movement
|
|
- Falling OBV = Volume supporting downward price movement
|
|
- DIVERGENCE: OBV direction differs from price (warning signal)
|
|
|
|
**MULTI-LAYOUT ANALYSIS:**
|
|
|
|
**AI Layout (RSI + MACD + EMAs):**
|
|
- Focus: Momentum + Trend Analysis
|
|
- Primary indicators: RSI, MACD, EMAs
|
|
- Use for: Trend direction, momentum signals, entry/exit timing
|
|
|
|
**DIY Layout (Stochastic RSI + VWAP + OBV):**
|
|
- Focus: Volume + Institutional Flow Analysis
|
|
- Primary indicators: Stochastic RSI, VWAP, OBV
|
|
- Use for: Volume confirmation, institutional sentiment, fair value
|
|
|
|
**PROFESSIONAL MULTI-LAYOUT REQUIREMENTS:**
|
|
|
|
3. **ENTRY WITH CROSS-LAYOUT CONFIRMATION**
|
|
- Exact price level with execution zone (high/low/optimal)
|
|
- Slippage buffer (±0.25, ±0.50, etc.)
|
|
- Rationale: e.g., "AI Layout: RSI oversold + MACD bullish crossover | DIY Layout: Stochastic RSI oversold crossover + VWAP reclaim"
|
|
- Execution instructions: What to wait for before entering
|
|
|
|
4. **STOP-LOSS (SL)**
|
|
- Exact level based on BOTH layouts
|
|
- Explain *why*: "Below VWAP AND under EMA 20 support confluence"
|
|
|
|
5. **TAKE PROFITS WITH INDICATOR EXPECTATIONS**
|
|
- TP1: Immediate structure with BOTH layout expectations
|
|
- TP2: Extended target with cross-layout momentum analysis
|
|
- Expected behavior for ALL indicators (RSI, Stochastic RSI, MACD, OBV, VWAP, EMAs)
|
|
|
|
6. **RISK-TO-REWARD**
|
|
- Show R:R with cross-layout validation
|
|
|
|
7. **CONFIRMATION TRIGGER**
|
|
- Exact signal from BOTH layouts: e.g., "AI Layout: MACD bullish crossover AND DIY Layout: VWAP reclaim with OBV rising"
|
|
|
|
8. **CROSS-LAYOUT CONSENSUS ANALYSIS**
|
|
- Where layouts AGREE (strengthen confidence)
|
|
- Where layouts DIVERGE (caution signals)
|
|
- Overall consensus assessment
|
|
|
|
9. **MULTI-LAYOUT INDICATOR ROADMAP**
|
|
- Expected behavior for ALL indicators at entry and targets
|
|
- Cross-validation warning signals
|
|
- Invalidation triggers from either layout
|
|
|
|
10. **LEVERAGE & POSITION SIZING**
|
|
- Based on timeframe AND cross-layout confidence
|
|
- Higher confidence from consensus = slightly higher position size
|
|
- Conflicting signals = reduce size or wait
|
|
|
|
**TIMEFRAME RISK ASSESSMENT:**
|
|
- **1m-15m**: High risk, 10x+ leverage, tight stops, scalping setups
|
|
- **1H-4H**: Medium risk, 3-5x leverage, moderate stops, swing setups
|
|
- **1D+**: Low risk, 1-2x leverage, wide stops, position setups
|
|
|
|
**ANALYSIS PROCESS:**
|
|
1. **Identify Layout Types**: Determine which layouts are provided
|
|
2. **Cross-Layout Momentum Assessment**: Compare RSI vs Stochastic RSI signals
|
|
3. **Cross-Layout Trend Confirmation**: EMA alignment vs VWAP positioning
|
|
4. **Cross-Layout Volume Analysis**: MACD histogram vs OBV flow agreement
|
|
5. **Consensus vs Divergence**: Where layouts agree/disagree
|
|
6. **Risk Assessment**: Adjust for timeframe and layout confidence
|
|
|
|
NEVER be vague — always define the level, the behavior, and the cross-layout consensus.
|
|
|
|
**Response Format** (return only valid JSON):
|
|
|
|
{
|
|
"summary": "Professional multi-layout analysis with cross-layout consensus and precise execution instructions",
|
|
"marketSentiment": "BULLISH|BEARISH|NEUTRAL",
|
|
"keyLevels": {
|
|
"support": [array of support levels from all charts],
|
|
"resistance": [array of resistance levels from all charts]
|
|
},
|
|
"recommendation": "BUY|SELL|HOLD",
|
|
"confidence": 85,
|
|
"reasoning": "Multi-layout technical analysis with cross-layout confirmation",
|
|
"layoutsAnalyzed": ["AI Layout", "DIY Layout"],
|
|
"layoutComparison": {
|
|
"aiLayout": "AI Layout analysis with RSI, MACD, EMA insights",
|
|
"diyLayout": "DIY Layout analysis with Stochastic RSI, VWAP, OBV insights",
|
|
"consensus": "Where both layouts agree - strengthens setup confidence",
|
|
"divergences": "Where layouts conflict - caution signals or wait"
|
|
},
|
|
"entry": {
|
|
"price": 150.50,
|
|
"zone": {
|
|
"low": 150.20,
|
|
"high": 150.80,
|
|
"optimal": 150.50
|
|
},
|
|
"slippageBuffer": 0.25,
|
|
"rationale": "Cross-layout confluence: AI Layout RSI oversold + MACD bullish crossover | DIY Layout Stochastic RSI oversold + VWAP reclaim",
|
|
"executionInstructions": "Wait for both MACD bullish crossover AND VWAP reclaim with rising OBV"
|
|
},
|
|
"stopLoss": {
|
|
"price": 148.00,
|
|
"rationale": "Below VWAP AND under EMA 20 support confluence - invalidates both layouts"
|
|
},
|
|
"takeProfits": {
|
|
"tp1": {
|
|
"price": 152.00,
|
|
"description": "Previous resistance - cross-layout profit taking zone",
|
|
"rsiExpectation": "RSI should reach 60-65 range",
|
|
"obvExpectation": "OBV should show higher highs confirming momentum",
|
|
"stochRsiExpectation": "Stochastic RSI should reach 70-80 range",
|
|
"vwapExpectation": "Price should maintain above VWAP"
|
|
},
|
|
"tp2": {
|
|
"price": 154.00,
|
|
"description": "Extended target - momentum continuation zone",
|
|
"rsiExpectation": "RSI may reach overbought 70+ (momentum exhaustion warning)",
|
|
"obvExpectation": "OBV continues rising but watch for divergence",
|
|
"stochRsiExpectation": "Stochastic RSI likely overbought 80+ (take profits)",
|
|
"vwapExpectation": "Price extension above VWAP - institutional profit taking"
|
|
}
|
|
},
|
|
"riskToReward": "1:2.5 — Risking $2.50 to potentially gain $6.25",
|
|
"confirmationTrigger": "AI Layout: MACD bullish crossover AND DIY Layout: VWAP reclaim with rising OBV",
|
|
"leverageGuidance": {
|
|
"timeframe": "1H",
|
|
"suggestedLeverage": "3-5x",
|
|
"positionSizePercent": "2-3%",
|
|
"reasoning": "Medium timeframe with strong cross-layout consensus allows moderate leverage",
|
|
"riskLevel": "MODERATE"
|
|
},
|
|
"indicatorRoadmap": {
|
|
"rsi": {
|
|
"atEntry": "Should be oversold below 30 with upward momentum",
|
|
"atTP1": "Expected to reach 60-65 range",
|
|
"atTP2": "May reach overbought 70+ (momentum exhaustion warning)",
|
|
"invalidation": "If fails to bounce from oversold levels",
|
|
"warningSignals": "Bearish divergence at TP2 levels"
|
|
},
|
|
"stochRsi": {
|
|
"atEntry": "Should show %K crossing above %D in oversold territory",
|
|
"atTP1": "Expected to reach 70-80 range",
|
|
"atTP2": "Likely overbought 80+ (take profits)",
|
|
"invalidation": "If %K crosses below %D without follow through",
|
|
"warningSignals": "Bearish crossover in overbought territory"
|
|
},
|
|
"obv": {
|
|
"atEntry": "Must be rising confirming buying pressure",
|
|
"atTP1": "Should show higher highs confirming momentum",
|
|
"atTP2": "Continues rising but watch for divergence",
|
|
"invalidation": "If starts declining while price rises",
|
|
"warningSignals": "Bearish divergence suggests institutional selling"
|
|
},
|
|
"vwap": {
|
|
"atEntry": "Price should reclaim VWAP with strong volume",
|
|
"invalidation": "If price rejected back below VWAP",
|
|
"confirmationSignal": "Strong hold above VWAP after reclaim"
|
|
},
|
|
"macd": {
|
|
"atEntry": "Should show bullish crossover above signal line",
|
|
"expectedBehavior": "Histogram turning green, momentum building",
|
|
"invalidation": "Bearish crossover or histogram declining"
|
|
}
|
|
},
|
|
"journalTemplate": {
|
|
"preFilledData": {
|
|
"asset": "SOLUSD",
|
|
"entry": 150.50,
|
|
"stopLoss": 148.00,
|
|
"tp1": 152.00,
|
|
"tp2": 154.00,
|
|
"riskReward": "1:2.5",
|
|
"setupType": "Multi-layout consensus: RSI oversold + VWAP reclaim"
|
|
},
|
|
"executionTracking": {
|
|
"confirmationReceived": "Did you wait for BOTH MACD crossover AND VWAP reclaim?",
|
|
"slippageExpected": "±0.25 acceptable",
|
|
"emotionalState": "Calm / FOMO / Hesitant / Revenge-trading?",
|
|
"executionNotes": "Cross-layout signal timing and fill quality"
|
|
},
|
|
"postTradeAnalysis": {
|
|
"didFollowPlan": "Followed multi-layout entry rules and exit strategy?",
|
|
"lessonsLearned": "Key takeaways from cross-layout analysis",
|
|
"nextTimeImprovement": "Better cross-layout signal timing"
|
|
}
|
|
},
|
|
"scenarioManagement": {
|
|
"invalidation": {
|
|
"priceLevel": 148.00,
|
|
"reasoning": "Below VWAP AND under EMA 20 - both layouts invalidated",
|
|
"immediateAction": "Cut position immediately, both setups failed",
|
|
"nextOpportunity": "Wait for new multi-layout consensus setup"
|
|
},
|
|
"alternatives": {
|
|
"tighterStopOption": "Use $149.20 stop if want tighter risk (1:1.8 R:R)",
|
|
"scaledEntryOption": "Scale in 50% at VWAP reclaim, 50% at MACD crossover",
|
|
"counterTrendSetup": "Short if both layouts show overbought rejection at resistance",
|
|
"betterRiskReward": "Wait for deeper pullback to $149.00 for 1:3.5 R:R"
|
|
}
|
|
},
|
|
"psychologyCoaching": {
|
|
"mindsetReminder": "Cross-layout consensus = higher probability, but still requires discipline",
|
|
"emotionalCheck": "Are you trading the consensus or forcing conflicting signals?",
|
|
"disciplineNote": "Wait for BOTH layouts to confirm - patience pays in multi-layout analysis",
|
|
"riskManagementReminder": "Even with consensus, risk management is paramount"
|
|
}
|
|
}
|
|
|
|
Return only the JSON object with your professional multi-layout trading analysis.`
|
|
|
|
const messages = [
|
|
{
|
|
role: "user" as const,
|
|
content: [
|
|
{ type: "text" as const, text: prompt },
|
|
...images
|
|
]
|
|
}
|
|
]
|
|
|
|
console.log(`🤖 Sending ${filenamesOrPaths.length} screenshots to OpenAI for multi-layout analysis...`)
|
|
|
|
// Add rate limiting check to prevent 429 errors
|
|
const now = Date.now()
|
|
if (this.lastApiCall && (now - this.lastApiCall) < 2000) {
|
|
const waitTime = 2000 - (now - this.lastApiCall)
|
|
console.log(`⏳ Rate limiting: waiting ${waitTime}ms before OpenAI call`)
|
|
await new Promise(resolve => setTimeout(resolve, waitTime))
|
|
}
|
|
|
|
try {
|
|
const response = await openai.chat.completions.create({
|
|
model: "gpt-4o-mini", // Cost-effective model with vision capabilities
|
|
messages,
|
|
max_tokens: 2000,
|
|
temperature: 0.1
|
|
})
|
|
|
|
this.lastApiCall = Date.now()
|
|
|
|
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) + '...')
|
|
|
|
// Parse JSON response
|
|
const jsonMatch = content.match(/\{[\s\S]*\}/)
|
|
if (!jsonMatch) {
|
|
throw new Error('No JSON found in response')
|
|
}
|
|
|
|
const analysis = JSON.parse(jsonMatch[0])
|
|
console.log('✅ Multi-layout analysis parsed successfully')
|
|
|
|
return analysis as AnalysisResult
|
|
} catch (error: any) {
|
|
if (error.status === 429) {
|
|
console.log('⏳ OpenAI rate limit hit - will retry on next cycle')
|
|
// Don't throw the error, just return null to skip this cycle gracefully
|
|
return null
|
|
}
|
|
throw error
|
|
}
|
|
|
|
} catch (error: any) {
|
|
console.error('❌ Multi-screenshot AI analysis failed:', error.message)
|
|
console.error('Full error:', error)
|
|
return null
|
|
}
|
|
}
|
|
|
|
async captureAndAnalyze(
|
|
symbol: string,
|
|
timeframe: string,
|
|
credentials: TradingViewCredentials
|
|
): Promise<AnalysisResult | null> {
|
|
try {
|
|
console.log(`Starting automated capture and analysis for ${symbol} ${timeframe}`)
|
|
|
|
// Capture screenshot using automation
|
|
const screenshot = await enhancedScreenshotService.captureQuick(symbol, timeframe, credentials)
|
|
|
|
if (!screenshot) {
|
|
throw new Error('Failed to capture screenshot')
|
|
}
|
|
|
|
console.log(`Screenshot captured: ${screenshot}`)
|
|
|
|
// Analyze the captured screenshot
|
|
const analysis = await this.analyzeScreenshot(screenshot)
|
|
|
|
if (!analysis) {
|
|
throw new Error('Failed to analyze screenshot')
|
|
}
|
|
|
|
console.log(`Analysis completed for ${symbol} ${timeframe}`)
|
|
return analysis
|
|
|
|
} catch (error) {
|
|
console.error('Automated capture and analysis failed:', error)
|
|
return null
|
|
}
|
|
}
|
|
|
|
async captureAndAnalyzeMultiple(
|
|
symbols: string[],
|
|
timeframes: string[],
|
|
credentials: TradingViewCredentials
|
|
): Promise<Array<{ symbol: string; timeframe: string; analysis: AnalysisResult | null }>> {
|
|
const results: Array<{ symbol: string; timeframe: string; analysis: AnalysisResult | null }> = []
|
|
|
|
for (const symbol of symbols) {
|
|
for (const timeframe of timeframes) {
|
|
try {
|
|
console.log(`Processing ${symbol} ${timeframe}...`)
|
|
const analysis = await this.captureAndAnalyze(symbol, timeframe, credentials)
|
|
|
|
results.push({
|
|
symbol,
|
|
timeframe,
|
|
analysis
|
|
})
|
|
|
|
// Small delay between captures to avoid overwhelming the system
|
|
await new Promise(resolve => setTimeout(resolve, 2000))
|
|
|
|
} catch (error) {
|
|
console.error(`Failed to process ${symbol} ${timeframe}:`, error)
|
|
results.push({
|
|
symbol,
|
|
timeframe,
|
|
analysis: null
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
return results
|
|
}
|
|
|
|
async captureAndAnalyzeWithConfig(config: ScreenshotConfig): Promise<{
|
|
screenshots: string[]
|
|
analysis: AnalysisResult | null
|
|
}> {
|
|
const { sessionId } = config
|
|
|
|
try {
|
|
console.log(`Starting automated capture with config for ${config.symbol} ${config.timeframe}`)
|
|
|
|
// Capture screenshots using enhanced service (this will handle its own progress)
|
|
const screenshots = await enhancedScreenshotService.captureWithLogin(config)
|
|
|
|
if (screenshots.length === 0) {
|
|
throw new Error('No screenshots captured')
|
|
}
|
|
|
|
console.log(`${screenshots.length} screenshot(s) captured`)
|
|
|
|
// Add AI analysis step to progress if sessionId exists
|
|
if (sessionId) {
|
|
progressTracker.updateStep(sessionId, 'analysis', 'active', 'Running AI analysis on screenshots...')
|
|
}
|
|
|
|
let analysis: AnalysisResult | null = null
|
|
|
|
if (screenshots.length === 1) {
|
|
// Single screenshot analysis
|
|
analysis = await this.analyzeScreenshot(screenshots[0])
|
|
} else {
|
|
// Multiple screenshots analysis
|
|
analysis = await this.analyzeMultipleScreenshots(screenshots)
|
|
}
|
|
|
|
if (!analysis) {
|
|
if (sessionId) {
|
|
progressTracker.updateStep(sessionId, 'analysis', 'error', 'AI analysis failed to generate results')
|
|
}
|
|
throw new Error('Failed to analyze screenshots')
|
|
}
|
|
|
|
console.log(`Analysis completed for ${config.symbol} ${config.timeframe}`)
|
|
|
|
if (sessionId) {
|
|
progressTracker.updateStep(sessionId, 'analysis', 'completed', 'AI analysis completed successfully!')
|
|
// Mark session as complete
|
|
setTimeout(() => progressTracker.deleteSession(sessionId), 1000)
|
|
}
|
|
|
|
// Trigger post-analysis cleanup in development mode
|
|
if (process.env.NODE_ENV === 'development') {
|
|
try {
|
|
// Dynamic import to avoid circular dependencies
|
|
const aggressiveCleanupModule = await import('./aggressive-cleanup')
|
|
const aggressiveCleanup = aggressiveCleanupModule.default
|
|
// Run cleanup in background, don't block the response
|
|
aggressiveCleanup.runPostAnalysisCleanup().catch(console.error)
|
|
} catch (cleanupError) {
|
|
console.error('Error triggering post-analysis cleanup:', cleanupError)
|
|
}
|
|
}
|
|
|
|
return {
|
|
screenshots,
|
|
analysis
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('Automated capture and analysis with config failed:', error)
|
|
|
|
if (sessionId) {
|
|
// Find the active step and mark it as error
|
|
const progress = progressTracker.getProgress(sessionId)
|
|
if (progress) {
|
|
const activeStep = progress.steps.find(step => step.status === 'active')
|
|
if (activeStep) {
|
|
progressTracker.updateStep(sessionId, activeStep.id, 'error', error instanceof Error ? error.message : 'Unknown error')
|
|
}
|
|
}
|
|
// Clean up session
|
|
setTimeout(() => progressTracker.deleteSession(sessionId), 5000)
|
|
}
|
|
|
|
return {
|
|
screenshots: [],
|
|
analysis: null
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
export const aiAnalysisService = new AIAnalysisService()
|