- 新增 finance/tests/ 6 个测试套件(agents/backtest/dao_upsert/factors/features/fundamental_lookahead) - 数据层: data_manager / dao 优化,新增 upsert 逻辑 - 因子层: 基本面因子抽象定位 _mapping、ROE/PE/PB 重构 - 回测层: vectorbt/engine 大改动(251 行),report 增强 - ML 层: features/backtest_integration 特征工程与回测优化 - CLI: agent_cli 重构 - config/settings 扩充配置项
71 lines
2.6 KiB
Python
71 lines
2.6 KiB
Python
"""
|
||
基本面因子前视回归测试:财报不得在披露日之前被回测看到。
|
||
"""
|
||
import sys
|
||
import os
|
||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||
|
||
import numpy as np
|
||
import pandas as pd
|
||
import pytest
|
||
|
||
from factors.fundamental.pe_pb import PEFactor
|
||
from factors.fundamental.roe import ROEFactor, ROETTMDeltaFactor
|
||
from factors.fundamental._mapping import map_fundamental_to_daily, effective_available_dates
|
||
|
||
INDICES = pd.date_range('2024-01-01', '2024-09-30', freq='B').strftime('%Y%m%d')
|
||
|
||
|
||
def _daily():
|
||
return pd.DataFrame({'close': np.full(len(INDICES), 10.0)}, index=INDICES)
|
||
|
||
|
||
def _fin_ann():
|
||
# 提供 ann_date(实际披露日):年报 4/25, 一季报 4/28, 中报 8/30
|
||
return pd.DataFrame({
|
||
'end_date': ['20231231', '20240331', '20240630'],
|
||
'ann_date': ['20240425', '20240428', '20240830'],
|
||
'eps': [1.0, 1.2, 1.5],
|
||
'roe': [0.10, 0.12, 0.15],
|
||
})
|
||
|
||
|
||
def test_lookahead_absent_before_disclosure():
|
||
daily = _daily()
|
||
mapped = map_fundamental_to_daily(daily, _fin_ann(), 'eps')
|
||
# 披露日(4/25)之前绝不可见任何财务值 → 消除前视
|
||
pre = mapped[mapped.index <= '20240424'].dropna()
|
||
assert pre.empty, "披露日前出现财务值 → 前视泄漏!"
|
||
# 4/25 起可见年报 eps=1.0
|
||
post = mapped[mapped.index >= '20240425'].dropna()
|
||
assert abs(float(post.iloc[0]) - 1.0) < 1e-6
|
||
|
||
|
||
def test_ann_date_refines_overlap():
|
||
daily = _daily()
|
||
mapped = map_fundamental_to_daily(daily, _fin_ann(), 'eps')
|
||
# 4/25-4/27 是年报(1.0),4/28 起切换为一季报(1.2)
|
||
band = mapped[(mapped.index >= '20240425') & (mapped.index <= '20240427')]
|
||
assert (band.dropna() == 1.0).all()
|
||
post = mapped[mapped.index >= '20240428'].dropna()
|
||
assert abs(float(post.iloc[0]) - 1.2) < 1e-6
|
||
|
||
|
||
def test_pe_roe_no_lookahead():
|
||
daily = _daily()
|
||
fin = _fin_ann()
|
||
for f in [PEFactor(fin), ROEFactor(fin), ROETTMDeltaFactor(fin)]:
|
||
s = f.calculate(daily)
|
||
pre = s[s.index <= '20240424'].dropna()
|
||
assert pre.empty, f"{f.name} 在披露日前出现值 → 前视泄漏"
|
||
|
||
|
||
def test_default_disclosure_lag_without_ann_date():
|
||
"""无 ann_date 时用法定滞后:年报(1231)→次年4/30。"""
|
||
daily = _daily()
|
||
fin = pd.DataFrame({'end_date': ['20231231'], 'eps': [1.0]})
|
||
mapped = map_fundamental_to_daily(daily, fin, 'eps')
|
||
pre = mapped[mapped.index <= '20240429'].dropna()
|
||
assert pre.empty, "无 ann_date 时财报不应在披露日前可见"
|
||
post = mapped[mapped.index >= '20240430'].dropna()
|
||
assert not post.empty |