refactor(signals): split the Track Record tab and cut the backtest page down

One tab stacked three things that all called themselves a track record:
realized paper P&L, setup-outcome grading under the rejected take-profit model,
and the backtest portfolio simulation. Split into Setups | Paper Trades |
Backtest, one subject each. `track` stays the Paper Trades slug so the legacy
/performance redirect keeps working. The grading diagnostic and its Evaluate /
Reset controls go with Backtest, not Paper Trades — reset_track_record deletes
trade_setups, not paper trades.

BacktestPanel 439 -> 175 lines. Its run settings alone were 106 lines of
hand-rolled sr-only radio cards for two binary choices; they are now two
Dropdowns and a button on one wrapping row, with the per-option prose moved into
the existing explainer. The amber warnings survive as a conditional slot, so a
non-default choice still announces itself but the common path is silent.

The recommendation printed eight findings at equal weight, burying the verdict
in tuning detail. `topic` now splits them: production, benchmark and robustness
stay inline, gate/exit/cutoff collapse behind a disclosure, and any WARNING or
LAGS item is promoted out of the collapsed group regardless of topic. No topic
chips — every backend string already self-prefixes, so a chip would render
"GATE | Gate: ...".

Portfolio metrics are now two tiers: five headline tiles for what the book
returned, then a smaller labelled row for how good that return was (Sortino,
Calmar (MAR), Gain/Pain, Profit Factor $, EV/trade). Reports cached before those
metrics existed hide the second row rather than showing a half-populated line of
dashes.

Extracted EquityCurveChart, PortfolioMonitorPanel and BacktestRecommendationCard,
plus a StatTile primitive and shared formatters for the duplication in the files
this touched. DashboardPage and OpenTradesPanel deliberately keep their own
copies — migrating them is separate scope.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-11 22:09:23 +02:00
co-authored by Claude Opus 5
parent 442dc3f04b
commit 13a984a84d
10 changed files with 599 additions and 397 deletions
+35
View File
@@ -0,0 +1,35 @@
/**
* One labelled metric. Lifted from the byte-identical `Stat` that lived in both
* BacktestPanel and MyTradesPanel.
*
* `size` is the hierarchy lever: `md` (default) is the headline look those two
* panels already had; `sm` marks a metric as supporting detail, which is what
* keeps a second row of ratios from reading as equally important as the returns
* above it.
*/
export function StatTile({
label,
value,
valueClass = 'text-gray-100',
sub,
title,
size = 'md',
}: {
label: string;
value: string;
valueClass?: string;
sub?: string;
/** Native tooltip — how the metric is defined. */
title?: string;
size?: 'md' | 'sm';
}) {
const pad = size === 'sm' ? 'p-3' : 'p-4';
const text = size === 'sm' ? 'text-lg' : 'text-2xl';
return (
<div className={`glass ${pad}`} title={title}>
<p className="section-index">{label}</p>
<p className={`num mt-1.5 ${text} font-semibold ${valueClass}`}>{value}</p>
{sub && <p className="mt-1 text-xs text-gray-500">{sub}</p>}
</div>
);
}