mirror of
https://ghfast.top/https://github.com/aeroxw/easy-tdx.git
synced 2026-09-12 22:44:17 +08:00
mypy (13 errors → 0): - portfolio/optimizer: register_optimizer 返回类型改为 Callable 装饰器签名 (原标注 type[WeightOptimizer] 导致 4 个子类 Too many arguments) - factor/engine: _datetime_to_int 用 isinstance 收窄替代 object→int 强转 - factor/analysis: 删多余 type:ignore(改由 mypy override 统一处理 scipy) - backtest/orders, execution: np.sqrt 表达式用 float() 包裹消除 no-any-return - MyTT.pyi: MACD 签名删除错误的 LOW/HIGH 参数(与 MyTT.py 实际签名对齐) - pyproject: 新增 scipy mypy override (ignore_missing_imports) ruff format: 8 个 test 文件格式化 验证: 564 passed, mypy 192 文件零错误, ruff check/format 全绿
46 lines
1.5 KiB
Python
46 lines
1.5 KiB
Python
"""Test RiskModel."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import numpy as np
|
|
import pandas as pd
|
|
|
|
from easy_tdx.portfolio.risk import RiskModel
|
|
|
|
|
|
def _make_returns(n_dates: int = 100, n_stocks: int = 5, seed: int = 42) -> pd.DataFrame:
|
|
rng = np.random.default_rng(seed)
|
|
codes = [f"{i:06d}" for i in range(n_stocks)]
|
|
return pd.DataFrame(rng.normal(0.001, 0.02, (n_dates, n_stocks)), columns=codes)
|
|
|
|
|
|
class TestCovarianceEstimation:
|
|
def test_shape(self):
|
|
cov = RiskModel().estimate_covariance(_make_returns())
|
|
assert cov.shape == (5, 5)
|
|
|
|
def test_symmetric(self):
|
|
cov = RiskModel().estimate_covariance(_make_returns())
|
|
assert np.allclose(cov.to_numpy(), cov.to_numpy().T)
|
|
|
|
def test_shrinkage_reduces_offdiag(self):
|
|
rm = RiskModel()
|
|
ret = _make_returns()
|
|
shrunk = rm.estimate_covariance(ret, method="shrinkage")
|
|
sample = rm.estimate_covariance(ret, method="sample")
|
|
off_shrunk = shrunk.values[~np.eye(5, dtype=bool)]
|
|
off_sample = sample.values[~np.eye(5, dtype=bool)]
|
|
assert np.abs(off_shrunk).mean() <= np.abs(off_sample).mean()
|
|
|
|
|
|
class TestPortfolioRisk:
|
|
def test_total_volatility(self):
|
|
cov = RiskModel().estimate_covariance(_make_returns())
|
|
risk = RiskModel().portfolio_risk({"000000": 0.5, "000001": 0.5}, cov)
|
|
assert risk["total_volatility"] > 0
|
|
assert risk["n_positions"] == 2
|
|
|
|
def test_empty_weights(self):
|
|
risk = RiskModel().portfolio_risk({}, pd.DataFrame())
|
|
assert risk["total_volatility"] == 0.0
|