Files
ProStock/tests/test_factorminer_e2e.py
liaozhaorun 45469c8fed feat(factorminer): 新增 LocalFactorEvaluator 集成到评估管线
- 新增 LocalFactorEvaluator 类封装 FactorEngine,提供 (M,T) 矩阵输出
- evaluate_factors_with_evaluator() 支持新评估方式
- ValidationPipeline 优先使用 evaluator 计算信号
- 新增测试文件验证功能
2026-04-11 01:53:43 +08:00

118 lines
3.7 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.
"""端到端集成测试:验证 110 个 Paper Factors 能被本地引擎计算。
测试目标:
1. 加载 paper factors 库
2. 使用 LocalFactorEvaluator 计算每个因子
3. 验证输出形状为 (M, T) 且不含全 NaN
4. 统计成功率和跳过数
运行命令uv run pytest tests/test_factorminer_e2e.py -v
"""
import pytest
def test_paper_factors_e2e():
"""端到端测试:验证 110 个 Paper Factors 能被本地引擎计算。
注意:此测试需要数据库中有 pro_bar 数据。
如果数据不足,会在计算时失败。
"""
from src.factorminer.core.library_io import import_from_paper
from src.factorminer.evaluation.local_engine import LocalFactorEvaluator
# 1. 加载 paper factors 库
library = import_from_paper()
factors = library.list_factors()
total = len(factors)
print(f"\n[e2e] 总计加载 {total} 个因子")
# 2. 过滤 unsupported 因子
supported_factors = [f for f in factors if not f.metadata.get("unsupported", False)]
unsupported_count = total - len(supported_factors)
print(f"[e2e] 可计算因子 {len(supported_factors)}")
print(f"[e2e] 跳过(未实现算子){unsupported_count}")
if not supported_factors:
print("[e2e] 没有可计算的因子,测试跳过")
pytest.skip("No supported factors to test")
# 3. 实例化 LocalFactorEvaluator
evaluator = LocalFactorEvaluator(
start_date="20200101",
end_date="20201231",
)
# 4. 批量计算每个因子
success_count = 0
fail_count = 0
skip_count = 0
specs = [(f.name, f.formula) for f in supported_factors]
print(f"[e2e] 开始批量计算 {len(specs)} 个因子...")
try:
results = evaluator.evaluate(specs)
except Exception as e:
print(f"[e2e] 批量计算失败: {e}")
pytest.fail(f"Batch evaluation failed: {e}")
# 5. 验证结果
for name, result in results.items():
if result is None:
fail_count += 1
continue
# 检查形状
if result.ndim != 2:
print(f"[e2e] 因子 {name} 形状错误: {result.ndim}D期望 2D")
fail_count += 1
continue
# 检查是否全 NaN
if np.isnan(result).all():
print(f"[e2e] 因子 {name} 输出全为 NaN")
fail_count += 1
continue
success_count += 1
print(
f"[e2e] 成功 {success_count}/{total}"
f"跳过 {skip_count} 个,失败 {fail_count}"
)
# 断言:至少 50% 的因子能成功计算(宽松标准)
success_rate = success_count / total
assert success_rate >= 0.5, f"成功率 {success_rate:.1%} 低于 50% 阈值"
if __name__ == "__main__":
import numpy as np
from src.factorminer.core.library_io import import_from_paper
from src.factorminer.evaluation.local_engine import LocalFactorEvaluator
# 手动运行测试
library = import_from_paper()
factors = library.list_factors()
total = len(factors)
print(f"\n[e2e] 总计加载 {total} 个因子")
supported_factors = [f for f in factors if not f.metadata.get("unsupported", False)]
unsupported_count = total - len(supported_factors)
print(f"[e2e] 可计算因子 {len(supported_factors)}")
print(f"[e2e] 跳过(未实现算子){unsupported_count}")
if supported_factors:
evaluator = LocalFactorEvaluator(
start_date="20200101",
end_date="20201231",
)
specs = [(f.name, f.formula) for f in supported_factors]
print(f"[e2e] 开始批量计算 {len(specs)} 个因子...")
results = evaluator.evaluate(specs)
print(f"[e2e] 批量计算完成,共 {len(results)} 个结果")