37 lines
1.8 KiB
Python
37 lines
1.8 KiB
Python
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}")
|