Spaces:
Running
Running
| import React from 'react'; | |
| import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; | |
| import { Badge } from '@/components/ui/badge'; | |
| import { | |
| BarChart, | |
| Bar, | |
| XAxis, | |
| YAxis, | |
| CartesianGrid, | |
| Tooltip, | |
| ResponsiveContainer, | |
| LineChart, | |
| Line, | |
| PieChart, | |
| Pie, | |
| Cell | |
| } from 'recharts'; | |
| import { | |
| TrendingUp, | |
| TrendingDown, | |
| Activity, | |
| Target, | |
| DollarSign, | |
| Percent | |
| } from 'lucide-react'; | |
| // Mock data for demonstration | |
| const performanceData = [ | |
| { date: '2024-01-01', profit: 120, loss: -30, trades: 8 }, | |
| { date: '2024-01-02', profit: 85, loss: -45, trades: 12 }, | |
| { date: '2024-01-03', profit: 95, loss: -20, trades: 6 }, | |
| { date: '2024-01-04', profit: 140, loss: -60, trades: 15 }, | |
| { date: '2024-01-05', profit: 110, loss: -25, trades: 9 }, | |
| { date: '2024-01-06', profit: 165, loss: -40, trades: 11 }, | |
| { date: '2024-01-07', profit: 190, loss: -55, trades: 14 } | |
| ]; | |
| const portfolioData = [ | |
| { name: 'SOL', value: 45, color: '#00D4AA' }, | |
| { name: 'USDC', value: 30, color: '#3B82F6' }, | |
| { name: 'RAY', value: 15, color: '#8B5CF6' }, | |
| { name: 'Others', value: 10, color: '#F59E0B' } | |
| ]; | |
| const tradingPairs = [ | |
| { pair: 'SOL/USDC', trades: 24, pnl: 340.50, winRate: 75 }, | |
| { pair: 'RAY/SOL', trades: 18, pnl: -125.30, winRate: 44 }, | |
| { pair: 'ORCA/USDC', trades: 12, pnl: 89.20, winRate: 67 }, | |
| { pair: 'BONK/SOL', trades: 8, pnl: 156.80, winRate: 88 } | |
| ]; | |
| export const PerformanceTracker: React.FC = () => { | |
| const totalPnL = performanceData.reduce((acc, day) => acc + day.profit + day.loss, 0); | |
| const totalTrades = performanceData.reduce((acc, day) => acc + day.trades, 0); | |
| const winningTrades = Math.floor(totalTrades * 0.685); // 68.5% win rate | |
| return ( | |
| <div className="space-y-6"> | |
| {/* Performance Overview */} | |
| <div className="grid grid-cols-1 lg:grid-cols-2 gap-6"> | |
| <Card className="bg-gradient-card border-border/50"> | |
| <CardHeader> | |
| <CardTitle className="flex items-center gap-2"> | |
| <TrendingUp className="h-5 w-5 text-primary" /> | |
| Daily P&L Trend | |
| </CardTitle> | |
| </CardHeader> | |
| <CardContent> | |
| <ResponsiveContainer width="100%" height={300}> | |
| <BarChart data={performanceData}> | |
| <CartesianGrid strokeDasharray="3 3" stroke="hsl(var(--border))" /> | |
| <XAxis | |
| dataKey="date" | |
| stroke="hsl(var(--muted-foreground))" | |
| fontSize={12} | |
| tickFormatter={(value) => new Date(value).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })} | |
| /> | |
| <YAxis stroke="hsl(var(--muted-foreground))" fontSize={12} /> | |
| <Tooltip | |
| contentStyle={{ | |
| backgroundColor: 'hsl(var(--card))', | |
| border: '1px solid hsl(var(--border))', | |
| borderRadius: 'var(--radius)' | |
| }} | |
| /> | |
| <Bar dataKey="profit" fill="hsl(var(--profit))" /> | |
| <Bar dataKey="loss" fill="hsl(var(--loss))" /> | |
| </BarChart> | |
| </ResponsiveContainer> | |
| </CardContent> | |
| </Card> | |
| <Card className="bg-gradient-card border-border/50"> | |
| <CardHeader> | |
| <CardTitle className="flex items-center gap-2"> | |
| <Activity className="h-5 w-5 text-primary" /> | |
| Portfolio Allocation | |
| </CardTitle> | |
| </CardHeader> | |
| <CardContent> | |
| <ResponsiveContainer width="100%" height={300}> | |
| <PieChart> | |
| <Pie | |
| data={portfolioData} | |
| cx="50%" | |
| cy="50%" | |
| outerRadius={80} | |
| dataKey="value" | |
| > | |
| {portfolioData.map((entry, index) => ( | |
| <Cell key={`cell-${index}`} fill={entry.color} /> | |
| ))} | |
| </Pie> | |
| <Tooltip | |
| contentStyle={{ | |
| backgroundColor: 'hsl(var(--card))', | |
| border: '1px solid hsl(var(--border))', | |
| borderRadius: 'var(--radius)' | |
| }} | |
| /> | |
| </PieChart> | |
| </ResponsiveContainer> | |
| <div className="grid grid-cols-2 gap-2 mt-4"> | |
| {portfolioData.map((item) => ( | |
| <div key={item.name} className="flex items-center gap-2"> | |
| <div | |
| className="w-3 h-3 rounded-full" | |
| style={{ backgroundColor: item.color }} | |
| /> | |
| <span className="text-sm">{item.name}</span> | |
| <span className="text-sm text-muted-foreground">{item.value}%</span> | |
| </div> | |
| ))} | |
| </div> | |
| </CardContent> | |
| </Card> | |
| </div> | |
| {/* Trading Pairs Performance */} | |
| <Card className="bg-gradient-card border-border/50"> | |
| <CardHeader> | |
| <CardTitle className="flex items-center gap-2"> | |
| <Target className="h-5 w-5 text-primary" /> | |
| Trading Pairs Performance | |
| </CardTitle> | |
| </CardHeader> | |
| <CardContent> | |
| <div className="space-y-4"> | |
| {tradingPairs.map((pair, index) => ( | |
| <div | |
| key={pair.pair} | |
| className="flex items-center justify-between p-4 rounded-lg border bg-secondary/30 animate-fade-in" | |
| style={{ animationDelay: `${index * 0.1}s` }} | |
| > | |
| <div className="flex items-center gap-4"> | |
| <div className="font-mono font-semibold">{pair.pair}</div> | |
| <Badge variant="outline" className="text-xs"> | |
| {pair.trades} trades | |
| </Badge> | |
| </div> | |
| <div className="flex items-center gap-6"> | |
| <div className="text-right"> | |
| <div className={`font-bold ${pair.pnl >= 0 ? 'text-profit' : 'text-loss'}`}> | |
| {pair.pnl >= 0 ? '+' : ''}${pair.pnl.toFixed(2)} | |
| </div> | |
| <div className="text-xs text-muted-foreground">P&L</div> | |
| </div> | |
| <div className="text-right"> | |
| <div className={`font-bold ${pair.winRate >= 60 ? 'text-profit' : pair.winRate >= 40 ? 'text-warning' : 'text-loss'}`}> | |
| {pair.winRate}% | |
| </div> | |
| <div className="text-xs text-muted-foreground">Win Rate</div> | |
| </div> | |
| </div> | |
| </div> | |
| ))} | |
| </div> | |
| </CardContent> | |
| </Card> | |
| {/* Summary Stats */} | |
| <div className="grid grid-cols-1 md:grid-cols-4 gap-4"> | |
| <Card className="bg-gradient-card border-border/50"> | |
| <CardContent className="p-4"> | |
| <div className="flex items-center gap-2"> | |
| <DollarSign className="h-5 w-5 text-profit" /> | |
| <div> | |
| <p className="text-sm text-muted-foreground">Total P&L</p> | |
| <p className={`text-lg font-bold ${totalPnL >= 0 ? 'text-profit' : 'text-loss'}`}> | |
| {totalPnL >= 0 ? '+' : ''}${totalPnL.toFixed(2)} | |
| </p> | |
| </div> | |
| </div> | |
| </CardContent> | |
| </Card> | |
| <Card className="bg-gradient-card border-border/50"> | |
| <CardContent className="p-4"> | |
| <div className="flex items-center gap-2"> | |
| <Activity className="h-5 w-5 text-info" /> | |
| <div> | |
| <p className="text-sm text-muted-foreground">Total Trades</p> | |
| <p className="text-lg font-bold">{totalTrades}</p> | |
| </div> | |
| </div> | |
| </CardContent> | |
| </Card> | |
| <Card className="bg-gradient-card border-border/50"> | |
| <CardContent className="p-4"> | |
| <div className="flex items-center gap-2"> | |
| <TrendingUp className="h-5 w-5 text-profit" /> | |
| <div> | |
| <p className="text-sm text-muted-foreground">Winning Trades</p> | |
| <p className="text-lg font-bold text-profit">{winningTrades}</p> | |
| </div> | |
| </div> | |
| </CardContent> | |
| </Card> | |
| <Card className="bg-gradient-card border-border/50"> | |
| <CardContent className="p-4"> | |
| <div className="flex items-center gap-2"> | |
| <Percent className="h-5 w-5 text-accent" /> | |
| <div> | |
| <p className="text-sm text-muted-foreground">Win Rate</p> | |
| <p className="text-lg font-bold text-profit">68.5%</p> | |
| </div> | |
| </div> | |
| </CardContent> | |
| </Card> | |
| </div> | |
| </div> | |
| ); | |
| }; |