fix(dashboard): Strategy page crashed on undefined fields
Some checks failed
ci/woodpecker/push/woodpecker Pipeline was canceled
Some checks failed
ci/woodpecker/push/woodpecker Pipeline was canceled
User reported UI error. Root cause: API GET /api/meet-kevin/strategy/
performance returns {trade_count, closed_trade_count, total_pnl_usd,
win_rate_pct, wins, losses} but the dashboard's StrategyPerformance
type expected {total_return_pct, sharpe_ratio, max_drawdown_pct,
open_positions, alpha_vs_spy_pct, ...}. So performance.open_positions
was undefined and .toString() crashed the whole page render.
Fix: update StrategyPerformance to match the actual API shape and
rewrite the 6-card headline grid to show the metrics the API
actually computes (trade count, closed count, total P&L, win rate,
wins, losses). Defensive ?? 0 fallbacks everywhere so future
schema drift doesn't crash again.
Long-term: extend the API to compute sharpe/max-dd/alpha vs SPY etc.
once there are real Kevin trades to compute them on (currently 0
trades — all 13 emitted signals fired outside market hours and were
correctly rejected by RiskManager).
This commit is contained in:
parent
d5359691b1
commit
1aeb6e8587
2 changed files with 27 additions and 29 deletions
|
|
@ -123,36 +123,35 @@ export default function MeetKevinStrategy() {
|
|||
|
||||
{/* Headline metrics */}
|
||||
{performance && (
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 xl:grid-cols-6 gap-4">
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 xl:grid-cols-6 gap-4">
|
||||
<MetricCard
|
||||
label="Total Return"
|
||||
value={fmt(performance.total_return_pct)}
|
||||
color={performance.total_return_pct >= 0 ? 'text-green-400' : 'text-red-400'}
|
||||
label="Total Trades"
|
||||
value={(performance.trade_count ?? 0).toString()}
|
||||
/>
|
||||
<MetricCard
|
||||
label="Ann. Return"
|
||||
value={fmt(performance.annualized_return_pct)}
|
||||
color={(performance.annualized_return_pct ?? 0) >= 0 ? 'text-green-400' : 'text-red-400'}
|
||||
label="Closed Trades"
|
||||
value={(performance.closed_trade_count ?? 0).toString()}
|
||||
/>
|
||||
<MetricCard
|
||||
label="Sharpe"
|
||||
value={performance.sharpe_ratio != null ? performance.sharpe_ratio.toFixed(2) : '—'}
|
||||
color={(performance.sharpe_ratio ?? 0) >= 1 ? 'text-green-400' : 'text-yellow-400'}
|
||||
label="Total P&L"
|
||||
value={`${(performance.total_pnl_usd ?? 0) >= 0 ? '+' : ''}$${(performance.total_pnl_usd ?? 0).toFixed(2)}`}
|
||||
color={(performance.total_pnl_usd ?? 0) >= 0 ? 'text-green-400' : 'text-red-400'}
|
||||
/>
|
||||
<MetricCard
|
||||
label="Max Drawdown"
|
||||
value={performance.max_drawdown_pct != null ? `${performance.max_drawdown_pct.toFixed(2)}%` : '—'}
|
||||
label="Win Rate"
|
||||
value={`${(performance.win_rate_pct ?? 0).toFixed(1)}%`}
|
||||
color={(performance.win_rate_pct ?? 0) >= 50 ? 'text-green-400' : 'text-yellow-400'}
|
||||
/>
|
||||
<MetricCard
|
||||
label="Wins"
|
||||
value={(performance.wins ?? 0).toString()}
|
||||
color="text-green-400"
|
||||
/>
|
||||
<MetricCard
|
||||
label="Losses"
|
||||
value={(performance.losses ?? 0).toString()}
|
||||
color="text-red-400"
|
||||
/>
|
||||
<MetricCard
|
||||
label="Alpha vs SPY"
|
||||
value={fmt(performance.alpha_vs_spy_pct)}
|
||||
color={(performance.alpha_vs_spy_pct ?? 0) >= 0 ? 'text-green-400' : 'text-red-400'}
|
||||
/>
|
||||
<MetricCard
|
||||
label="Open Positions"
|
||||
value={performance.open_positions.toString()}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
|
|||
|
|
@ -199,13 +199,12 @@ export interface StrategyEquityCurve {
|
|||
}
|
||||
|
||||
export interface StrategyPerformance {
|
||||
total_return_pct: number;
|
||||
annualized_return_pct: number | null;
|
||||
sharpe_ratio: number | null;
|
||||
max_drawdown_pct: number | null;
|
||||
win_rate: number | null;
|
||||
// Live-path metrics — current shape from
|
||||
// GET /api/meet-kevin/strategy/performance.
|
||||
trade_count: number;
|
||||
alpha_vs_spy_pct: number | null;
|
||||
open_positions: number;
|
||||
last_backtest_at: string | null;
|
||||
closed_trade_count: number;
|
||||
total_pnl_usd: number;
|
||||
win_rate_pct: number;
|
||||
wins: number;
|
||||
losses: number;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue