'use client'; import { Box, CloseButton, Drawer, Flex, Portal, SimpleGrid, Text, } from '@chakra-ui/react'; import type { StrategyChartSnapshot } from '@tradejs/types'; import { formatInteger, formatPercent, formatSignedNumber, getPnlColor, } from '#components/Shared/OrdersDrawer'; import { buildQuarterlyMonthlyStats } from '#app/lib/strategyPerformance'; import { AdvancedMetricsPanel } from './AdvancedMetricsPanel'; import { ChartPanel, DrawdownTimelineChart, PnlDistributionChart, RollingPerformanceChart, TimeOfDaySessionChart, WinLossStreakTimelineChart, } from './StrategyPerformanceCharts'; import { buildStrategySnapshotCardViewModel, getMetricColor, getPnlBarColor, type AiDiagnosticGroup, type AiDiagnosticMetric, type SymbolPnlRank, } from './StrategySnapshotCard.presenter'; type StrategySnapshotCardViewModel = ReturnType< typeof buildStrategySnapshotCardViewModel >; const AiDiagnosticCard = ({ metric }: { metric: AiDiagnosticMetric }) => ( {metric.label} {metric.value} {metric.detail ? ( {metric.detail} ) : null} ); const AiDiagnosticGroupBlock = ({ group }: { group: AiDiagnosticGroup }) => ( {group.title} {group.description} {group.metrics.map((metric) => ( ))} ); const AiDiagnosticsPanel = ({ groups }: { groups: AiDiagnosticGroup[] }) => { if (!groups.length) { return null; } return ( AI diagnostics classifier-only details {groups.map((group) => ( ))} ); }; export const StrategySnapshotCardDetailsDrawer = ({ snapshot, mode, open, onOpenChange, viewModel, }: { snapshot: StrategyChartSnapshot; mode: 'replay' | 'ai'; open: boolean; onOpenChange: (open: boolean) => void; viewModel: StrategySnapshotCardViewModel; }) => { const { aiDiagnosticGroups, directionStatGroups, topSymbolPnlRanking, worstSymbolPnlRanking, symbolRankingMaxAbsPnl, drawerMetrics, advancedMetrics, } = viewModel; const { monthlyStats, tradePoints: snapshotTradePoints, drawdownPoints, rollingPerformancePoints, pnlDistributionBins, sessionPnlStats, hourlyPnlStats, } = viewModel.performance; const renderSymbolPnlRanking = ({ title, subtitle, ranking, }: { title: string; subtitle: string; ranking: SymbolPnlRank[]; }) => ( {title} {subtitle} {ranking.length ? ( <> Contracts P&L (USDT) {ranking.map((rank) => { const barWidth = Math.max( 6, (Math.abs(rank.pnl) / symbolRankingMaxAbsPnl) * 100, ); return ( {rank.symbol} {formatInteger(rank.orders)} orders · win{' '} {formatPercent(rank.winRate)} · avg{' '} {rank.avgPnl == null ? 'n/a' : formatSignedNumber(rank.avgPnl)} {formatSignedNumber(rank.pnl)} ); })} ) : ( No symbol P&L data )} ); return ( onOpenChange(e.open)} > {snapshot.title} {snapshot.subtitle || 'AI train details'} {drawerMetrics.map((metric) => ( {metric.label} {metric.value} ))} {monthlyStats.length ? ( Monthly Performance {monthlyStats.map((yearGroup) => ( {yearGroup.year} {buildQuarterlyMonthlyStats(yearGroup.months).map( (quarter) => ( {quarter.label} {quarter.months.map((month, monthOffset) => { const monthIndex = quarter.monthIndexes[monthOffset] ?? 0; if (!month) { return ( ); } const winRate = month.orders > 0 ? (month.wins / month.orders) * 100 : null; return ( {month.monthLabel} {String(month.monthIndex).padStart( 2, '0', )} {formatSignedNumber(month.pnl)} Orders {formatInteger(month.orders)} Win rate {formatPercent(winRate)} ); })} ), )} ))} ) : null} {mode === 'ai' ? ( ) : null} {mode === 'ai' ? ( {renderSymbolPnlRanking({ title: 'P&L Ranking', subtitle: 'Top 10 contracts', ranking: topSymbolPnlRanking, })} {renderSymbolPnlRanking({ title: 'Worst Contracts', subtitle: 'Worst 10 contracts', ranking: worstSymbolPnlRanking, })} ) : null} LONG / SHORT {directionStatGroups.map((group) => ( {group.direction} {!group.hasData ? ( no data ) : null} {group.metrics.map((metric) => ( {metric.label} {metric.value} ))} ))} ); };