import numpy as np import pandas as pd def compute_metrics(trades: pd.DataFrame, equity: pd.Series, initial: float) -> dict: m = {"trades": int(len(trades)), "initial": initial} final = float(equity.iloc[-1]) if len(equity) else initial m["final"] = final m["net"] = final - initial m["return_pct"] = (final / initial - 1) * 100 if len(equity): peak = equity.cummax() m["max_dd_pct"] = float(((peak - equity) / peak).max() * 100) daily = equity.groupby(equity.index.date).last().pct_change().dropna() m["sharpe"] = float(daily.mean() / daily.std() * np.sqrt(252)) if len(daily) > 5 and daily.std() > 0 else 0.0 else: m["max_dd_pct"], m["sharpe"] = 0.0, 0.0 if len(trades): w, l = trades[trades.pnl > 0].pnl, trades[trades.pnl <= 0].pnl m["win_rate"] = len(w) / len(trades) * 100 m["profit_factor"] = float(w.sum() / -l.sum()) if l.sum() < 0 else float("inf") m["expectancy"] = float(trades.pnl.mean()) m["avg_win"] = float(w.mean()) if len(w) else 0.0 m["avg_loss"] = float(l.mean()) if len(l) else 0.0 m["avg_r"] = float(trades.r.mean()) streak = best = 0 for p in trades.pnl: streak = streak + 1 if p <= 0 else 0 best = max(best, streak) m["max_loss_streak"] = best else: m.update(win_rate=0.0, profit_factor=0.0, expectancy=0.0, avg_win=0.0, avg_loss=0.0, avg_r=0.0, max_loss_streak=0) return m def fmt(m: dict) -> str: pf = "inf" if m["profit_factor"] == float("inf") else f"{m['profit_factor']:.2f}" return (f"Trades {m['trades']} | Net {m['net']:+.0f}$ ({m['return_pct']:+.1f}%) | " f"Winrate {m['win_rate']:.0f}% | PF {pf} | MaxDD {m['max_dd_pct']:.1f}% | Sharpe {m['sharpe']:.2f}")