mirror of
https://github.com/NoFxAiOS/nofx.git
synced 2026-07-18 01:44:38 +08:00
fix: dashboard metrics — real drawdown baseline, realized/unrealized split, risk radar fields
- Max drawdown was double-broken: the backend built the equity curve on a hardcoded $10k baseline (understating a small account's drawdown ~20x) and the frontend multiplied the already-percent value by 100 again (0.87% shown as -86.9%). The curve now starts from the trader's real initial balance (10k fallback when unknown) and the UI renders the percent once; the demo engine and type docs are aligned to percent semantics. - Header now separates equity-based 'Total P/L (incl. unrealized)' from 'Realized P/L (closed trades)' so it no longer contradicts profit factor / win rate, and the stats strip shows the fee-drag chain (gross - fees = net) plus a per-trade-labelled sharpe. - Risk radar read a non-existent account field (total_unrealized_profit) so unrealized PnL always showed $0; small PnLs also render with cents now. - Nav 'Connect Hyperliquid' turns into a green connected chip when the server already holds a fully-authorized exchange, instead of nagging forever from a browser without the localStorage flow state.
This commit is contained in:
@@ -339,14 +339,21 @@ export function TerminalDashboard({
|
||||
</div>
|
||||
<div className="tm-rule" />
|
||||
|
||||
{/* metric row */}
|
||||
{/* metric row — "Total P/L" is equity-based (includes unrealized);
|
||||
"Realized P/L" is closed-trades only and matches PF/win-rate/sharpe,
|
||||
so the two never read as contradicting each other */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)' }}>
|
||||
{[
|
||||
{ l: 'Equity', v: fmtUsd(account?.total_equity), c: 'var(--tm-ink)' },
|
||||
{ l: 'Total P/L', v: `${fmtUsd(pnl, true)} (${fmtPct(pnlPct)})`, c: up ? 'var(--tm-up)' : 'var(--tm-dn)' },
|
||||
{ l: 'Win rate', v: fullStats != null ? `${fullStats.win_rate.toFixed(1)}%` : '—', c: 'var(--tm-ink)' },
|
||||
{ l: 'Total P/L · incl. unrealized', v: `${fmtUsd(pnl, true)} (${fmtPct(pnlPct)})`, c: up ? 'var(--tm-up)' : 'var(--tm-dn)' },
|
||||
{
|
||||
l: 'Realized P/L · closed trades',
|
||||
v: fullStats != null ? fmtUsd(fullStats.total_pnl, true) : '—',
|
||||
c: fullStats != null && fullStats.total_pnl >= 0 ? 'var(--tm-up)' : 'var(--tm-dn)',
|
||||
},
|
||||
{ l: 'Profit factor', v: fullStats != null ? fullStats.profit_factor.toFixed(2) : '—', c: 'var(--tm-ink)' },
|
||||
{ l: 'Max drawdown', v: fullStats != null ? `-${(fullStats.max_drawdown_pct * 100).toFixed(1)}%` : '—', c: 'var(--tm-dn)' },
|
||||
// max_drawdown_pct is already a percent (18.5 = -18.5%)
|
||||
{ l: 'Max drawdown', v: fullStats != null ? `-${fullStats.max_drawdown_pct.toFixed(1)}%` : '—', c: 'var(--tm-dn)' },
|
||||
].map((m, i) => (
|
||||
<div key={m.l} style={{ padding: '12px 14px', borderRight: i < 4 ? cellBorder : 'none' }}>
|
||||
<div className="tm-sc">{m.l}</div>
|
||||
@@ -361,11 +368,14 @@ export function TerminalDashboard({
|
||||
<>
|
||||
<div className="tm-mono" style={{ display: 'flex', gap: 18, padding: '6px 14px', fontSize: 11, color: 'var(--tm-ink-2)', flexWrap: 'wrap' }}>
|
||||
<span className="tm-sc">trades <b style={{ color: 'var(--tm-ink)' }}>{fullStats.total_trades}</b></span>
|
||||
<span className="tm-sc tm-up">win {fullStats.win_trades}</span>
|
||||
<span className="tm-sc tm-up">win {fullStats.win_trades} ({fullStats.win_rate.toFixed(1)}%)</span>
|
||||
<span className="tm-sc tm-dn">loss {fullStats.loss_trades}</span>
|
||||
<span className="tm-sc">sharpe <b style={{ color: 'var(--tm-ink)' }}>{fullStats.sharpe_ratio.toFixed(2)}</b></span>
|
||||
{/* fee-drag chain: gross realized − fees = net realized */}
|
||||
<span className="tm-sc">gross <b style={{ color: 'var(--tm-ink)' }}>{fmtUsd(fullStats.total_pnl + fullStats.total_fee, true)}</b></span>
|
||||
<span className="tm-sc">fees <b style={{ color: 'var(--tm-ink)' }}>-{fmtUsd(fullStats.total_fee)}</b></span>
|
||||
<span className="tm-sc">net <b style={{ color: fullStats.total_pnl >= 0 ? 'var(--tm-up)' : 'var(--tm-dn)' }}>{fmtUsd(fullStats.total_pnl, true)}</b></span>
|
||||
<span className="tm-sc">sharpe/trade <b style={{ color: 'var(--tm-ink)' }}>{fullStats.sharpe_ratio.toFixed(2)}</b></span>
|
||||
<span className="tm-sc">avg win/loss <b style={{ color: 'var(--tm-ink)' }}>{fullStats.avg_win.toFixed(2)}/{fullStats.avg_loss.toFixed(2)}</b></span>
|
||||
<span className="tm-sc">fees <b style={{ color: 'var(--tm-ink)' }}>{fmtUsd(fullStats.total_fee)}</b></span>
|
||||
</div>
|
||||
<div className="tm-rule" />
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user