first commit
This commit is contained in:
41
backend/app/backtest/metrics.py
Normal file
41
backend/app/backtest/metrics.py
Normal file
@@ -0,0 +1,41 @@
|
||||
"""绩效统计(阶段1 补基准归因:超额/信息比率/beta/alpha)。"""
|
||||
from __future__ import annotations
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
|
||||
def compute_metrics(equity: pd.Series, bars_per_year: int = 252) -> dict:
|
||||
equity = equity.dropna()
|
||||
if len(equity) < 2 or equity.iloc[0] == 0:
|
||||
return {"total_return": 0.0, "max_drawdown": 0.0, "sharpe": 0.0,
|
||||
"volatility": 0.0, "win_rate": 0.0}
|
||||
|
||||
total_return = float(equity.iloc[-1] / equity.iloc[0] - 1)
|
||||
|
||||
returns = equity.pct_change().dropna()
|
||||
cummax = equity.cummax()
|
||||
drawdown = (equity - cummax) / cummax
|
||||
max_drawdown = float(abs(drawdown.min()))
|
||||
|
||||
std = float(returns.std())
|
||||
sharpe = float(returns.mean() / std * np.sqrt(bars_per_year)) if std > 0 else 0.0
|
||||
volatility = std * np.sqrt(bars_per_year)
|
||||
|
||||
return {
|
||||
"total_return": total_return,
|
||||
"max_drawdown": max_drawdown,
|
||||
"sharpe": sharpe,
|
||||
"volatility": float(volatility),
|
||||
"win_rate": 0.0, # 由 engine 用成交对计算后注入
|
||||
}
|
||||
|
||||
|
||||
def win_rate_from_fills(fills) -> float:
|
||||
"""按"卖出-对应买入"配对估算胜率(粗略,阶段1 用 FIFO 精确配对)。"""
|
||||
sells = [f for f in fills if f.side.value == "sell"]
|
||||
if not sells:
|
||||
return 0.0
|
||||
wins = sum(1 for f in fills if f.side.value == "sell" and f.price > 0)
|
||||
# 简化:有成交即计;真实胜率需配对,这里先返回 0 占位,由 engine 精算
|
||||
return 0.0
|
||||
Reference in New Issue
Block a user