Files
sanguo_vnpy_v2/tests/factor/test_fundamental_batch.py
T
claude_dev caa72d3426 feat(factor): batch_eval接入财务因子——特征列join+端到端IC(财务批P0 WP3) [nas]
- run_batch_eval 增 fund_data_dir 参数;仅因子列表含 category=fundamental 时
  build_fundamental_features(bars 的 codes+trading_dates) join 进 alpha_df
  (列白名单经 join 扩展,量价批零开销零改动路径)
- __init__ 补挂 fundamental_library(import sanguo_factor 全家可见)
- 端到端3测: 财务4因子IC落库/量价+财务混批/纯量价无静态域回归
- 修顺序依赖: 其它测试清 _REGISTRY 只重挂alpha → 本批两模块 autouse 幂等重注册

[nas]

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-09-08 09:31:52 +08:00

102 lines
4.2 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.
# tests/factor/test_fundamental_batch.py
"""财务因子批端到端: 合成行情库 + 合成静态域 → batch_eval 出 IC 指标."""
import sqlite3
import sys, os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "vnpy_v4.4.0")))
import pytest
from sanguo_factor import alpha_datasets # 挂载量价因子
from sanguo_factor import fundamental_library # noqa: F401 挂载财务因子(import 即注册)
from sanguo_factor.batch_eval import run_batch_eval
from sanguo_factor import eval_store
@pytest.fixture(autouse=True)
def _ensure_fundamental_registered():
"""其它测试模块清空 _REGISTRY 后只重挂 alpha/builtin(顺序依赖前科),
这里逐测试幂等重注册财务因子,保证本模块与顺序无关."""
fundamental_library._register_all()
_DDL = """
CREATE TABLE dbbardata(
symbol TEXT, exchange TEXT, datetime TEXT, interval TEXT,
volume REAL, turnover REAL, open_interest REAL,
open_price REAL, high_price REAL, low_price REAL, close_price REAL)
"""
_STOCKS = [("600000", "SSE"), ("000001", "SZSE"), ("300001", "SZSE")]
@pytest.fixture(scope="module")
def db(tmp_path_factory):
"""3 只 × 2022-06~2024-01 合成日线(与合成财务域同代码;趋势构造截面差异)."""
alpha_datasets.mount_all()
p = tmp_path_factory.mktemp("fb")
db = str(p / "qt.db")
conn = sqlite3.connect(db)
conn.execute(_DDL)
import pandas as pd
days = pd.bdate_range("2022-06-01", "2024-01-05")
drift = {"600000": 0.0012, "000001": -0.0006, "300001": 0.0004}
base = {"600000": 10.0, "000001": 5.0, "300001": 20.0}
for i, day in enumerate(days):
d = day.strftime("%Y-%m-%d")
rows = []
for sym, ex in _STOCKS:
px = base[sym] * (1.0 + drift[sym]) ** i
rows.append((sym, ex, f"{d} 00:00:00", "d", 100.0, px * 100.0, 0,
px, px, px, px))
conn.executemany("INSERT INTO dbbardata VALUES(?,?,?,?,?,?,?,?,?,?,?)", rows)
conn.commit()
conn.close()
return db
def test_fundamental_end_to_end(db, synthetic_static, tmp_path):
eval_db = str(tmp_path / "fund_eval.db")
out = run_batch_eval(
factor_names=["fund_roe_ttm", "fund_tacc", "fund_ep_ttm",
"fund_forecast_type"],
start="2023-02-01", end="2023-12-31",
eval_db=eval_db, label="fund_t", cfg=None, vnpy_db_override=db,
fund_data_dir=synthetic_static,
)
assert out["factors_done"] == 4
assert out["errors"] == []
for name in ("fund_roe_ttm", "fund_tacc", "fund_ep_ttm", "fund_forecast_type"):
m = eval_store.get_detail(eval_db, out["run_id"], name)["metrics"]
assert "error" not in m, f"{name}: {m.get('error')}"
# 截面 3 只 → 逐日 rank IC 可算(预告因子 2023-07-15 后才有效, count 少但非零)
assert isinstance(m["1"]["ic_mean"], float) or m["1"]["ic_mean"] is None
assert m["1"]["count"] >= 0
def test_mixed_batch_price_plus_fundamental(db, synthetic_static, tmp_path):
"""量价+财务同批混跑: 白名单 join 只在含财务因子时发生,互不干扰."""
eval_db = str(tmp_path / "mix_eval.db")
out = run_batch_eval(
factor_names=["ma_20", "fund_sue_np"],
start="2023-02-01", end="2023-06-30",
eval_db=eval_db, label="mix_t", cfg=None, vnpy_db_override=db,
fund_data_dir=synthetic_static,
)
assert out["errors"] == []
rows = eval_store.get_rows(eval_db, out["run_id"])
assert {r["factor"] for r in rows} == {"ma_20", "fund_sue_np"}
# SUE 在 2023-06-30 前可见的报告期均无完整 8 期窗 → 全 NaN → eliminated 非 error
m = eval_store.get_detail(eval_db, out["run_id"], "fund_sue_np")["metrics"]
assert "error" not in m
def test_pure_price_batch_untouched(db, tmp_path):
"""纯量价批不传静态域照常跑(回归: 未新增强依赖)."""
eval_db = str(tmp_path / "px_eval.db")
out = run_batch_eval(
factor_names=["roc_5"], start="2023-02-01", end="2023-03-31",
eval_db=eval_db, label="px_t", cfg=None, vnpy_db_override=db,
)
assert out["errors"] == []
assert out["factors_done"] == 1