问题根因: - pandas reindex(method='ffill') 只填充新增行的 NaN,不填充已存在的 NaN - 当 factor_df 中已有境外市场放假日期的 NaN 值时,reindex 无法填充 修复方案: - 改为两步操作:reindex() 然后 ffill() - ffill() 会填充所有 NaN,包括已存在的 验证结果: - 2026-04-30 HSI: None → 0.2388 ✅ - 2026-04-30 GDAXI: None → 0.5647 ✅ - 2026-05-08 HSI: None → 0.1144 ✅
框架 V2 - 重构版本
📋 设计理念
三层架构
framework_v2/
├── core/ # 纯抽象接口(零实现)
├── shared/ # 通用实现(2+策略复用)
└── tests/ # 框架测试
设计原则
- 按需抽象:不预先设计,只抽象已验证的通用逻辑
- 职责分离:数据获取、因子计算、信号生成、回测执行各司其职
- 向后兼容:与现有策略并行运行,验证一致后再替换
- 测试驱动:每个组件必须有对比验证测试
📚 文档
- 数据架构方案 - 完整的数据架构设计(Schema、验证、性能优化)
- 跨市场对齐方案 - CrossMarketAligner 使用指南
- 数据流完整推演 - 从 OHLCV 到最终收益的 7 个阶段推演
- Aligner + Schema 整合方案 - Pydantic Schema 与对齐器结合使用
- FlaskAPIFetcher 使用指南 - 通过 HTTP API 获取线上数据
🏗️ 目录结构
framework_v2/
├── __init__.py
├── README.md
│
├── core/ # 核心抽象接口
│ ├── __init__.py
│ ├── strategy.py # StrategyBase (ABC)
│ ├── factor.py # FactorBase (ABC)
│ ├── signal.py # SignalGenerator (ABC)
│ ├── executor.py # Executor (ABC)
│ └── data.py # DataFetcher (ABC)
│
├── shared/ # 通用实现
│ ├── __init__.py
│ ├── factors/
│ │ ├── __init__.py
│ │ ├── talib_base.py # TALibFactorBase (需要 talib)
│ │ └── momentum.py # 动量因子(已验证✓)
│ ├── data/
│ │ ├── __init__.py
│ │ └── alignment.py # 跨市场对齐器(已验证✓)
│ └── signals/ # 待实现
│ └── ...
│
└── tests/ # 测试
├── __init__.py
└── test_momentum_parity.py # 因子对比测试(通过✓)
✅ 已完成
阶段1: 核心接口层 ✓
- StrategyBase - 策略抽象基类
- FactorBase - 因子抽象基类
- SignalGenerator - 信号生成器抽象基类
- Executor - 执行器抽象基类
- DataFetcher - 数据获取器抽象基类
阶段2: 通用因子层 ✓
- MomentumFactor - 动量因子(完全复制现有逻辑)
- 对比验证测试(通过✓,差异 = 0)
阶段2.5: 数据对齐层 ✓
- CrossMarketAligner - 跨市场数据对齐器
- 解决 ffill 陷阱(价格 vs 收益率)
- 解决跨市场日历不对齐
- 解决 NaN 传播问题
- 完整测试套件(5/5 通过✓)
🎯 验证结果
MomentumFactor 对比测试
============================================================
MomentumFactor 对比测试
============================================================
1. 加载测试数据...
⚠ 未找到测试数据,使用模拟数据
2. 计算旧因子(strategies/shared/factors/momentum.py)...
✓ 旧因子计算完成
结果范围: -0.8515 ~ 8.5805
NaN 数量: 22
3. 计算新因子(framework_v2/shared/factors/momentum.py)...
✓ 新因子计算完成
结果范围: -0.8515 ~ 8.5805
NaN 数量: 22
4. 对比结果...
✓ 索引一致
最大差异: 0.000000e+00
平均差异: 0.000000e+00
✓ 差异在容差范围内 (< 1e-10)
============================================================
✓ 测试通过:新旧因子输出完全一致!
============================================================
📝 下一步计划
阶段3: 信号层迁移
- TopNSelector - Top N 选股器
- DynamicThreshold - 动态阈值(V3逻辑)
- RebalanceController - 调仓控制器
- 信号对比验证测试
阶段4: 执行层迁移
- BacktestRunner - 回测执行器
- 收益计算对比测试
阶段5: 数据层迁移
- RotationDataFetcher - 轮动策略数据获取器
- CrossMarketAligner - 跨市场对齐器
阶段6: 策略组装
- RotationStrategyV2 - 新框架轮动策略
- 完整策略对比测试
🔧 使用方法
运行测试
# 运行因子对比测试
python framework_v2/tests/test_momentum_parity.py
# 运行所有测试
python -m pytest framework_v2/tests/
使用新因子
from framework_v2.shared.factors import MomentumFactor
# 创建因子
factor = MomentumFactor(n_days=25, weighted=True, crash_filter=True)
# 计算因子值
import pandas as pd
data = pd.DataFrame({'close': [...]}, index=[...])
factor_values = factor.compute(data)
📊 与旧框架对比
| 维度 | 旧框架 (framework/) | 新框架 (framework_v2/) |
|---|---|---|
| 架构 | 抽象+实现混杂 | 三层分离(core/shared/tests) |
| 因子 | 独立实现 | TALibFactorBase + 定制继承 |
| 信号 | 包含所有逻辑 | 拆分为 Signal + Threshold + Rebalance |
| 数据 | 耦合在策略中 | DataFetcher 抽象 |
| 测试 | 部分覆盖 | 每个组件必须有对比测试 |
| 状态 | 生产环境 ✓ | 开发中 🚧 |
⚠️ 注意事项
- talib 依赖:TALibFactorBase 需要安装
ta-lib,但未安装不影响 MomentumFactor 使用 - 并行开发:新框架与旧框架并行,不修改现有代码
- 验证优先:每个模块迁移后立即验证,确保结果一致
创建日期: 2026-05-06 版本: 2.0.0