168 lines
6.9 KiB
JavaScript
168 lines
6.9 KiB
JavaScript
import { useState, useEffect } from 'react';
|
|
import { Badge } from '../ui/Badge';
|
|
import { TrendingUp, TrendingDown, Target, BarChart3 } from 'lucide-react';
|
|
import { getApiUrl } from '@/config/api';
|
|
|
|
export default function PerformanceTrackingPanel() {
|
|
const [stats, setStats] = useState({
|
|
totalSignals: 0,
|
|
highConviction: 0,
|
|
currentlyTracking: 0,
|
|
winRate: {
|
|
all: 64.2,
|
|
highScore: 76.3,
|
|
tapeAligned: 71.8,
|
|
patternMatched: 79.1
|
|
},
|
|
avgPerformance: {
|
|
avgWinner: 2.3,
|
|
avgLoser: -1.2,
|
|
rrRatio: 1.9,
|
|
expectancy: 1.1
|
|
}
|
|
});
|
|
|
|
useEffect(() => {
|
|
const fetchStats = async () => {
|
|
try {
|
|
const response = await fetch(getApiUrl('/api/performance/stats'));
|
|
|
|
// Check if response is ok
|
|
if (!response.ok) {
|
|
// If endpoint doesn't exist (404), silently fail and keep default stats
|
|
if (response.status === 404) {
|
|
console.warn('Performance stats endpoint not available');
|
|
return;
|
|
}
|
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
}
|
|
|
|
const result = await response.json();
|
|
|
|
if (result.success && result.data) {
|
|
setStats({
|
|
totalSignals: result.data.totalSignals || 0,
|
|
highConviction: result.data.highConviction || 0,
|
|
currentlyTracking: result.data.currentlyTracking || 0,
|
|
winRate: {
|
|
all: result.data.winRate?.all || 0,
|
|
highScore: result.data.winRate?.highScore || 0,
|
|
tapeAligned: result.data.winRate?.tapeAligned || 0,
|
|
patternMatched: result.data.winRate?.patternMatched || 0
|
|
},
|
|
avgPerformance: {
|
|
avgWinner: result.data.avgPerformance?.avgWinner || 0,
|
|
avgLoser: result.data.avgPerformance?.avgLoser || 0,
|
|
rrRatio: result.data.avgPerformance?.rrRatio || 0,
|
|
expectancy: result.data.avgPerformance?.expectancy || 0
|
|
}
|
|
});
|
|
} else {
|
|
throw new Error(result.error || 'Failed to fetch stats');
|
|
}
|
|
} catch (error) {
|
|
// Only log if it's not a 404 (endpoint doesn't exist)
|
|
if (!error.message.includes('404')) {
|
|
console.error('Failed to fetch performance stats:', error);
|
|
}
|
|
// Keep existing stats on error (don't reset to 0)
|
|
}
|
|
};
|
|
|
|
fetchStats();
|
|
// Refresh every 5 minutes
|
|
const interval = setInterval(fetchStats, 5 * 60 * 1000);
|
|
return () => clearInterval(interval);
|
|
}, []);
|
|
|
|
return (
|
|
<div className="bg-slate-900/50 backdrop-blur-sm rounded-lg border border-slate-800/50 p-4 shadow-lg">
|
|
<div className="flex items-center justify-between mb-4">
|
|
<div className="flex items-center gap-2">
|
|
<BarChart3 className="w-5 h-5 text-blue-400" />
|
|
<h3 className="font-semibold text-slate-100">📊 TODAY'S SIGNALS</h3>
|
|
</div>
|
|
<Badge variant="outline" className="text-xs">
|
|
Live
|
|
</Badge>
|
|
</div>
|
|
|
|
<div className="space-y-4">
|
|
{/* Signal Counts */}
|
|
<div className="grid grid-cols-3 gap-3">
|
|
<div className="bg-slate-800/50 rounded p-3">
|
|
<div className="text-xs text-slate-400 mb-1">Total Signals</div>
|
|
<div className="text-lg font-bold text-slate-100">{stats.totalSignals}</div>
|
|
</div>
|
|
<div className="bg-slate-800/50 rounded p-3">
|
|
<div className="text-xs text-slate-400 mb-1">High Conviction (5+)</div>
|
|
<div className="text-lg font-bold text-green-400">{stats.highConviction}</div>
|
|
</div>
|
|
<div className="bg-slate-800/50 rounded p-3">
|
|
<div className="text-xs text-slate-400 mb-1">Tracking</div>
|
|
<div className="text-lg font-bold text-blue-400">{stats.currentlyTracking}</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Win Rate Section */}
|
|
<div className="bg-slate-800/30 rounded p-4 border border-slate-700/50">
|
|
<div className="flex items-center gap-2 mb-3">
|
|
<Target className="w-4 h-4 text-green-400" />
|
|
<h4 className="text-sm font-semibold text-slate-300">🎯 WIN RATE (Last 30 Days)</h4>
|
|
</div>
|
|
<div className="space-y-2 text-xs">
|
|
<div className="flex justify-between items-center">
|
|
<span className="text-slate-400">All Signals:</span>
|
|
<span className="text-slate-200 font-semibold">{stats.winRate.all}%</span>
|
|
</div>
|
|
<div className="flex justify-between items-center">
|
|
<span className="text-slate-400">High Score (5+):</span>
|
|
<span className="text-green-400 font-semibold">{stats.winRate.highScore}%</span>
|
|
</div>
|
|
<div className="flex justify-between items-center">
|
|
<span className="text-slate-400">Tape Aligned:</span>
|
|
<span className="text-blue-400 font-semibold">{stats.winRate.tapeAligned}%</span>
|
|
</div>
|
|
<div className="flex justify-between items-center">
|
|
<span className="text-slate-400">Pattern Matched:</span>
|
|
<span className="text-yellow-400 font-semibold">{stats.winRate.patternMatched}%</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Average Performance */}
|
|
<div className="bg-slate-800/30 rounded p-4 border border-slate-700/50">
|
|
<div className="flex items-center gap-2 mb-3">
|
|
<TrendingUp className="w-4 h-4 text-blue-400" />
|
|
<h4 className="text-sm font-semibold text-slate-300">💰 AVG PERFORMANCE</h4>
|
|
</div>
|
|
<div className="space-y-2 text-xs">
|
|
<div className="flex justify-between items-center">
|
|
<span className="text-slate-400">Avg Winner:</span>
|
|
<span className="text-green-400 font-semibold">+{stats.avgPerformance.avgWinner}%</span>
|
|
</div>
|
|
<div className="flex justify-between items-center">
|
|
<span className="text-slate-400">Avg Loser:</span>
|
|
<span className="text-red-400 font-semibold">{stats.avgPerformance.avgLoser}%</span>
|
|
</div>
|
|
<div className="flex justify-between items-center">
|
|
<span className="text-slate-400">R:R Ratio:</span>
|
|
<span className="text-slate-200 font-semibold">{stats.avgPerformance.rrRatio}:1</span>
|
|
</div>
|
|
<div className="flex justify-between items-center pt-2 border-t border-slate-700/50">
|
|
<span className="text-slate-300 font-semibold">Expectancy:</span>
|
|
<span className="text-green-400 font-bold">+{stats.avgPerformance.expectancy}% per trade</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Action Button */}
|
|
<button className="w-full px-4 py-2 bg-blue-600/20 hover:bg-blue-600/30 border border-blue-500/50 rounded-md text-sm text-blue-400 font-medium transition-colors">
|
|
View Full Stats
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|