54 lines
2.7 KiB
Python
54 lines
2.7 KiB
Python
import sys, os
|
|
_VNPY_SRC = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "vnpy_v4.4.0"))
|
|
sys.path.insert(0, _VNPY_SRC)
|
|
|
|
import pandas as pd
|
|
import numpy as np
|
|
import empyrical
|
|
from sanguo_backtest.metrics import compute_metrics, MetricsResult, BENCHMARK_SYMBOL
|
|
|
|
def _make_daily(returns):
|
|
idx = pd.date_range("2024-01-01", periods=len(returns), freq="B")
|
|
return pd.DataFrame({"return": returns}, index=idx)
|
|
|
|
def test_compute_metrics_scalars_match_empyrical():
|
|
np.random.seed(42)
|
|
strat = pd.Series(np.random.normal(0.001, 0.02, 100),
|
|
index=pd.date_range("2024-01-01", periods=100, freq="B"))
|
|
bench = pd.Series(np.random.normal(0.0005, 0.015, 100), index=strat.index)
|
|
daily_df = pd.DataFrame({"return": strat.values}, index=strat.index)
|
|
|
|
res = compute_metrics(daily_df, bench)
|
|
assert isinstance(res, MetricsResult)
|
|
# 标量口径与 empyrical 直接计算一致
|
|
assert abs(res.scalars["alpha"] - empyrical.alpha(strat, bench)) < 1e-9
|
|
assert abs(res.scalars["beta"] - empyrical.beta(strat, bench)) < 1e-9
|
|
assert abs(res.scalars["sharpe_ratio"] - empyrical.sharpe_ratio(strat)) < 1e-9
|
|
assert abs(res.scalars["sortino_ratio"] - empyrical.sortino_ratio(strat)) < 1e-9
|
|
assert abs(res.scalars["max_drawdown"] - empyrical.max_drawdown(strat)) < 1e-9
|
|
assert abs(res.scalars["annual_volatility"] - empyrical.annual_volatility(strat)) < 1e-9
|
|
|
|
def test_compute_metrics_has_all_required_scalars():
|
|
strat = pd.Series([0.01, -0.005, 0.02, 0.0],
|
|
index=pd.date_range("2024-01-01", periods=4, freq="B"))
|
|
bench = pd.Series([0.005, 0.001, 0.01, -0.002], index=strat.index)
|
|
res = compute_metrics(pd.DataFrame({"return": strat.values}, index=strat.index), bench)
|
|
required = {"total_return","annual_return","alpha","beta","sharpe_ratio",
|
|
"sortino_ratio","information_ratio","annual_volatility","max_drawdown",
|
|
"benchmark_return","benchmark_volatility"}
|
|
assert required.issubset(res.scalars.keys())
|
|
|
|
def test_compute_metrics_series_keys_and_length():
|
|
strat = pd.Series(np.random.normal(0, 0.01, 50),
|
|
index=pd.date_range("2024-01-01", periods=50, freq="B"))
|
|
bench = pd.Series(np.random.normal(0, 0.01, 50), index=strat.index)
|
|
res = compute_metrics(pd.DataFrame({"return": strat.values}, index=strat.index), bench)
|
|
for key in ["equity_curve","benchmark_curve","alpha","beta","drawdown"]:
|
|
assert key in res.series
|
|
assert len(res.series[key]) == 50
|
|
assert res.series["drawdown"].max() <= 1e-9 # 回撤 <= 0
|
|
|
|
def test_benchmark_symbol_map():
|
|
assert BENCHMARK_SYMBOL["hs300"] == "sh000300"
|
|
assert BENCHMARK_SYMBOL["zz500"] == "sz000905"
|