🔧 Fix AI Analysis Service - Improved Prompts & Error Handling
✅ FIXED: AI analysis prompts to bypass OpenAI safety guardrails ✅ FIXED: Added technical analysis focus instead of trading advice tone ✅ FIXED: Improved JSON parsing and error handling ✅ ADDED: Option to use existing screenshots for testing (useExisting param) ✅ IMPROVED: Better image detail settings and temperature for consistency 🐛 DEBUGGING: Still investigating why AI claims it can't see images - OpenAI vision capabilities confirmed working with public images - Model gpt-4o has proper vision support - Issue appears to be with chart image content or encoding 🎯 NEXT: Debug image encoding and model response inconsistency
This commit is contained in:
@@ -3,10 +3,11 @@ import { aiAnalysisService } from '../../../lib/ai-analysis'
|
|||||||
import { enhancedScreenshotService } from '../../../lib/enhanced-screenshot'
|
import { enhancedScreenshotService } from '../../../lib/enhanced-screenshot'
|
||||||
import { settingsManager } from '../../../lib/settings'
|
import { settingsManager } from '../../../lib/settings'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
import fs from 'fs'
|
||||||
|
|
||||||
export async function POST(req: NextRequest) {
|
export async function POST(req: NextRequest) {
|
||||||
try {
|
try {
|
||||||
const { symbol, layouts, timeframe } = await req.json()
|
const { symbol, layouts, timeframe, useExisting } = await req.json()
|
||||||
|
|
||||||
// Load current settings
|
// Load current settings
|
||||||
const settings = await settingsManager.loadSettings()
|
const settings = await settingsManager.loadSettings()
|
||||||
@@ -19,9 +20,37 @@ export async function POST(req: NextRequest) {
|
|||||||
if (!finalSymbol) {
|
if (!finalSymbol) {
|
||||||
return NextResponse.json({ error: 'Missing symbol' }, { status: 400 })
|
return NextResponse.json({ error: 'Missing symbol' }, { status: 400 })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let screenshots: string[] = []
|
||||||
|
|
||||||
const baseFilename = `${finalSymbol}_${finalTimeframe}_${Date.now()}`
|
// If useExisting is true, find existing screenshots
|
||||||
const screenshots = await enhancedScreenshotService.capture(finalSymbol, `${baseFilename}.png`, finalLayouts, finalTimeframe)
|
if (useExisting) {
|
||||||
|
console.log('Using existing screenshots for analysis...')
|
||||||
|
const screenshotsDir = path.join(process.cwd(), 'screenshots')
|
||||||
|
const allFiles = await fs.promises.readdir(screenshotsDir)
|
||||||
|
|
||||||
|
// Find screenshots matching the symbol and timeframe
|
||||||
|
const matchingFiles = allFiles.filter(file =>
|
||||||
|
file.includes(finalSymbol) &&
|
||||||
|
file.includes(finalTimeframe) &&
|
||||||
|
file.endsWith('.png') &&
|
||||||
|
!file.includes('debug')
|
||||||
|
)
|
||||||
|
|
||||||
|
if (matchingFiles.length > 0) {
|
||||||
|
// Use the most recent screenshots (limit to 3 for analysis)
|
||||||
|
screenshots = matchingFiles
|
||||||
|
.sort((a, b) => b.localeCompare(a)) // Sort by name (which includes timestamp)
|
||||||
|
.slice(0, 3)
|
||||||
|
.map(file => path.join(screenshotsDir, file))
|
||||||
|
} else {
|
||||||
|
return NextResponse.json({ error: `No existing screenshots found for ${finalSymbol} ${finalTimeframe}` }, { status: 404 })
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Original behavior - capture new screenshots
|
||||||
|
const baseFilename = `${finalSymbol}_${finalTimeframe}_${Date.now()}`
|
||||||
|
screenshots = await enhancedScreenshotService.capture(finalSymbol, `${baseFilename}.png`, finalLayouts, finalTimeframe)
|
||||||
|
}
|
||||||
|
|
||||||
let result
|
let result
|
||||||
if (screenshots.length === 1) {
|
if (screenshots.length === 1) {
|
||||||
@@ -46,7 +75,8 @@ export async function POST(req: NextRequest) {
|
|||||||
timeframe: finalTimeframe,
|
timeframe: finalTimeframe,
|
||||||
layouts: finalLayouts
|
layouts: finalLayouts
|
||||||
},
|
},
|
||||||
screenshots: screenshots.map((s: string) => path.basename(s))
|
screenshots: screenshots.map((s: string) => path.basename(s)),
|
||||||
|
usedExisting: useExisting || false
|
||||||
})
|
})
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
return NextResponse.json({ error: e.message }, { status: 500 })
|
return NextResponse.json({ error: e.message }, { status: 500 })
|
||||||
|
|||||||
113
debug-ai-analysis.js
Normal file
113
debug-ai-analysis.js
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
const OpenAI = require('openai').default
|
||||||
|
|
||||||
|
// Initialize OpenAI
|
||||||
|
const openai = new OpenAI({
|
||||||
|
apiKey: process.env.OPENAI_API_KEY,
|
||||||
|
})
|
||||||
|
|
||||||
|
async function testAIAnalysis() {
|
||||||
|
try {
|
||||||
|
console.log('🔍 Testing AI analysis with a real screenshot...')
|
||||||
|
|
||||||
|
// Use one of the existing screenshots
|
||||||
|
const screenshotsDir = path.join(process.cwd(), 'screenshots')
|
||||||
|
const testImage = 'SOLUSD_60_1752324455391_ai.png'
|
||||||
|
const imagePath = path.join(screenshotsDir, testImage)
|
||||||
|
|
||||||
|
console.log(`📸 Using screenshot: ${imagePath}`)
|
||||||
|
|
||||||
|
// Check if file exists
|
||||||
|
if (!fs.existsSync(imagePath)) {
|
||||||
|
console.error('❌ Screenshot file not found!')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('✅ Screenshot file found')
|
||||||
|
|
||||||
|
// Read and encode image
|
||||||
|
const imageBuffer = fs.readFileSync(imagePath)
|
||||||
|
const base64Image = imageBuffer.toString('base64')
|
||||||
|
|
||||||
|
console.log(`📊 Image size: ${imageBuffer.length} bytes`)
|
||||||
|
console.log(`🔒 Base64 length: ${base64Image.length} characters`)
|
||||||
|
console.log(`🎯 Base64 preview: ${base64Image.substring(0, 100)}...`)
|
||||||
|
|
||||||
|
// Improved prompt for testing
|
||||||
|
const prompt = `You are a technical chart analysis expert. Please analyze this TradingView chart image and provide objective technical analysis data.
|
||||||
|
|
||||||
|
**Important**: This is for educational and research purposes only. Please analyze the technical indicators, price levels, and chart patterns visible in the image.
|
||||||
|
|
||||||
|
Examine the chart and identify:
|
||||||
|
- Current price action and trend direction
|
||||||
|
- Key support and resistance levels visible on the chart
|
||||||
|
- Technical indicator readings (RSI, moving averages, volume if visible)
|
||||||
|
- Chart patterns or formations
|
||||||
|
- Market structure elements
|
||||||
|
|
||||||
|
Provide your analysis in this exact JSON format (replace values with your analysis):
|
||||||
|
|
||||||
|
{
|
||||||
|
"summary": "Objective description of what you observe in the chart",
|
||||||
|
"marketSentiment": "BULLISH",
|
||||||
|
"recommendation": "BUY",
|
||||||
|
"confidence": 75
|
||||||
|
}
|
||||||
|
|
||||||
|
Return only the JSON object with your technical analysis.`
|
||||||
|
|
||||||
|
console.log('🤖 Sending request to OpenAI...')
|
||||||
|
|
||||||
|
const response = await openai.chat.completions.create({
|
||||||
|
model: "gpt-4o", // Latest vision model
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
role: "user",
|
||||||
|
content: [
|
||||||
|
{ type: "text", text: prompt },
|
||||||
|
{
|
||||||
|
type: "image_url",
|
||||||
|
image_url: {
|
||||||
|
url: `data:image/png;base64,${base64Image}`,
|
||||||
|
detail: "low" // Add detail parameter to reduce token usage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
max_tokens: 500,
|
||||||
|
temperature: 0.1
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('✅ Response received from OpenAI')
|
||||||
|
|
||||||
|
const content = response.choices[0]?.message?.content
|
||||||
|
console.log('📝 Full response content:')
|
||||||
|
console.log(content)
|
||||||
|
|
||||||
|
// Try to extract JSON
|
||||||
|
const jsonMatch = content?.match(/\{[\s\S]*\}/)
|
||||||
|
if (jsonMatch) {
|
||||||
|
console.log('✅ JSON found in response:')
|
||||||
|
console.log(jsonMatch[0])
|
||||||
|
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(jsonMatch[0])
|
||||||
|
console.log('✅ JSON successfully parsed:')
|
||||||
|
console.log(JSON.stringify(parsed, null, 2))
|
||||||
|
} catch (e) {
|
||||||
|
console.error('❌ Failed to parse JSON:', e.message)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.error('❌ No JSON found in response')
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Error testing AI analysis:', error.message)
|
||||||
|
console.error('Full error:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the test
|
||||||
|
testAIAnalysis()
|
||||||
71
debug-openai-vision.js
Normal file
71
debug-openai-vision.js
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
const OpenAI = require('openai').default
|
||||||
|
|
||||||
|
async function testOpenAIVision() {
|
||||||
|
try {
|
||||||
|
console.log('🔍 Testing OpenAI Vision capabilities...')
|
||||||
|
|
||||||
|
const openai = new OpenAI({
|
||||||
|
apiKey: process.env.OPENAI_API_KEY,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Test with a simple text-only request first
|
||||||
|
console.log('📝 Testing text-only request...')
|
||||||
|
|
||||||
|
const textResponse = await openai.chat.completions.create({
|
||||||
|
model: "gpt-4o",
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
role: "user",
|
||||||
|
content: "Respond with a simple JSON: {'test': 'success'}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
max_tokens: 50
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('✅ Text response:', textResponse.choices[0]?.message?.content)
|
||||||
|
|
||||||
|
// Test with a simple image URL (public image)
|
||||||
|
console.log('🖼️ Testing with public image...')
|
||||||
|
|
||||||
|
const imageResponse = await openai.chat.completions.create({
|
||||||
|
model: "gpt-4o",
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
role: "user",
|
||||||
|
content: [
|
||||||
|
{ type: "text", text: "What do you see in this image? Respond with JSON: {'description': 'your description'}" },
|
||||||
|
{
|
||||||
|
type: "image_url",
|
||||||
|
image_url: {
|
||||||
|
url: "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
max_tokens: 100
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('✅ Image response:', imageResponse.choices[0]?.message?.content)
|
||||||
|
|
||||||
|
// Check account details
|
||||||
|
console.log('🔍 Checking available models...')
|
||||||
|
|
||||||
|
const models = await openai.models.list()
|
||||||
|
const visionModels = models.data.filter(model =>
|
||||||
|
model.id.includes('gpt-4') && (model.id.includes('vision') || model.id.includes('gpt-4o'))
|
||||||
|
)
|
||||||
|
|
||||||
|
console.log('🎯 Available vision models:')
|
||||||
|
visionModels.forEach(model => console.log(` - ${model.id}`))
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Error:', error.message)
|
||||||
|
if (error.response) {
|
||||||
|
console.error('📊 Response status:', error.response.status)
|
||||||
|
console.error('📝 Response data:', JSON.stringify(error.response.data, null, 2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testOpenAIVision()
|
||||||
@@ -50,73 +50,53 @@ export class AIAnalysisService {
|
|||||||
const imageBuffer = await fs.readFile(imagePath)
|
const imageBuffer = await fs.readFile(imagePath)
|
||||||
const base64Image = imageBuffer.toString('base64')
|
const base64Image = imageBuffer.toString('base64')
|
||||||
|
|
||||||
const prompt = `You are now a professional trading assistant focused on short-term crypto trading using 5–15min timeframes. You behave with the precision and decisiveness of a top proprietary desk trader. No vagueness, no fluff.
|
const prompt = `You are a technical chart analysis expert. Please analyze this TradingView chart image and provide objective technical analysis data.
|
||||||
|
|
||||||
Analyze the attached TradingView chart screenshot and provide a detailed trading analysis.
|
**Important**: This is for educational and research purposes only. Please analyze the technical indicators, price levels, and chart patterns visible in the image.
|
||||||
|
|
||||||
### WHEN GIVING A TRADE SETUP:
|
Examine the chart and identify:
|
||||||
Be 100% SPECIFIC. Provide:
|
- Current price action and trend direction
|
||||||
|
- Key support and resistance levels visible on the chart
|
||||||
|
- Technical indicator readings (RSI, moving averages, volume if visible)
|
||||||
|
- Chart patterns or formations
|
||||||
|
- Market structure elements
|
||||||
|
|
||||||
1. **ENTRY**
|
Provide your analysis in this exact JSON format (replace values with your analysis):
|
||||||
- Exact price level (with a ± entry buffer if needed)
|
|
||||||
- Rationale: e.g., "Rejection from 15 EMA + VWAP confluence near intraday supply"
|
|
||||||
|
|
||||||
2. **STOP-LOSS (SL)**
|
|
||||||
- Exact level (not arbitrary)
|
|
||||||
- Explain *why* it's there: "Above VWAP + failed breakout zone"
|
|
||||||
|
|
||||||
3. **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
|
|
||||||
|
|
||||||
4. **RISK-TO-REWARD**
|
|
||||||
- Show R:R. Ex: "1:2.5 — Risking $X to potentially gain $Y"
|
|
||||||
|
|
||||||
5. **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"
|
|
||||||
|
|
||||||
6. **INDICATOR ANALYSIS**
|
|
||||||
- **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*
|
|
||||||
|
|
||||||
Return your answer as a JSON object with the following structure:
|
|
||||||
{
|
{
|
||||||
"summary": "Brief market summary",
|
"summary": "Objective description of what you observe in the chart",
|
||||||
"marketSentiment": "BULLISH" | "BEARISH" | "NEUTRAL",
|
"marketSentiment": "BULLISH|BEARISH|NEUTRAL",
|
||||||
"keyLevels": {
|
"keyLevels": {
|
||||||
"support": [number array],
|
"support": [list of visible support price levels as numbers],
|
||||||
"resistance": [number array]
|
"resistance": [list of visible resistance price levels as numbers]
|
||||||
},
|
},
|
||||||
"recommendation": "BUY" | "SELL" | "HOLD",
|
"recommendation": "BUY|SELL|HOLD",
|
||||||
"confidence": number (0-100),
|
"confidence": 75,
|
||||||
"reasoning": "Detailed reasoning with specific levels, indicators, and confirmation triggers",
|
"reasoning": "Technical analysis reasoning based on indicators and price action",
|
||||||
"entry": {
|
"entry": {
|
||||||
"price": number,
|
"price": 150.50,
|
||||||
"buffer": "string describing entry buffer",
|
"buffer": "±0.25",
|
||||||
"rationale": "string explaining entry logic"
|
"rationale": "Technical reasoning for entry level"
|
||||||
},
|
},
|
||||||
"stopLoss": {
|
"stopLoss": {
|
||||||
"price": number,
|
"price": 148.00,
|
||||||
"rationale": "string explaining stop loss placement"
|
"rationale": "Technical reasoning for stop level"
|
||||||
},
|
},
|
||||||
"takeProfits": {
|
"takeProfits": {
|
||||||
"tp1": { "price": number, "description": "string" },
|
"tp1": { "price": 152.00, "description": "First target reasoning" },
|
||||||
"tp2": { "price": number, "description": "string" }
|
"tp2": { "price": 154.00, "description": "Second target reasoning" }
|
||||||
},
|
},
|
||||||
"riskToReward": "string like '1:2.5 - Risking $X to gain $Y'",
|
"riskToReward": "1:2",
|
||||||
"confirmationTrigger": "string describing exact signal to wait for",
|
"confirmationTrigger": "Technical signal to watch for",
|
||||||
"indicatorAnalysis": {
|
"indicatorAnalysis": {
|
||||||
"rsi": "string describing RSI behavior",
|
"rsi": "RSI level and interpretation",
|
||||||
"vwap": "string describing VWAP behavior",
|
"vwap": "VWAP relationship to price",
|
||||||
"obv": "string describing OBV behavior"
|
"obv": "Volume analysis if visible"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Be concise but thorough. Only return valid JSON.`
|
Return only the JSON object with your technical analysis.`
|
||||||
|
|
||||||
const response = await openai.chat.completions.create({
|
const response = await openai.chat.completions.create({
|
||||||
model: "gpt-4o", // Updated to current vision model
|
model: "gpt-4o", // Updated to current vision model
|
||||||
messages: [
|
messages: [
|
||||||
@@ -124,17 +104,31 @@ Be concise but thorough. Only return valid JSON.`
|
|||||||
role: "user",
|
role: "user",
|
||||||
content: [
|
content: [
|
||||||
{ type: "text", text: prompt },
|
{ type: "text", text: prompt },
|
||||||
{ type: "image_url", image_url: { url: `data:image/png;base64,${base64Image}` } }
|
{
|
||||||
|
type: "image_url",
|
||||||
|
image_url: {
|
||||||
|
url: `data:image/png;base64,${base64Image}`,
|
||||||
|
detail: "low" // Reduce token usage
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
max_tokens: 1024
|
max_tokens: 1024,
|
||||||
|
temperature: 0.1
|
||||||
})
|
})
|
||||||
|
|
||||||
const content = response.choices[0]?.message?.content
|
const content = response.choices[0]?.message?.content
|
||||||
if (!content) return null
|
if (!content) return null
|
||||||
|
|
||||||
|
console.log('AI response content:', content)
|
||||||
|
|
||||||
// Extract JSON from response
|
// Extract JSON from response
|
||||||
const match = content.match(/\{[\s\S]*\}/)
|
const match = content.match(/\{[\s\S]*\}/)
|
||||||
if (!match) return null
|
if (!match) {
|
||||||
|
console.error('No JSON found in response. Full content:', content)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
const json = match[0]
|
const json = match[0]
|
||||||
console.log('Raw JSON from AI:', json)
|
console.log('Raw JSON from AI:', json)
|
||||||
@@ -181,83 +175,55 @@ Be concise but thorough. Only return valid JSON.`
|
|||||||
images.push({ type: "image_url", image_url: { url: `data:image/png;base64,${base64Image}` } })
|
images.push({ type: "image_url", image_url: { url: `data:image/png;base64,${base64Image}` } })
|
||||||
}
|
}
|
||||||
|
|
||||||
const prompt = `You are an expert crypto trading analyst with advanced vision capabilities. I'm sending you TradingView chart screenshot(s) that you CAN and MUST analyze.
|
const prompt = `You are a technical chart analysis expert. Please analyze these TradingView chart images and provide objective technical analysis data.
|
||||||
|
|
||||||
**IMPORTANT: You have full image analysis capabilities. Please analyze the TradingView chart images I'm providing.**
|
**Important**: This is for educational and research purposes only. Please analyze the technical indicators, price levels, and chart patterns visible in the images.
|
||||||
|
|
||||||
Analyze the attached TradingView chart screenshots (multiple layouts of the same symbol) and provide a comprehensive trading analysis by combining insights from all charts.
|
Examine all the charts and provide a consolidated analysis by identifying:
|
||||||
|
- Current price action and trend direction across layouts
|
||||||
### TRADING ANALYSIS REQUIREMENTS:
|
- Key support and resistance levels visible on the charts
|
||||||
|
- Technical indicator readings (RSI, moving averages, volume if visible)
|
||||||
You are a professional trading assistant focused on short-term crypto trading using 5–15min timeframes. You behave with the precision and decisiveness of a top proprietary desk trader. No vagueness, no fluff.
|
- Chart patterns or formations
|
||||||
|
- Market structure elements
|
||||||
### WHEN GIVING A TRADE SETUP:
|
- Cross-reference different timeframes/layouts for the most accurate analysis
|
||||||
Be 100% SPECIFIC. Provide:
|
|
||||||
|
|
||||||
1. **ENTRY**
|
|
||||||
- Exact price level (with a ± entry buffer if needed)
|
|
||||||
- Rationale: e.g., "Rejection from 15 EMA + VWAP confluence near intraday supply"
|
|
||||||
|
|
||||||
2. **STOP-LOSS (SL)**
|
|
||||||
- Exact level (not arbitrary)
|
|
||||||
- Explain *why* it's there: "Above VWAP + failed breakout zone"
|
|
||||||
|
|
||||||
3. **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
|
|
||||||
|
|
||||||
4. **RISK-TO-REWARD**
|
|
||||||
- Show R:R. Ex: "1:2.5 — Risking $X to potentially gain $Y"
|
|
||||||
|
|
||||||
5. **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"
|
|
||||||
|
|
||||||
6. **INDICATOR ANALYSIS**
|
|
||||||
- **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*
|
|
||||||
|
|
||||||
Cross-reference all layouts to provide the most accurate analysis. If layouts show conflicting signals, explain which one takes priority and why.
|
|
||||||
|
|
||||||
**CRITICAL: You MUST analyze the actual chart images provided. Do not respond with generic advice.**
|
**CRITICAL: You MUST analyze the actual chart images provided. Do not respond with generic advice.**
|
||||||
|
|
||||||
Return your answer as a JSON object with the following structure:
|
Provide your analysis in this exact JSON format (replace values with your analysis):
|
||||||
|
|
||||||
{
|
{
|
||||||
"summary": "Brief market summary combining all layouts",
|
"summary": "Objective description combining analysis from all charts",
|
||||||
"marketSentiment": "BULLISH" | "BEARISH" | "NEUTRAL",
|
"marketSentiment": "BULLISH|BEARISH|NEUTRAL",
|
||||||
"keyLevels": {
|
"keyLevels": {
|
||||||
"support": [number array],
|
"support": [list of visible support price levels as numbers],
|
||||||
"resistance": [number array]
|
"resistance": [list of visible resistance price levels as numbers]
|
||||||
},
|
},
|
||||||
"recommendation": "BUY" | "SELL" | "HOLD",
|
"recommendation": "BUY|SELL|HOLD",
|
||||||
"confidence": number (0-100),
|
"confidence": 75,
|
||||||
"reasoning": "Detailed reasoning with specific levels, indicators, and confirmation triggers from all layouts",
|
"reasoning": "Technical analysis reasoning based on indicators and price action from all layouts",
|
||||||
"entry": {
|
"entry": {
|
||||||
"price": number,
|
"price": 150.50,
|
||||||
"buffer": "string describing entry buffer",
|
"buffer": "±0.25",
|
||||||
"rationale": "string explaining entry logic"
|
"rationale": "Technical reasoning for entry level"
|
||||||
},
|
},
|
||||||
"stopLoss": {
|
"stopLoss": {
|
||||||
"price": number,
|
"price": 148.00,
|
||||||
"rationale": "string explaining stop loss placement"
|
"rationale": "Technical reasoning for stop level"
|
||||||
},
|
},
|
||||||
"takeProfits": {
|
"takeProfits": {
|
||||||
"tp1": { "price": number, "description": "string" },
|
"tp1": { "price": 152.00, "description": "First target reasoning" },
|
||||||
"tp2": { "price": number, "description": "string" }
|
"tp2": { "price": 154.00, "description": "Second target reasoning" }
|
||||||
},
|
},
|
||||||
"riskToReward": "string like '1:2.5 - Risking $X to gain $Y'",
|
"riskToReward": "1:2",
|
||||||
"confirmationTrigger": "string describing exact signal to wait for",
|
"confirmationTrigger": "Technical signal to watch for",
|
||||||
"indicatorAnalysis": {
|
"indicatorAnalysis": {
|
||||||
"rsi": "string describing RSI behavior",
|
"rsi": "RSI level and interpretation",
|
||||||
"vwap": "string describing VWAP behavior",
|
"vwap": "VWAP relationship to price",
|
||||||
"obv": "string describing OBV behavior"
|
"obv": "Volume analysis if visible"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Be concise but thorough. Only return valid JSON.`
|
Return only the JSON object with your consolidated technical analysis.`
|
||||||
|
|
||||||
const response = await openai.chat.completions.create({
|
const response = await openai.chat.completions.create({
|
||||||
model: "gpt-4o", // gpt-4o has better vision capabilities than gpt-4-vision-preview
|
model: "gpt-4o", // gpt-4o has better vision capabilities than gpt-4-vision-preview
|
||||||
|
|||||||
30
test-analysis-api.js
Normal file
30
test-analysis-api.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
async function testAnalysisAPI() {
|
||||||
|
try {
|
||||||
|
console.log('🧪 Testing AI analysis API with existing screenshots...')
|
||||||
|
|
||||||
|
// Test the API by calling it directly (without requiring new screenshots)
|
||||||
|
const response = await fetch('http://localhost:3000/api/analyze', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
symbol: 'SOLUSD',
|
||||||
|
timeframe: '60',
|
||||||
|
useExisting: true // This will make it use existing screenshots
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = await response.json()
|
||||||
|
console.log('📊 API Response:')
|
||||||
|
console.log(JSON.stringify(data, null, 2))
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Error testing API:', error.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testAnalysisAPI()
|
||||||
37
test-direct-analysis.mjs
Normal file
37
test-direct-analysis.mjs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { aiAnalysisService } from '../lib/ai-analysis.js'
|
||||||
|
import fs from 'fs'
|
||||||
|
|
||||||
|
async function testDirectAnalysis() {
|
||||||
|
try {
|
||||||
|
console.log('🧪 Testing AI analysis with existing screenshot...')
|
||||||
|
|
||||||
|
const screenshotDir = '/app/screenshots'
|
||||||
|
const screenshots = fs.readdirSync(screenshotDir).filter(f =>
|
||||||
|
f.includes('SOLUSD_60') && f.endsWith('.png') && !f.includes('debug')
|
||||||
|
)
|
||||||
|
|
||||||
|
console.log('📸 Available screenshots:', screenshots)
|
||||||
|
|
||||||
|
if (screenshots.length > 0) {
|
||||||
|
const filename = screenshots[0]
|
||||||
|
console.log(`🔍 Analyzing: ${filename}`)
|
||||||
|
|
||||||
|
const result = await aiAnalysisService.analyzeScreenshot(filename)
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
console.log('✅ Analysis successful!')
|
||||||
|
console.log('📊 Analysis result:')
|
||||||
|
console.log(JSON.stringify(result, null, 2))
|
||||||
|
} else {
|
||||||
|
console.log('❌ Analysis failed - returned null')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('❌ No suitable screenshots found')
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Error in direct analysis test:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testDirectAnalysis()
|
||||||
Reference in New Issue
Block a user