With several strategies the header cards showed only the first one. Expose day_pnl and drawdown_pct per strategy and add aggregateStatus() (frontend) so the cards show the whole account: summed cash/equity/P&L/trades/positions, worst drawdown, and any halt. Single-strategy runs are unchanged. Adds tests.
35 lines
1.1 KiB
JavaScript
35 lines
1.1 KiB
JavaScript
/**
|
|
* Top-of-dashboard status. With one strategy it is that strategy's status;
|
|
* with several, the per-strategy numbers are aggregated for the whole account.
|
|
*/
|
|
export function aggregateStatus(status, multiStatus) {
|
|
const list = multiStatus?.strategies || []
|
|
if (list.length <= 1) return status
|
|
|
|
const sum = (field) => list.reduce((acc, s) => acc + (s[field] || 0), 0)
|
|
const halted = list.filter((s) => s.halted)
|
|
|
|
return {
|
|
...status,
|
|
running: multiStatus.running,
|
|
price: multiStatus.price ?? status.price,
|
|
cash: sum('cash'),
|
|
equity: multiStatus.equity,
|
|
starting_balance: multiStatus.starting_balance,
|
|
realized_pnl: sum('realized_pnl'),
|
|
unrealized_pnl: sum('unrealized_pnl'),
|
|
total_pnl: multiStatus.total_pnl,
|
|
day_pnl: sum('day_pnl'),
|
|
// Worst individual strategy drawdown; the portfolio peak is not tracked.
|
|
drawdown_pct: Math.max(0, ...list.map((s) => s.drawdown_pct || 0)),
|
|
trades_today: sum('trades_today'),
|
|
open_positions: sum('open_positions'),
|
|
halted: halted.length > 0,
|
|
halt_reason:
|
|
halted
|
|
.map((s) => s.halt_reason)
|
|
.filter(Boolean)
|
|
.join('; ') || null,
|
|
}
|
|
}
|