42 lines
1.4 KiB
Python
42 lines
1.4 KiB
Python
"""绩效统计(阶段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
|