fix: implement proper multi-timeframe batch analysis

- Create /api/batch-analysis endpoint that collects ALL screenshots first
- Then sends all screenshots to AI for comprehensive analysis
- Fixes issue where individual timeframes were analyzed immediately
- Multi-timeframe analysis now provides cross-timeframe consensus
- Update AIAnalysisPanel to use batch analysis for multiple timeframes
- Maintains backward compatibility with single timeframe analysis
This commit is contained in:
mindesbunister
2025-07-18 18:32:08 +02:00
parent bd49c65867
commit 2bdf9e2b41
6 changed files with 413 additions and 89 deletions

View File

@@ -251,68 +251,57 @@ export default function AIAnalysisPanel({ onAnalysisComplete }: AIAnalysisPanelP
onAnalysisComplete(data.analysis, analysisSymbol)
}
} else {
// Multiple timeframe analysis
const results = []
// Multiple timeframe analysis - use batch analysis endpoint
console.log(`🧪 Starting batch analysis for ${analysisTimeframes.length} timeframes`)
for (let i = 0; i < analysisTimeframes.length; i++) {
const tf = analysisTimeframes[i]
const timeframeLabel = timeframes.find(t => t.value === tf)?.label || tf
console.log(`🧪 Analyzing timeframe: ${timeframeLabel}`)
const response = await fetch('/api/enhanced-screenshot', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
symbol: analysisSymbol,
timeframe: tf,
layouts: selectedLayouts,
analyze: true
})
})
const result = await response.json()
results.push({
timeframe: tf,
timeframeLabel,
success: response.ok,
result
const response = await fetch('/api/batch-analysis', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
symbol: analysisSymbol,
timeframes: analysisTimeframes,
layouts: selectedLayouts,
analyze: true
})
})
// Start progress tracking for the first timeframe session
if (i === 0 && result.sessionId) {
startProgressTracking(result.sessionId)
}
// Update timeframe progress manually for multi-timeframe
setProgress(prev => prev ? {
...prev,
timeframeProgress: {
current: i + 1,
total: analysisTimeframes.length,
currentTimeframe: timeframeLabel
}
} : null)
// Small delay between requests
await new Promise(resolve => setTimeout(resolve, 1000))
}
const data = await response.json()
const multiResult = {
if (!response.ok) {
throw new Error(data.error || 'Batch analysis failed')
}
// Start real-time progress tracking if sessionId is provided
if (data.sessionId) {
startProgressTracking(data.sessionId)
}
// Convert batch analysis result to compatible format
const batchResult = {
type: 'multi_timeframe',
symbol: analysisSymbol,
summary: `Analyzed ${results.length} timeframes for ${analysisSymbol}`,
results
summary: data.summary,
analysis: data.analysis, // Comprehensive analysis of ALL screenshots
totalScreenshots: data.totalScreenshots,
results: data.screenshotResults?.map((sr: any) => ({
timeframe: sr.timeframe,
timeframeLabel: sr.timeframeLabel,
success: sr.success,
result: {
screenshots: sr.screenshots?.map((path: string) => ({
url: `/screenshots/${path.split('/').pop()}`,
timestamp: Date.now()
})) || [],
analysis: sr.timeframe === analysisTimeframes[0] ? data.analysis : null // Only show comprehensive analysis on first timeframe
}
})) || []
}
setResult(multiResult)
setResult(batchResult)
// Call the callback with the first successful analysis result if provided
if (onAnalysisComplete) {
const firstSuccessfulResult = results.find(r => r.success && r.result?.analysis)
if (firstSuccessfulResult) {
onAnalysisComplete(firstSuccessfulResult.result.analysis, analysisSymbol)
}
// Call the callback with the comprehensive analysis result if provided
if (onAnalysisComplete && data.analysis) {
onAnalysisComplete(data.analysis, analysisSymbol)
}
}
} catch (err) {
@@ -1397,15 +1386,28 @@ export default function AIAnalysisPanel({ onAnalysisComplete }: AIAnalysisPanelP
</div>
)}
{/* Position Calculator */}
{result && result.analysis && (
<div className="mt-6">
{/* Position Calculator - Always Show */}
<div className="mt-6">
<div className="card card-gradient">
<div className="flex items-center justify-between mb-6">
<h2 className="text-xl font-bold text-white flex items-center">
<span className="w-8 h-8 bg-gradient-to-br from-green-400 to-emerald-600 rounded-lg flex items-center justify-center mr-3">
📊
</span>
Position Calculator
</h2>
<div className="flex items-center space-x-2 text-sm text-gray-400">
<div className="w-2 h-2 bg-green-400 rounded-full animate-pulse"></div>
<span>Live Calculator</span>
</div>
</div>
<PositionCalculator
analysis={result.analysis}
analysis={result?.analysis || null}
currentPrice={
result.analysis.entry?.price ||
result.analysis.entry ||
(typeof result.analysis.entry === 'string' ? parseFloat(result.analysis.entry.replace(/[^0-9.-]+/g, '')) : 0) ||
result?.analysis?.entry?.price ||
result?.analysis?.entry ||
(typeof result?.analysis?.entry === 'string' ? parseFloat(result?.analysis?.entry.replace(/[^0-9.-]+/g, '')) : 0) ||
currentPrice ||
0
}
@@ -1415,7 +1417,7 @@ export default function AIAnalysisPanel({ onAnalysisComplete }: AIAnalysisPanelP
}}
/>
</div>
)}
</div>
{result && !result.analysis && result.screenshots && (
<div className="mt-6 p-4 bg-yellow-500/10 border border-yellow-500/30 rounded-lg">