""" 因子对比验证测试 验证新框架的 MomentumFactor 与现有实现输出一致 """ import sys import pandas as pd import numpy as np from pathlib import Path # 添加项目根目录 project_root = Path(__file__).parent.parent.parent sys.path.insert(0, str(project_root)) def test_momentum_factor_parity(): """验证新因子与旧因子输出一致""" print("=" * 60) print(" MomentumFactor 对比测试") print("=" * 60) # 1. 加载测试数据 print("\n1. 加载测试数据...") test_data_path = project_root / 'data' / 'index_history_data' # 使用纳指100数据测试 import glob ndx_files = glob.glob(str(test_data_path / '*NDX*')) if ndx_files: test_file = ndx_files[0] data = pd.read_csv(test_file, index_col=0, parse_dates=True) print(f" ✓ 加载 {test_file}") print(f" 数据范围: {data.index[0]} ~ {data.index[-1]}") print(f" 数据长度: {len(data)} 条") else: print(" ⚠ 未找到测试数据,使用模拟数据") # 生成模拟数据 np.random.seed(42) dates = pd.date_range('2020-01-01', periods=500, freq='B') prices = 100 * np.cumprod(1 + np.random.randn(500) * 0.02) data = pd.DataFrame({ 'close': prices, 'open': prices * 0.99, 'high': prices * 1.01, 'low': prices * 0.98, 'volume': np.random.randint(1000000, 10000000, 500) }, index=dates) # 2. 计算旧因子 print("\n2. 计算旧因子(strategies/shared/factors/momentum.py)...") from strategies.shared.factors.momentum import MomentumFactor as OldMomentum old_factor = OldMomentum(n_days=25, weighted=True, crash_filter=True) old_result = old_factor.compute(data) print(f" ✓ 旧因子计算完成") print(f" 结果范围: {old_result.min():.4f} ~ {old_result.max():.4f}") print(f" NaN 数量: {old_result.isna().sum()}") # 3. 计算新因子 print("\n3. 计算新因子(framework_v2/shared/factors/momentum.py)...") from framework_v2.shared.factors.momentum import MomentumFactor as NewMomentum new_factor = NewMomentum(n_days=25, weighted=True, crash_filter=True) new_result = new_factor.compute(data) print(f" ✓ 新因子计算完成") print(f" 结果范围: {new_result.min():.4f} ~ {new_result.max():.4f}") print(f" NaN 数量: {new_result.isna().sum()}") # 4. 对比结果 print("\n4. 对比结果...") # 检查索引是否一致 if not old_result.index.equals(new_result.index): print(" ✗ 索引不一致") return False print(" ✓ 索引一致") # 检查数值差异 diff = (old_result - new_result).abs() max_diff = diff.max() mean_diff = diff.mean() print(f" 最大差异: {max_diff:.6e}") print(f" 平均差异: {mean_diff:.6e}") # 允许浮点数精度误差(1e-10) tolerance = 1e-10 if max_diff < tolerance: print(f" ✓ 差异在容差范围内 (< {tolerance:.0e})") print("\n" + "=" * 60) print(" ✓ 测试通过:新旧因子输出完全一致!") print("=" * 60) return True else: print(f" ✗ 差异超出容差范围") print("\n" + "=" * 60) print(" ✗ 测试失败:新旧因子输出不一致") print("=" * 60) # 打印前10个差异点 diff_nonzero = diff[diff > tolerance] if len(diff_nonzero) > 0: print(f"\n 前10个差异点:") for date, val in diff_nonzero.head(10).items(): old_val = old_result.loc[date] new_val = new_result.loc[date] print(f" {date}: 旧={old_val:.6f}, 新={new_val:.6f}, 差异={val:.6e}") return False if __name__ == '__main__': success = test_momentum_factor_parity() sys.exit(0 if success else 1)