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
|