Files
trading_bot_v4/app/analytics/page.tsx
mindesbunister 711ff9aaf4 Add signal quality version comparison to analytics dashboard
- Created /api/analytics/version-comparison endpoint
- Shows performance metrics for v1, v2, v3 scoring logic
- Compares: trade count, win rate, P&L, quality scores, MFE/MAE
- Special focus on extreme positions (< 15% or > 85% range)
- Tracks weak ADX count (< 18) for each version
- Visual indicators for current version (v3)
- Data collection progress notice for v3 (need 20+ trades)
- Legend explaining MFE, MAE, extreme positions, weak ADX

Enables data-driven optimization by comparing algorithm performance
with clean, version-tagged datasets.
2025-11-07 13:05:48 +01:00

678 lines
31 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.
/**
* Trading Bot v4 - Analytics Dashboard
*
* Comprehensive view of trading performance and statistics
*/
'use client'
import { useState, useEffect } from 'react'
interface Stats {
period: string
realTrades: {
total: number
winning: number
losing: number
winRate: string
totalPnL: string
avgWin: string
avgLoss: string
profitFactor: string
}
testTrades: {
count: number
note: string
}
}
interface LastTrade {
id: string
symbol: string
direction: string
entryPrice: number
entryTime: string
exitPrice?: number
exitTime?: string
exitReason?: string
realizedPnL?: number
realizedPnLPercent?: number
positionSizeUSD: number
leverage: number
stopLossPrice: number
takeProfit1Price: number
takeProfit2Price: number
isTestTrade: boolean
signalQualityScore?: number
}
interface NetPosition {
symbol: string
longUSD: number
shortUSD: number
netUSD: number
netSOL: number
netDirection: 'long' | 'short' | 'flat'
tradeCount: number
}
interface PositionSummary {
summary: {
individualTrades: number
testTrades: number
totalIndividualExposure: string
netExposure: string
explanation: string
}
netPositions: NetPosition[]
}
interface VersionStats {
version: string
tradeCount: number
winRate: number
totalPnL: number
avgPnL: number
avgQualityScore: number | null
avgMFE: number | null
avgMAE: number | null
extremePositions: {
count: number
avgADX: number | null
weakADXCount: number
winRate: number
avgPnL: number
}
}
interface VersionComparison {
versions: VersionStats[]
descriptions: Record<string, string>
}
export default function AnalyticsPage() {
const [stats, setStats] = useState<Stats | null>(null)
const [positions, setPositions] = useState<PositionSummary | null>(null)
const [lastTrade, setLastTrade] = useState<LastTrade | null>(null)
const [versionComparison, setVersionComparison] = useState<VersionComparison | null>(null)
const [loading, setLoading] = useState(true)
const [selectedDays, setSelectedDays] = useState(30)
useEffect(() => {
loadData()
}, [selectedDays])
const loadData = async () => {
setLoading(true)
try {
const [statsRes, positionsRes, lastTradeRes, versionRes] = await Promise.all([
fetch(`/api/analytics/stats?days=${selectedDays}`),
fetch('/api/analytics/positions'),
fetch('/api/analytics/last-trade'),
fetch('/api/analytics/version-comparison'),
])
const statsData = await statsRes.json()
const positionsData = await positionsRes.json()
const lastTradeData = await lastTradeRes.json()
const versionData = await versionRes.json()
setStats(statsData.stats)
setPositions(positionsData.summary)
setLastTrade(lastTradeData.trade)
setVersionComparison(versionData.success ? versionData : null)
} catch (error) {
console.error('Failed to load analytics:', error)
}
setLoading(false)
}
const clearManuallyClosed = async () => {
if (!confirm('Clear all open trades from database? Use this if you manually closed positions in Drift UI.')) {
return
}
try {
const res = await fetch('/api/trading/clear-manual-closes', {
method: 'POST',
})
if (res.ok) {
alert('✅ Manually closed trades cleared from database')
loadData() // Reload data
} else {
const error = await res.json()
alert(`❌ Failed to clear: ${error.error}`)
}
} catch (error) {
console.error('Failed to clear trades:', error)
alert('❌ Failed to clear trades')
}
}
if (loading) {
return (
<div className="min-h-screen bg-gradient-to-br from-gray-900 via-gray-800 to-gray-900 flex items-center justify-center">
<div className="text-center">
<div className="inline-block animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500 mb-4"></div>
<p className="text-gray-400">Loading analytics...</p>
</div>
</div>
)
}
return (
<div className="min-h-screen bg-gradient-to-br from-gray-900 via-gray-800 to-gray-900">
{/* Header */}
<div className="bg-gray-800/50 backdrop-blur-sm border-b border-gray-700">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
<div className="flex items-center justify-between">
<div className="flex items-center space-x-4">
<a href="/" className="text-gray-400 hover:text-white transition">
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 19l-7-7m0 0l7-7m-7 7h18" />
</svg>
</a>
<div>
<h1 className="text-2xl font-bold text-white">📊 Analytics Dashboard</h1>
<p className="text-sm text-gray-400">Trading performance and statistics</p>
</div>
</div>
{/* Time Period Selector */}
<div className="flex items-center space-x-4">
<a
href="/analytics/optimization"
className="px-4 py-2 bg-blue-600 hover:bg-blue-700 rounded-lg text-white font-semibold transition-colors"
>
🎯 TP/SL Optimization
</a>
<div className="flex items-center space-x-2">
<span className="text-sm text-gray-400">Period:</span>
<select
value={selectedDays}
onChange={(e) => setSelectedDays(Number(e.target.value))}
className="bg-gray-700 text-white rounded-lg px-4 py-2 border border-gray-600 focus:border-blue-500 focus:outline-none"
>
<option value={7}>7 days</option>
<option value={30}>30 days</option>
<option value={90}>90 days</option>
<option value={365}>1 year</option>
</select>
</div>
</div>
</div>
</div>
</div>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
{/* Position Summary */}
{positions && (
<div className="mb-8">
<div className="flex items-center justify-between mb-4">
<h2 className="text-xl font-bold text-white">📍 Current Positions</h2>
<button
onClick={clearManuallyClosed}
className="px-4 py-2 bg-red-600 hover:bg-red-700 rounded-lg text-white text-sm font-semibold transition-colors"
title="Clear open trades from database if you manually closed them in Drift UI"
>
🗑 Clear Manual Closes
</button>
</div>
<div className="grid md:grid-cols-4 gap-4">
<div className="bg-gray-800/50 backdrop-blur-sm rounded-xl p-6 border border-gray-700">
<div className="text-sm text-gray-400 mb-1">Open Trades</div>
<div className="text-3xl font-bold text-white">{positions.summary.individualTrades}</div>
</div>
<div className="bg-gray-800/50 backdrop-blur-sm rounded-xl p-6 border border-gray-700">
<div className="text-sm text-gray-400 mb-1">Test Trades</div>
<div className="text-3xl font-bold text-yellow-500">{positions.summary.testTrades}</div>
</div>
<div className="bg-gray-800/50 backdrop-blur-sm rounded-xl p-6 border border-gray-700">
<div className="text-sm text-gray-400 mb-1">Total Exposure</div>
<div className="text-3xl font-bold text-blue-400">{positions.summary.totalIndividualExposure}</div>
</div>
<div className="bg-gray-800/50 backdrop-blur-sm rounded-xl p-6 border border-gray-700">
<div className="text-sm text-gray-400 mb-1">Net Exposure</div>
<div className="text-3xl font-bold text-purple-400">{positions.summary.netExposure}</div>
</div>
</div>
{positions.netPositions.length > 0 && (
<div className="mt-4 bg-gray-800/50 backdrop-blur-sm rounded-xl p-6 border border-gray-700">
<h3 className="text-lg font-semibold text-white mb-4">Net Positions (Drift View)</h3>
<div className="space-y-3">
{positions.netPositions.map((pos, i) => (
<div key={i} className="flex items-center justify-between p-4 bg-gray-700/30 rounded-lg">
<div className="flex items-center space-x-4">
<div className="text-2xl">🎯</div>
<div>
<div className="text-white font-medium">{pos.symbol}</div>
<div className="text-sm text-gray-400">{pos.tradeCount} trade{pos.tradeCount > 1 ? 's' : ''}</div>
</div>
</div>
<div className="text-right">
<div className={`text-lg font-bold ${pos.netDirection === 'long' ? 'text-green-400' : pos.netDirection === 'short' ? 'text-red-400' : 'text-gray-400'}`}>
{pos.netDirection.toUpperCase()}: {Math.abs(pos.netSOL).toFixed(4)} SOL
</div>
<div className="text-sm text-gray-400">${Math.abs(pos.netUSD).toFixed(2)}</div>
</div>
</div>
))}
</div>
</div>
)}
{positions.summary.individualTrades === 0 && (
<div className="mt-4 bg-gray-800/30 backdrop-blur-sm rounded-xl p-8 border border-gray-700 text-center">
<div className="text-4xl mb-2">📭</div>
<p className="text-gray-400">No open positions</p>
</div>
)}
</div>
)}
{/* Signal Quality Version Comparison */}
{versionComparison && versionComparison.versions.length > 0 && (
<div className="mb-8">
<h2 className="text-xl font-bold text-white mb-4">🔬 Signal Quality Logic Versions</h2>
<div className="bg-gray-800/50 backdrop-blur-sm rounded-xl p-6 border border-gray-700">
<p className="text-gray-300 text-sm mb-6 leading-relaxed">
The bot has evolved through different signal quality scoring algorithms.
This section compares their performance to enable data-driven optimization.
</p>
<div className="space-y-4">
{versionComparison.versions.map((version, idx) => {
const isCurrentVersion = version.version === 'v3'
return (
<div
key={version.version}
className={`p-5 rounded-lg border ${isCurrentVersion ? 'bg-blue-900/20 border-blue-500/50' : 'bg-gray-700/30 border-gray-600'}`}
>
<div className="flex items-start justify-between mb-4">
<div className="flex-1">
<div className="flex items-center space-x-3 mb-2">
<h3 className={`text-lg font-bold ${isCurrentVersion ? 'text-blue-400' : 'text-white'}`}>
{version.version.toUpperCase()}
{isCurrentVersion && (
<span className="ml-2 px-2 py-1 text-xs bg-blue-600 text-white rounded-full">
CURRENT
</span>
)}
</h3>
</div>
<p className="text-sm text-gray-400">
{versionComparison.descriptions[version.version] || 'Unknown version'}
</p>
</div>
</div>
{/* Main Metrics Grid */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-3 mb-4">
<div className="bg-gray-800/50 rounded-lg p-3">
<div className="text-xs text-gray-400 mb-1">Trades</div>
<div className="text-xl font-bold text-white">{version.tradeCount}</div>
</div>
<div className="bg-gray-800/50 rounded-lg p-3">
<div className="text-xs text-gray-400 mb-1">Win Rate</div>
<div className={`text-xl font-bold ${version.winRate >= 50 ? 'text-green-400' : 'text-red-400'}`}>
{version.winRate}%
</div>
</div>
<div className="bg-gray-800/50 rounded-lg p-3">
<div className="text-xs text-gray-400 mb-1">Total P&L</div>
<div className={`text-xl font-bold ${version.totalPnL >= 0 ? 'text-green-400' : 'text-red-400'}`}>
{version.totalPnL >= 0 ? '+' : ''}${version.totalPnL.toFixed(2)}
</div>
</div>
<div className="bg-gray-800/50 rounded-lg p-3">
<div className="text-xs text-gray-400 mb-1">Avg P&L</div>
<div className={`text-xl font-bold ${version.avgPnL >= 0 ? 'text-green-400' : 'text-red-400'}`}>
{version.avgPnL >= 0 ? '+' : ''}${version.avgPnL.toFixed(2)}
</div>
</div>
</div>
{/* Advanced Metrics */}
<div className="grid grid-cols-2 md:grid-cols-3 gap-3 mb-4">
{version.avgQualityScore !== null && (
<div className="bg-gray-800/50 rounded-lg p-3">
<div className="text-xs text-gray-400 mb-1">Avg Quality Score</div>
<div className={`text-lg font-semibold ${version.avgQualityScore >= 75 ? 'text-green-400' : 'text-yellow-400'}`}>
{version.avgQualityScore}/100
</div>
</div>
)}
{version.avgMFE !== null && (
<div className="bg-gray-800/50 rounded-lg p-3">
<div className="text-xs text-gray-400 mb-1">Avg MFE</div>
<div className="text-lg font-semibold text-green-400">
+{version.avgMFE.toFixed(2)}%
</div>
</div>
)}
{version.avgMAE !== null && (
<div className="bg-gray-800/50 rounded-lg p-3">
<div className="text-xs text-gray-400 mb-1">Avg MAE</div>
<div className="text-lg font-semibold text-red-400">
{version.avgMAE.toFixed(2)}%
</div>
</div>
)}
</div>
{/* Extreme Position Stats */}
{version.extremePositions.count > 0 && (
<div className="pt-4 border-t border-gray-600/50">
<div className="text-xs text-gray-400 mb-3 flex items-center">
<span className="text-yellow-500 mr-2"></span>
Extreme Positions (&lt; 15% or &gt; 85% range)
</div>
<div className="grid grid-cols-2 md:grid-cols-5 gap-2">
<div className="bg-gray-800/50 rounded p-2">
<div className="text-xs text-gray-500">Count</div>
<div className="text-sm font-semibold text-white">
{version.extremePositions.count}
</div>
</div>
{version.extremePositions.avgADX !== null && (
<div className="bg-gray-800/50 rounded p-2">
<div className="text-xs text-gray-500">Avg ADX</div>
<div className={`text-sm font-semibold ${version.extremePositions.avgADX >= 18 ? 'text-green-400' : 'text-orange-400'}`}>
{version.extremePositions.avgADX.toFixed(1)}
</div>
</div>
)}
<div className="bg-gray-800/50 rounded p-2">
<div className="text-xs text-gray-500">Weak ADX</div>
<div className="text-sm font-semibold text-orange-400">
{version.extremePositions.weakADXCount}
</div>
</div>
<div className="bg-gray-800/50 rounded p-2">
<div className="text-xs text-gray-500">Win Rate</div>
<div className={`text-sm font-semibold ${version.extremePositions.winRate >= 50 ? 'text-green-400' : 'text-red-400'}`}>
{version.extremePositions.winRate}%
</div>
</div>
<div className="bg-gray-800/50 rounded p-2">
<div className="text-xs text-gray-500">Avg P&L</div>
<div className={`text-sm font-semibold ${version.extremePositions.avgPnL >= 0 ? 'text-green-400' : 'text-red-400'}`}>
{version.extremePositions.avgPnL >= 0 ? '+' : ''}${version.extremePositions.avgPnL.toFixed(2)}
</div>
</div>
</div>
</div>
)}
{/* Data Collection Notice for v3 */}
{isCurrentVersion && version.tradeCount < 20 && (
<div className="mt-4 p-3 bg-yellow-900/20 rounded-lg border border-yellow-500/30">
<div className="flex items-start space-x-2">
<span className="text-yellow-500 text-sm">📊</span>
<p className="text-xs text-yellow-300/80 leading-relaxed">
<strong>Data Collection Phase:</strong> Need {20 - version.tradeCount} more trades
before v3 performance can be reliably evaluated. This version is designed to prevent
losses from extreme position entries with weak trends (ADX &lt; 18).
</p>
</div>
</div>
)}
</div>
)
})}
</div>
{/* Legend */}
<div className="mt-6 pt-6 border-t border-gray-600/50">
<div className="text-xs text-gray-400 space-y-1">
<div><strong className="text-gray-300">MFE (Max Favorable Excursion):</strong> Best profit % reached during trade lifetime</div>
<div><strong className="text-gray-300">MAE (Max Adverse Excursion):</strong> Worst loss % reached during trade lifetime</div>
<div><strong className="text-gray-300">Extreme Positions:</strong> Trades entered at price range extremes (&lt; 15% or &gt; 85%)</div>
<div><strong className="text-gray-300">Weak ADX:</strong> Trend strength below 18 (indicates sideways/choppy market)</div>
</div>
</div>
</div>
</div>
)}
{/* Last Trade Details */}
{lastTrade && (
<div className="mb-8">
<h2 className="text-xl font-bold text-white mb-4">🔍 Last Trade</h2>
<div className="bg-gray-800/50 backdrop-blur-sm rounded-xl p-6 border border-gray-700">
<div className="flex items-start justify-between mb-4">
<div className="flex items-center space-x-4">
<div className="text-3xl">
{lastTrade.direction === 'long' ? '📈' : '📉'}
</div>
<div>
<div className="text-2xl font-bold text-white">{lastTrade.symbol}</div>
<div className="flex items-center space-x-2 mt-1">
<span className={`px-3 py-1 rounded-full text-sm font-semibold ${lastTrade.direction === 'long' ? 'bg-green-900/50 text-green-400' : 'bg-red-900/50 text-red-400'}`}>
{lastTrade.direction.toUpperCase()}
</span>
{lastTrade.isTestTrade && (
<span className="px-3 py-1 rounded-full text-sm font-semibold bg-yellow-900/50 text-yellow-400">
TEST
</span>
)}
</div>
</div>
</div>
{lastTrade.exitTime && lastTrade.realizedPnL !== undefined && (
<div className="text-right">
<div className={`text-3xl font-bold ${lastTrade.realizedPnL >= 0 ? 'text-green-400' : 'text-red-400'}`}>
{lastTrade.realizedPnL >= 0 ? '+' : ''}${lastTrade.realizedPnL.toFixed(2)}
</div>
{lastTrade.realizedPnLPercent !== undefined && (
<div className={`text-sm ${lastTrade.realizedPnLPercent >= 0 ? 'text-green-400' : 'text-red-400'}`}>
{lastTrade.realizedPnLPercent >= 0 ? '+' : ''}{lastTrade.realizedPnLPercent.toFixed(2)}%
</div>
)}
</div>
)}
{!lastTrade.exitTime && (
<div className="text-right">
<div className="text-2xl font-bold text-blue-400">OPEN</div>
<div className="text-sm text-gray-400">Currently active</div>
</div>
)}
</div>
<div className="grid md:grid-cols-3 gap-4 mb-4">
<div className="bg-gray-700/30 rounded-lg p-4">
<div className="text-sm text-gray-400 mb-1">Entry</div>
<div className="text-xl font-bold text-white">${lastTrade.entryPrice.toFixed(4)}</div>
<div className="text-xs text-gray-500">
{new Date(lastTrade.entryTime).toLocaleString()}
</div>
</div>
<div className="bg-gray-700/30 rounded-lg p-4">
<div className="text-sm text-gray-400 mb-1">Position Size</div>
<div className="text-xl font-bold text-white">${lastTrade.positionSizeUSD.toFixed(2)}</div>
<div className="text-xs text-gray-500">
{lastTrade.leverage}x leverage
</div>
</div>
<div className="bg-gray-700/30 rounded-lg p-4">
<div className="text-sm text-gray-400 mb-1">Signal Quality</div>
{lastTrade.signalQualityScore !== undefined ? (
<>
<div className={`text-xl font-bold ${lastTrade.signalQualityScore >= 80 ? 'text-green-400' : lastTrade.signalQualityScore >= 70 ? 'text-yellow-400' : 'text-orange-400'}`}>
{lastTrade.signalQualityScore}/100
</div>
<div className="text-xs text-gray-500">
{lastTrade.signalQualityScore >= 80 ? 'Excellent' : lastTrade.signalQualityScore >= 70 ? 'Good' : 'Marginal'}
</div>
</>
) : (
<>
<div className="text-xl font-bold text-gray-500">N/A</div>
<div className="text-xs text-gray-500">No score available</div>
</>
)}
</div>
</div>
{lastTrade.exitTime && lastTrade.exitPrice && (
<div className="grid md:grid-cols-1 gap-4 mb-4">
<div className="bg-gray-700/30 rounded-lg p-4">
<div className="text-sm text-gray-400 mb-1">Exit</div>
<div className="text-xl font-bold text-white">${lastTrade.exitPrice.toFixed(4)}</div>
<div className="text-xs text-gray-500">
{new Date(lastTrade.exitTime).toLocaleString()}
</div>
</div>
</div>
)}
<div className="grid md:grid-cols-3 gap-4">
<div className="bg-gray-700/30 rounded-lg p-3">
<div className="text-xs text-gray-400 mb-1">Stop Loss</div>
<div className="text-lg font-semibold text-red-400">${lastTrade.stopLossPrice.toFixed(4)}</div>
</div>
<div className="bg-gray-700/30 rounded-lg p-3">
<div className="text-xs text-gray-400 mb-1">TP1</div>
<div className="text-lg font-semibold text-green-400">${lastTrade.takeProfit1Price.toFixed(4)}</div>
</div>
<div className="bg-gray-700/30 rounded-lg p-3">
<div className="text-xs text-gray-400 mb-1">TP2</div>
<div className="text-lg font-semibold text-green-400">${lastTrade.takeProfit2Price.toFixed(4)}</div>
</div>
</div>
{lastTrade.exitReason && (
<div className="mt-4 p-3 bg-blue-900/20 rounded-lg border border-blue-500/30">
<span className="text-sm text-gray-400">Exit Reason: </span>
<span className="text-sm font-semibold text-blue-400">{lastTrade.exitReason}</span>
</div>
)}
</div>
</div>
)}
{/* Trading Statistics */}
{stats && (
<div>
<h2 className="text-xl font-bold text-white mb-4">📈 Performance ({stats.period})</h2>
{/* Main Stats Grid */}
<div className="grid md:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
<div className="bg-gray-800/50 backdrop-blur-sm rounded-xl p-6 border border-gray-700">
<div className="text-sm text-gray-400 mb-1">Total Trades</div>
<div className="text-3xl font-bold text-white">{stats.realTrades.total}</div>
<div className="text-xs text-gray-500 mt-2">
{stats.testTrades.count} test trade{stats.testTrades.count !== 1 ? 's' : ''} excluded
</div>
</div>
<div className="bg-gray-800/50 backdrop-blur-sm rounded-xl p-6 border border-gray-700">
<div className="text-sm text-gray-400 mb-1">Win Rate</div>
<div className="text-3xl font-bold text-green-400">{stats.realTrades.winRate}</div>
<div className="text-xs text-gray-500 mt-2">
{stats.realTrades.winning}W / {stats.realTrades.losing}L
</div>
</div>
<div className="bg-gray-800/50 backdrop-blur-sm rounded-xl p-6 border border-gray-700">
<div className="text-sm text-gray-400 mb-1">Total P&L</div>
<div className={`text-3xl font-bold ${parseFloat(stats.realTrades.totalPnL.replace('$', '')) >= 0 ? 'text-green-400' : 'text-red-400'}`}>
{stats.realTrades.totalPnL}
</div>
</div>
<div className="bg-gray-800/50 backdrop-blur-sm rounded-xl p-6 border border-gray-700">
<div className="text-sm text-gray-400 mb-1">Profit Factor</div>
<div className="text-3xl font-bold text-blue-400">{stats.realTrades.profitFactor}</div>
</div>
</div>
{/* Detailed Stats */}
<div className="grid md:grid-cols-2 gap-6">
<div className="bg-gray-800/50 backdrop-blur-sm rounded-xl p-6 border border-gray-700">
<h3 className="text-lg font-semibold text-white mb-4 flex items-center">
<span className="text-2xl mr-2"></span>
Winning Trades
</h3>
<div className="space-y-3">
<div className="flex justify-between">
<span className="text-gray-400">Count:</span>
<span className="text-white font-medium">{stats.realTrades.winning}</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Average Win:</span>
<span className="text-green-400 font-medium">{stats.realTrades.avgWin}</span>
</div>
</div>
</div>
<div className="bg-gray-800/50 backdrop-blur-sm rounded-xl p-6 border border-gray-700">
<h3 className="text-lg font-semibold text-white mb-4 flex items-center">
<span className="text-2xl mr-2"></span>
Losing Trades
</h3>
<div className="space-y-3">
<div className="flex justify-between">
<span className="text-gray-400">Count:</span>
<span className="text-white font-medium">{stats.realTrades.losing}</span>
</div>
<div className="flex justify-between">
<span className="text-gray-400">Average Loss:</span>
<span className="text-red-400 font-medium">{stats.realTrades.avgLoss}</span>
</div>
</div>
</div>
</div>
{stats.realTrades.total === 0 && (
<div className="mt-6 bg-gray-800/30 backdrop-blur-sm rounded-xl p-8 border border-gray-700 text-center">
<div className="text-4xl mb-2">📊</div>
<p className="text-gray-400 mb-2">No trading data yet</p>
<p className="text-sm text-gray-500">Start trading to see your performance statistics</p>
</div>
)}
</div>
)}
{/* Info Note */}
<div className="mt-8 bg-blue-900/20 backdrop-blur-sm rounded-xl p-6 border border-blue-500/30">
<div className="flex items-start space-x-3">
<div className="text-2xl">💡</div>
<div>
<h4 className="text-white font-semibold mb-2">Understanding Position Netting</h4>
<p className="text-gray-300 text-sm leading-relaxed">
Drift perpetual futures automatically NET opposite positions in the same market.
If you have both LONG and SHORT positions in SOL-PERP, Drift shows only the net exposure.
The database tracks individual trades for complete history, while this dashboard shows
your actual market exposure.
</p>
</div>
</div>
</div>
</div>
</div>
)
}