from typing import Dict, List import numpy as np from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score class ModelEvaluator: @staticmethod def calculate_metrics(y_true, y_pred) -> Dict[str, float]: mae = mean_absolute_error(y_true, y_pred) rmse = mean_squared_error(y_true, y_pred, squared=False) mape = np.mean(np.abs((y_true - y_pred) / y_true)) * 100 r2 = r2_score(y_true, y_pred) return { "mae": float(mae), "rmse": float(rmse), "mape": float(mape) if not np.isnan(mape) else 0.0, "r2": float(r2), } @staticmethod def calculate_sharpe_ratio(returns: np.ndarray, risk_free_rate: float = 0.0) -> float: if len(returns) == 0 or np.std(returns) == 0: return 0.0 excess_returns = returns - risk_free_rate return float(np.mean(excess_returns) / np.std(excess_returns)) @staticmethod def calculate_max_drawdown(values: np.ndarray) -> float: if len(values) == 0: return 0.0 cumulative = np.cumsum(values) running_max = np.maximum.accumulate(cumulative) drawdown = (cumulative - running_max) return float(drawdown.min()) class BacktestEvaluator: def __init__(self): self.trades: List[Dict] = [] def add_trade(self, trade: Dict): self.trades.append(trade) def evaluate(self) -> Dict[str, float]: if not self.trades: return { "total_revenue": 0.0, "total_trades": 0, "win_rate": 0.0, "sharpe_ratio": 0.0, "max_drawdown": 0.0, } total_revenue = sum(t.get("revenue", 0) for t in self.trades) winning_trades = sum(1 for t in self.trades if t.get("revenue", 0) > 0) win_rate = winning_trades / len(self.trades) if self.trades else 0.0 returns = np.array([t.get("revenue", 0) for t in self.trades]) sharpe_ratio = ModelEvaluator.calculate_sharpe_ratio(returns) max_drawdown = ModelEvaluator.calculate_max_drawdown(returns) return { "total_revenue": total_revenue, "total_trades": len(self.trades), "win_rate": win_rate, "sharpe_ratio": sharpe_ratio, "max_drawdown": max_drawdown, } def reset(self): self.trades = [] __all__ = ["ModelEvaluator", "BacktestEvaluator"]