Files
trading_bot_v3/components/AIAnalysisPanel_new.tsx
mindesbunister e985a9ec6f 🚀 Fix Drift Protocol integration - Connection now working
 Key fixes:
- Bypass problematic SDK subscription that caused 410 Gone errors
- Use direct account verification without subscription
- Add fallback modes for better reliability
- Switch to Helius RPC endpoint for better rate limits
- Implement proper error handling and retry logic

🔧 Technical changes:
- Enhanced drift-trading.ts with no-subscription approach
- Added Drift API endpoints (/api/drift/login, /balance, /positions)
- Created DriftAccountStatus and DriftTradingPanel components
- Updated Dashboard.tsx to show Drift account status
- Added comprehensive test scripts for debugging

📊 Results:
- Connection Status: Connected 
- Account verification: Working 
- Balance retrieval: Working  (21.94 total collateral)
- Private key authentication: Working 
- User account: 3dG7wayp7b9NBMo92D2qL2sy1curSC4TTmskFpaGDrtA

🌐 RPC improvements:
- Using Helius RPC for better reliability
- Added fallback RPC options in .env
- Eliminated rate limiting issues
2025-07-13 00:20:01 +02:00

387 lines
16 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client"
import React, { useState } from 'react'
const layouts = (process.env.NEXT_PUBLIC_TRADINGVIEW_LAYOUTS || 'ai,Diy module').split(',').map(l => l.trim())
const timeframes = [
{ label: '1m', value: '1' },
{ label: '5m', value: '5' },
{ label: '15m', value: '15' },
{ label: '1h', value: '60' },
{ label: '4h', value: '240' },
{ label: '1d', value: 'D' },
{ label: '1w', value: 'W' },
{ label: '1M', value: 'M' },
]
const popularCoins = [
{ name: 'Bitcoin', symbol: 'BTCUSD', icon: '₿', color: 'from-orange-400 to-orange-600' },
{ name: 'Ethereum', symbol: 'ETHUSD', icon: 'Ξ', color: 'from-blue-400 to-blue-600' },
{ name: 'Solana', symbol: 'SOLUSD', icon: '◎', color: 'from-purple-400 to-purple-600' },
{ name: 'Sui', symbol: 'SUIUSD', icon: '🔷', color: 'from-cyan-400 to-cyan-600' },
{ name: 'Avalanche', symbol: 'AVAXUSD', icon: '🔺', color: 'from-red-400 to-red-600' },
{ name: 'Cardano', symbol: 'ADAUSD', icon: '♠', color: 'from-indigo-400 to-indigo-600' },
{ name: 'Polygon', symbol: 'MATICUSD', icon: '🔷', color: 'from-violet-400 to-violet-600' },
{ name: 'Chainlink', symbol: 'LINKUSD', icon: '🔗', color: 'from-blue-400 to-blue-600' },
]
export default function AIAnalysisPanel() {
const [symbol, setSymbol] = useState('BTCUSD')
const [selectedLayouts, setSelectedLayouts] = useState<string[]>([layouts[0]])
const [timeframe, setTimeframe] = useState('60')
const [loading, setLoading] = useState(false)
const [result, setResult] = useState<any>(null)
const [error, setError] = useState<string | null>(null)
// Helper function to safely render any value
const safeRender = (value: any): string => {
if (typeof value === 'string') return value
if (typeof value === 'number') return value.toString()
if (Array.isArray(value)) return value.join(', ')
if (typeof value === 'object' && value !== null) {
return JSON.stringify(value)
}
return String(value)
}
const toggleLayout = (layout: string) => {
setSelectedLayouts(prev =>
prev.includes(layout)
? prev.filter(l => l !== layout)
: [...prev, layout]
)
}
const quickAnalyze = async (coinSymbol: string) => {
setSymbol(coinSymbol)
setSelectedLayouts([layouts[0]]) // Use first layout
setLoading(true)
setError(null)
setResult(null)
try {
const res = await fetch('/api/analyze', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ symbol: coinSymbol, layouts: [layouts[0]], timeframe })
})
const data = await res.json()
if (!res.ok) throw new Error(data.error || 'Unknown error')
setResult(data)
} catch (e: any) {
setError(e.message)
}
setLoading(false)
}
async function handleAnalyze() {
setLoading(true)
setError(null)
setResult(null)
if (selectedLayouts.length === 0) {
setError('Please select at least one layout')
setLoading(false)
return
}
try {
const res = await fetch('/api/analyze', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ symbol, layouts: selectedLayouts, timeframe })
})
const data = await res.json()
if (!res.ok) throw new Error(data.error || 'Unknown error')
setResult(data)
} catch (e: any) {
setError(e.message)
}
setLoading(false)
}
return (
<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-cyan-400 to-blue-600 rounded-lg flex items-center justify-center mr-3">
🤖
</span>
AI Chart Analysis
</h2>
<div className="flex items-center space-x-2 text-sm text-gray-400">
<div className="w-2 h-2 bg-cyan-400 rounded-full animate-pulse"></div>
<span>AI Powered</span>
</div>
</div>
{/* Quick Coin Selection */}
<div className="mb-8">
<div className="flex items-center justify-between mb-4">
<h3 className="text-sm font-semibold text-gray-300 flex items-center">
<span className="w-4 h-4 bg-yellow-500 rounded-full mr-2"></span>
Quick Analysis
</h3>
<span className="text-xs text-gray-500">Click any coin for instant analysis</span>
</div>
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
{popularCoins.map(coin => (
<button
key={coin.symbol}
onClick={() => quickAnalyze(coin.symbol)}
disabled={loading}
className={`group relative p-4 rounded-xl border transition-all duration-300 ${
symbol === coin.symbol
? 'border-cyan-500 bg-cyan-500/10 shadow-lg shadow-cyan-500/20'
: 'border-gray-700 bg-gray-800/50 hover:border-gray-600 hover:bg-gray-800'
} ${loading ? 'opacity-50 cursor-not-allowed' : 'hover:scale-105 hover:shadow-lg'}`}
>
<div className={`w-10 h-10 bg-gradient-to-br ${coin.color} rounded-lg flex items-center justify-center mb-3 mx-auto text-white font-bold`}>
{coin.icon}
</div>
<div className="text-xs font-semibold text-white">{coin.name}</div>
<div className="text-xs text-gray-400 mt-1">{coin.symbol}</div>
{symbol === coin.symbol && (
<div className="absolute top-2 right-2 w-2 h-2 bg-cyan-400 rounded-full animate-pulse"></div>
)}
</button>
))}
</div>
</div>
{/* Advanced Controls */}
<div className="border-t border-gray-700 pt-6">
<h3 className="text-sm font-semibold text-gray-300 mb-4 flex items-center">
<span className="w-4 h-4 bg-purple-500 rounded-full mr-2"></span>
Advanced Analysis
</h3>
{/* Symbol and Timeframe */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
<div className="md:col-span-2">
<label className="block text-xs font-medium text-gray-400 mb-2">Trading Pair</label>
<input
className="w-full px-4 py-3 bg-gray-800/50 border border-gray-700 rounded-lg text-white placeholder-gray-500 focus:border-cyan-500 focus:outline-none focus:ring-2 focus:ring-cyan-500/20 transition-all"
value={symbol}
onChange={e => setSymbol(e.target.value.toUpperCase())}
placeholder="e.g., BTCUSD, ETHUSD"
/>
</div>
<div>
<label className="block text-xs font-medium text-gray-400 mb-2">Timeframe</label>
<select
className="w-full px-4 py-3 bg-gray-800/50 border border-gray-700 rounded-lg text-white focus:border-cyan-500 focus:outline-none focus:ring-2 focus:ring-cyan-500/20 transition-all"
value={timeframe}
onChange={e => setTimeframe(e.target.value)}
>
{timeframes.map(tf => (
<option key={tf.value} value={tf.value} className="bg-gray-800">
{tf.label}
</option>
))}
</select>
</div>
</div>
{/* Layout Selection */}
<div className="mb-6">
<label className="block text-xs font-medium text-gray-400 mb-3">Analysis Layouts</label>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
{layouts.map(layout => (
<label key={layout} className="group relative">
<input
type="checkbox"
checked={selectedLayouts.includes(layout)}
onChange={() => toggleLayout(layout)}
className="sr-only"
/>
<div className={`flex items-center p-3 rounded-lg border cursor-pointer transition-all ${
selectedLayouts.includes(layout)
? 'border-cyan-500 bg-cyan-500/10 text-cyan-300'
: 'border-gray-700 bg-gray-800/30 text-gray-300 hover:border-gray-600 hover:bg-gray-800/50'
}`}>
<div className={`w-4 h-4 rounded border-2 mr-3 flex items-center justify-center ${
selectedLayouts.includes(layout)
? 'border-cyan-500 bg-cyan-500'
: 'border-gray-600'
}`}>
{selectedLayouts.includes(layout) && (
<svg className="w-2 h-2 text-white" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clipRule="evenodd" />
</svg>
)}
</div>
<span className="text-sm font-medium">{layout}</span>
</div>
</label>
))}
</div>
{selectedLayouts.length > 0 && (
<div className="mt-3 p-3 bg-gray-800/30 rounded-lg">
<div className="text-xs text-gray-400">
Selected layouts: <span className="text-cyan-400">{selectedLayouts.join(', ')}</span>
</div>
</div>
)}
</div>
{/* Analyze Button */}
<button
className={`w-full py-3 px-6 rounded-lg font-semibold transition-all duration-300 ${
loading
? 'bg-gray-700 text-gray-400 cursor-not-allowed'
: 'btn-primary transform hover:scale-[1.02] active:scale-[0.98]'
}`}
onClick={handleAnalyze}
disabled={loading}
>
{loading ? (
<div className="flex items-center justify-center space-x-2">
<div className="spinner"></div>
<span>Analyzing Chart...</span>
</div>
) : (
<div className="flex items-center justify-center space-x-2">
<span>🚀</span>
<span>Start AI Analysis</span>
</div>
)}
</button>
</div>
{/* Results Section */}
{error && (
<div className="mt-6 p-4 bg-red-500/10 border border-red-500/30 rounded-lg">
<div className="flex items-start space-x-3">
<div className="w-5 h-5 text-red-400 mt-0.5"></div>
<div>
<h4 className="text-red-400 font-medium text-sm">Analysis Error</h4>
<p className="text-red-300 text-xs mt-1 opacity-90">{error}</p>
</div>
</div>
</div>
)}
{loading && (
<div className="mt-6 p-4 bg-cyan-500/10 border border-cyan-500/30 rounded-lg">
<div className="flex items-center space-x-3">
<div className="spinner border-cyan-500"></div>
<div>
<h4 className="text-cyan-400 font-medium text-sm">AI Processing</h4>
<p className="text-cyan-300 text-xs mt-1 opacity-90">
Analyzing {symbol} on {timeframe} timeframe...
</p>
</div>
</div>
</div>
)}
{result && (
<div className="mt-6 space-y-4">
<div className="flex items-center justify-between">
<h3 className="text-lg font-bold text-white flex items-center">
<span className="w-6 h-6 bg-gradient-to-br from-green-400 to-emerald-600 rounded-lg flex items-center justify-center mr-2 text-sm">
</span>
Analysis Complete
</h3>
{result.layoutsAnalyzed && (
<div className="text-xs text-gray-400">
Layouts: {result.layoutsAnalyzed.join(', ')}
</div>
)}
</div>
<div className="grid gap-4">
{/* Summary */}
<div className="p-4 bg-gradient-to-r from-gray-800/50 to-gray-700/50 rounded-lg border border-gray-700">
<h4 className="text-sm font-semibold text-gray-300 mb-2 flex items-center">
<span className="w-4 h-4 bg-blue-500 rounded-full mr-2"></span>
Market Summary
</h4>
<p className="text-white text-sm leading-relaxed">{safeRender(result.summary)}</p>
</div>
{/* Key Metrics */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="p-4 bg-gradient-to-br from-green-500/10 to-emerald-500/10 border border-green-500/30 rounded-lg">
<h4 className="text-sm font-semibold text-green-400 mb-2">Market Sentiment</h4>
<p className="text-white font-medium">{safeRender(result.marketSentiment)}</p>
</div>
<div className="p-4 bg-gradient-to-br from-blue-500/10 to-cyan-500/10 border border-blue-500/30 rounded-lg">
<h4 className="text-sm font-semibold text-blue-400 mb-2">Recommendation</h4>
<p className="text-white font-medium">{safeRender(result.recommendation)}</p>
{result.confidence && (
<p className="text-cyan-300 text-xs mt-1">{safeRender(result.confidence)}% confidence</p>
)}
</div>
</div>
{/* Trading Levels */}
{result.keyLevels && (
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="p-4 bg-gradient-to-br from-red-500/10 to-rose-500/10 border border-red-500/30 rounded-lg">
<h4 className="text-sm font-semibold text-red-400 mb-2">Resistance Levels</h4>
<p className="text-red-300 font-mono text-sm">
{result.keyLevels.resistance?.join(', ') || 'None identified'}
</p>
</div>
<div className="p-4 bg-gradient-to-br from-green-500/10 to-emerald-500/10 border border-green-500/30 rounded-lg">
<h4 className="text-sm font-semibold text-green-400 mb-2">Support Levels</h4>
<p className="text-green-300 font-mono text-sm">
{result.keyLevels.support?.join(', ') || 'None identified'}
</p>
</div>
</div>
)}
{/* Trading Setup */}
{(result.entry || result.stopLoss || result.takeProfits) && (
<div className="p-4 bg-gradient-to-br from-purple-500/10 to-violet-500/10 border border-purple-500/30 rounded-lg">
<h4 className="text-sm font-semibold text-purple-400 mb-3">Trading Setup</h4>
<div className="grid grid-cols-1 md:grid-cols-3 gap-3">
{result.entry && (
<div>
<span className="text-xs text-gray-400">Entry Point</span>
<p className="text-yellow-300 font-mono font-semibold">
${safeRender(result.entry.price || result.entry)}
</p>
{result.entry.rationale && (
<p className="text-xs text-gray-300 mt-1">{safeRender(result.entry.rationale)}</p>
)}
</div>
)}
{result.stopLoss && (
<div>
<span className="text-xs text-gray-400">Stop Loss</span>
<p className="text-red-300 font-mono font-semibold">
${safeRender(result.stopLoss.price || result.stopLoss)}
</p>
{result.stopLoss.rationale && (
<p className="text-xs text-gray-300 mt-1">{safeRender(result.stopLoss.rationale)}</p>
)}
</div>
)}
{result.takeProfits && (
<div>
<span className="text-xs text-gray-400">Take Profit</span>
<p className="text-green-300 font-mono font-semibold">
{typeof result.takeProfits === 'object'
? Object.values(result.takeProfits).map(tp => `$${safeRender(tp)}`).join(', ')
: `$${safeRender(result.takeProfits)}`}
</p>
</div>
)}
</div>
</div>
)}
</div>
</div>
)}
</div>
)
}