'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}
))}
))}
);
};