import { useMemo } from 'react'; import { Link } from 'react-router-dom'; import { usePaperTrades } from '../../hooks/usePaperTrades'; import { tradePnl } from '../../lib/paperTrade'; import { formatPrice, fmtR, fmtSignedMoney, rColor } from '../../lib/format'; import { Section } from '../ui/Section'; import { Callout } from '../ui/Callout'; import { StatTile } from '../ui/StatTile'; // How the trade was closed — useful context on real trades at almost no cost. function reasonMeta(reason: string | null): { label: string; cls: string } { switch (reason) { case 'stop': return { label: 'Stop', cls: 'text-red-400' }; case 'trailing': return { label: 'Trail', cls: 'text-amber-400' }; case 'target': return { label: 'Target', cls: 'text-emerald-400' }; case 'time': return { label: 'Time', cls: 'text-gray-400' }; case 'manual': return { label: 'Manual', cls: 'text-blue-300' }; default: return { label: '—', cls: 'text-gray-500' }; } } export function MyTradesPanel() { const { data: closed, isLoading } = usePaperTrades('closed'); const stats = useMemo(() => { const rows = (closed ?? []).map((t) => ({ t, p: tradePnl(t) })); const rs = rows.map((r) => r.p?.r).filter((r): r is number => r != null); const pnls = rows.map((r) => r.p?.pnl ?? 0); const alphas = rows.map((r) => r.t.alpha_usd).filter((a): a is number => a != null); const wins = pnls.filter((p) => p > 0).length; const losses = pnls.filter((p) => p < 0).length; const decided = wins + losses; return { total: rows.length, wins, losses, hitRate: decided ? (wins / decided) * 100 : null, avgR: rs.length ? rs.reduce((a, b) => a + b, 0) / rs.length : null, totalR: rs.length ? rs.reduce((a, b) => a + b, 0) : null, totalPnl: pnls.reduce((a, b) => a + b, 0), totalAlpha: alphas.length ? alphas.reduce((a, b) => a + b, 0) : null, rows, }; }, [closed]); if (isLoading) return null; return (
{stats.total === 0 ? ( No closed trades yet. Take setups as paper trades and they’ll resolve here when price hits the stop or target (or when you sell). ) : (
{stats.rows.map(({ t, p }) => ( ))}
Ticker Dir Entry Exit Px P&L R Alpha Reason Closed
{t.symbol} {t.direction} {formatPrice(t.entry_price)} {t.close_price != null ? formatPrice(t.close_price) : '—'} {p ? fmtSignedMoney(p.pnl) : '—'} {p?.r != null ? fmtR(p.r) : '—'} {t.alpha_pct != null ? `${t.alpha_pct >= 0 ? '+' : ''}${t.alpha_pct.toFixed(1)}%` : '—'} {reasonMeta(t.close_reason).label} {t.closed_at ? new Date(t.closed_at).toLocaleDateString() : '—'}
)}
); }