Files
stock/backend/app/backtest/metrics.py
2026-08-07 16:08:34 +08:00

42 lines
1.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""绩效统计阶段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