Files
sanguo_vnpy_v2/sanguo_factor/composite_rolling.py
T

63 lines
2.9 KiB
Python

"""合成层 v2c(Rolling): 滚动制度因子注册——每年一份权重制度,档案扫描批量挂载.
v2c 语义: 权重不再是全期单档案,而是按年滚动——每年一份"制度"档案
weight_profiles/{scope}_roll_{year}.json(数据拟合产出,scope=quant12/all18),
注册为 composite_v2c_{scope}_{year};跑批按年段评估后离线拼接(本模块只管
注册机制,不做拼接).
文件名 → 因子名约定: year 取档案名尾部 4 位数字(20 开头),scope 取 _roll_
前段;不合约定的文件(v2a/v2b 档案等)不纳入扫描.依赖完全复用 composite_
weighting(v2a)管线: load_profile 校验 + register_composite_from_profile
三源表匹配/0 权项跳过/幂等注册._register_all 先幂等重挂 v2a 依赖链
(v1.1 源+neu+v2a/v2b 默认档案),再逐滚动档案注册;单档案失败 raise 且带
文件名——制度期缺失会让年段拼接静默少一段,宁可失败不静默吞.
"""
import re
from pathlib import Path
from . import composite_weighting
from .composite_weighting import load_profile, register_composite_from_profile
# 滚动档案目录: 相对本文件定位(与代码同仓同版本,不依赖 cwd)
_PROFILE_DIR = Path(__file__).parent / "weight_profiles"
# 约定名: {scope}_roll_{year}.json(year=尾部 4 位数字,20 开头)
_ROLLING_NAME_RE = re.compile(r"^(?P<scope>[a-z0-9]+)_roll_(?P<year>20\d{2})\.json$")
def _iter_rolling_profiles() -> list[tuple[str, Path]]:
"""扫描 weight_profiles/ 下约定名滚动档案,返回 (因子名, 路径) 列表.
排序稳定 (scope 字典序, year 升序);非约定名文件(v2a/v2b 档案/非 json)
不纳入——因子名排序与 (scope,year) 元组序在 scope 互为前缀时会分叉,
故显式按元组排,不依赖名字串序.
"""
entries: list[tuple[str, str, Path]] = []
for path in _PROFILE_DIR.iterdir():
m = _ROLLING_NAME_RE.match(path.name)
if m is not None:
entries.append((m["scope"], m["year"], path))
entries.sort(key=lambda e: (e[0], e[1]))
return [(f"composite_v2c_{scope}_{year}", path) for scope, year, path in entries]
def _register_all() -> None:
"""幂等注册全部滚动制度因子(先幂等重挂 v2a 依赖链,再逐滚动档案注册).
单档案加载/注册失败 raise 且带文件名(防静默丢制度期);registry 被清后
可独立重建(v2a 的 _register_all 幂等重挂 v1.1 源+neu+默认档案).
"""
composite_weighting._register_all()
for name, path in _iter_rolling_profiles():
try:
register_composite_from_profile(load_profile(str(path)), name)
except Exception as e:
raise ValueError(f"滚动制度档案加载/注册失败({path.name}): {e}") from e
# 模块导入时自动注册(与 composite_weighting 同模式);失败给可读错误(fail-fast)
try:
_register_all()
except Exception as e:
raise ImportError(f"合成层 v2c 滚动制度因子注册失败({_PROFILE_DIR}): {e}") from e