From 85791a2e82dfbfc542adb3e4736b4a4604eb7bcd Mon Sep 17 00:00:00 2001 From: mindesbunister Date: Sun, 13 Jul 2025 18:07:32 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=80=20Enhanced=20Multi-Timeframe=20Ana?= =?UTF-8?q?lysis=20with=20Smart=20Defaults?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit โœจ Major UI/UX Improvements: - AI + DIY layouts now default selections for comprehensive analysis - Multi-timeframe selection support for broader market outlook - Quick timeframe presets: Scalping, Day Trading, Swing, Position - Combined coin + timeframe selection workflow ๐Ÿ“Š Enhanced Analysis Features: - Multiple timeframe analysis in single request - Smart timeframe grouping (5m+15m+1h for scalping, etc.) - Cross-timeframe consensus display - Individual timeframe result breakdown - Visual timeframe selection with active indicators ๐ŸŽจ Improved User Experience: - Quick action buttons for instant multi-timeframe analysis - Clear selection indicators and counters - Preset combinations for different trading styles - Streamlined workflow: Select presets โ†’ Pick coin โ†’ Analyze - Beautiful multi-timeframe result visualization ๐Ÿ”ง Technical Enhancements: - Support for analyzing 1-8 timeframes simultaneously - Automatic delay between requests to prevent rate limiting - Error handling for individual timeframe failures - Responsive grid layouts for different screen sizes --- components/AIAnalysisPanel.tsx | 382 +++++++++++++++++++++++++-------- 1 file changed, 288 insertions(+), 94 deletions(-) diff --git a/components/AIAnalysisPanel.tsx b/components/AIAnalysisPanel.tsx index 57bb636..4f69e9a 100644 --- a/components/AIAnalysisPanel.tsx +++ b/components/AIAnalysisPanel.tsx @@ -26,8 +26,8 @@ const popularCoins = [ export default function AIAnalysisPanel() { const [symbol, setSymbol] = useState('BTCUSD') - const [selectedLayouts, setSelectedLayouts] = useState([layouts[0]]) - const [timeframe, setTimeframe] = useState('60') + const [selectedLayouts, setSelectedLayouts] = useState(['ai', 'diy']) // Default to both AI and DIY + const [selectedTimeframes, setSelectedTimeframes] = useState(['60']) // Support multiple timeframes const [loading, setLoading] = useState(false) const [result, setResult] = useState(null) const [error, setError] = useState(null) @@ -51,32 +51,79 @@ export default function AIAnalysisPanel() { ) } - const performAnalysis = async (analysisSymbol = symbol, analysisTimeframe = timeframe) => { - if (loading || selectedLayouts.length === 0) return + const toggleTimeframe = (timeframe: string) => { + setSelectedTimeframes(prev => + prev.includes(timeframe) + ? prev.filter(tf => tf !== timeframe) + : [...prev, timeframe] + ) + } + + const performAnalysis = async (analysisSymbol = symbol, analysisTimeframes = selectedTimeframes) => { + if (loading || selectedLayouts.length === 0 || analysisTimeframes.length === 0) return setLoading(true) setError(null) setResult(null) try { - const response = await fetch('/api/enhanced-screenshot', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - symbol: analysisSymbol, - timeframe: analysisTimeframe, - layouts: selectedLayouts, - analyze: true // Request AI analysis of captured screenshots + if (analysisTimeframes.length === 1) { + // Single timeframe analysis + const response = await fetch('/api/enhanced-screenshot', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + symbol: analysisSymbol, + timeframe: analysisTimeframes[0], + layouts: selectedLayouts, + analyze: true + }) }) - }) - const data = await response.json() - - if (!response.ok) { - throw new Error(data.error || 'Analysis failed') + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || 'Analysis failed') + } + + setResult(data) + } else { + // Multiple timeframe analysis + const results = [] + + for (const tf of analysisTimeframes) { + console.log(`๐Ÿงช Analyzing timeframe: ${timeframes.find(t => t.value === tf)?.label || tf}`) + + 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: timeframes.find(t => t.value === tf)?.label || tf, + success: response.ok, + result + }) + + // Small delay between requests + await new Promise(resolve => setTimeout(resolve, 2000)) + } + + setResult({ + type: 'multi_timeframe', + symbol: analysisSymbol, + summary: `Analyzed ${results.length} timeframes for ${analysisSymbol}`, + results + }) } - - setResult(data) } catch (err) { setError(err instanceof Error ? err.message : 'Failed to perform analysis') } finally { @@ -84,59 +131,34 @@ export default function AIAnalysisPanel() { } } - const quickAnalyze = async (coinSymbol: string) => { + const quickAnalyze = async (coinSymbol: string, quickTimeframes = selectedTimeframes) => { setSymbol(coinSymbol) if (!loading) { - await performAnalysis(coinSymbol) + await performAnalysis(coinSymbol, quickTimeframes) } } const quickTimeframeTest = async (testTimeframe: string) => { - setTimeframe(testTimeframe) - if (!loading && symbol) { - await performAnalysis(symbol, testTimeframe) + // Toggle the timeframe in selection instead of replacing + const newTimeframes = selectedTimeframes.includes(testTimeframe) + ? selectedTimeframes.filter(tf => tf !== testTimeframe) + : [...selectedTimeframes, testTimeframe] + + setSelectedTimeframes(newTimeframes) + + if (!loading && symbol && newTimeframes.length > 0) { + await performAnalysis(symbol, newTimeframes) } } const testAllTimeframes = async () => { if (loading) return - setLoading(true) - setError(null) - const results = [] + const allTimeframeValues = timeframes.map(tf => tf.value) + setSelectedTimeframes(allTimeframeValues) - try { - for (const tf of timeframes) { - console.log(`๐Ÿงช Testing timeframe: ${tf.label}`) - setTimeframe(tf.value) - - const response = await fetch('/api/enhanced-screenshot', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - symbol, - timeframe: tf.value, - layouts: selectedLayouts, - analyze: true // Request AI analysis for timeframe testing too - }) - }) - - const result = await response.json() - results.push({ timeframe: tf.label, success: response.ok, result }) - - // Small delay between tests - await new Promise(resolve => setTimeout(resolve, 2000)) - } - - setResult({ - type: 'timeframe_test', - summary: `Tested ${results.length} timeframes`, - results - }) - } catch (err) { - setError(err instanceof Error ? err.message : 'Timeframe testing failed') - } finally { - setLoading(false) + if (!loading && symbol) { + await performAnalysis(symbol, allTimeframeValues) } } @@ -159,32 +181,70 @@ export default function AIAnalysisPanel() { - {/* Quick Coin Selection */} + {/* Quick Coin & Timeframe Analysis */}

Quick Analysis

- Click any coin for instant analysis + Select coin + timeframe combo for instant analysis
+ + {/* Quick Timeframe Presets */} +
+ +
+ + + + +
+
+ + {/* Coin Selection */}
{popularCoins.map(coin => ( ))}
- +
+ + +
{/* Analyze Button */} @@ -347,13 +448,106 @@ export default function AIAnalysisPanel() {

AI Processing

- Analyzing {symbol} on {timeframe} timeframe... + Analyzing {symbol} on {selectedTimeframes.length === 1 + ? `${timeframes.find(tf => tf.value === selectedTimeframes[0])?.label} timeframe` + : `${selectedTimeframes.length} timeframes` + }...

)} + {result && result.type === 'multi_timeframe' && ( +
+
+

+ + ๐Ÿ“Š + + Multi-Timeframe Analysis +

+
+ {result.symbol} โ€ข {result.results.length} timeframes +
+
+ +
+

Analysis Summary

+

{result.summary}

+
+ +
+ {result.results.map((timeframeResult: any, index: number) => ( +
+
+
+ {timeframeResult.success ? 'โœ…' : 'โŒ'} {timeframeResult.timeframeLabel} Timeframe +
+ + {timeframeResult.success ? 'Analysis Complete' : 'Failed'} + +
+ + {timeframeResult.success && timeframeResult.result.analysis && ( +
+
+
Sentiment
+
+ {safeRender(timeframeResult.result.analysis.marketSentiment)} +
+
+
+
Recommendation
+
+ {safeRender(timeframeResult.result.analysis.recommendation)} +
+
+
+
Confidence
+
+ {safeRender(timeframeResult.result.analysis.confidence)}% +
+
+
+ )} + + {timeframeResult.success && timeframeResult.result.analysis?.entry && ( +
+
Entry Setup
+
+ ๐Ÿ“ ${safeRender(timeframeResult.result.analysis.entry.price)} + {timeframeResult.result.analysis.entry.buffer && ( + + {safeRender(timeframeResult.result.analysis.entry.buffer)} + + )} +
+ {timeframeResult.result.analysis.stopLoss && ( +
+ ๐Ÿ›‘ SL: ${safeRender(timeframeResult.result.analysis.stopLoss.price)} +
+ )} +
+ )} + + {!timeframeResult.success && ( +
+ Analysis failed for this timeframe +
+ )} +
+ ))} +
+
+ )} + {result && result.analysis && (