feat(framework_v2): 对齐 V1 配置,实现指数信号→ETF收益回测

配置对齐:
- config_simple.yaml 严格对齐 V1 config.yaml
  * 11 个标的覆盖 7 个策略分组
  * 回测区间: 2020-01-01 ~ 至今
  * 选股数量: Top-3,强制分散化
  * V3 动态阈值(短债动量参考)
  * 溢价控制启用(HK/US 10%阈值)

策略实现:
- SimpleRotationStrategy 支持 signal_source/trade_source 分离
  * get_codes() 同时获取信号和交易标的
  * compute_factors() 只使用 signal_source 计算因子
  * _execute_backtest() 使用 trade_source 计算收益
  * 支持跨市场场景(指数信号 → ETF收益)

回测验证:
- 成功运行端到端回测
- 获取 21 个标的(11 signal + 10 trade)
- 平均仓位 84.42%
- ⚠️ 已知问题: Flask API 只返回缓存数据(2026年),需修复

修复项:
- StrategyBase.run() 兼容信号矩阵(移除 'weight' 列假设)
This commit is contained in:
2026-05-24 14:58:41 +08:00
parent 43ce8056f1
commit e6657bd2cc
4 changed files with 264 additions and 52 deletions

View File

@@ -0,0 +1,98 @@
"""
简单轮动策略回测脚本
测试场景:指数信号 → ETF收益
- 使用指数计算动量信号
- 使用 ETF 计算收益
"""
import sys
from pathlib import Path
# 添加项目根目录到 Python 路径
project_root = Path(__file__).parent.parent.parent
sys.path.insert(0, str(project_root))
from framework_v2.config import load_config
from framework_v2.strategies.rotation.simple import SimpleRotationStrategy
def run_backtest():
"""运行回测"""
print("=" * 70)
print(" ETF轮动策略回测V2 框架)")
print(" 场景:指数信号 → ETF收益复现 V1 结果")
print("=" * 70)
# 加载配置
config_file = project_root / "framework_v2" / "strategies" / "rotation" / "config_simple.yaml"
print(f"\n配置文件: {config_file}")
config = load_config(str(config_file))
# 打印配置摘要
print("\n" + "=" * 70)
print(" 配置摘要")
print("=" * 70)
print(f"策略名称: {config.metadata.strategy}")
print(f"回测区间: {config.backtest.start_date} ~ {config.backtest.end_date or '至今'}")
print(f"因子类型: {config.factor.type.value}")
print(f"动量窗口: {config.factor.n_days}")
print(f"选股数量: {config.rotation.select_num}")
# 打印资产池
print(f"\n资产池 ({config.asset_pools.count()} 个标的):")
for code, asset in config.asset_pools.assets.items():
print(f" {code}: {asset.name}")
print(f" 分组: {asset.group}")
print(f" 信号: {asset.signal_source}")
print(f" 交易: {asset.trade_source}")
print(f" 跨市场: {'' if asset.is_cross_market else ''}")
# 创建策略
print("\n" + "=" * 70)
print(" 运行回测...")
print("=" * 70)
strategy = SimpleRotationStrategy(config)
result = strategy.run()
# 打印结果
print("\n" + "=" * 70)
print(" 回测结果")
print("=" * 70)
metrics = result['metrics']
print(f"总收益: {metrics['total_return']:.2%}")
print(f"年化收益: {metrics['annual_return']:.2%}")
print(f"最大回撤: {metrics['max_drawdown']:.2%}")
print(f"夏普比率: {metrics['sharpe_ratio']:.2f}")
print(f"交易天数: {metrics['n_days']}")
# 打印净值曲线
equity_curve = result['equity_curve']
print(f"\n净值曲线:")
print(f" 起始净值: {equity_curve.iloc[0]:.4f}")
print(f" 结束净值: {equity_curve.iloc[-1]:.4f}")
print(f" 数据点数: {len(equity_curve)}")
# 保存结果
output_dir = project_root / "framework_v2" / "results"
output_dir.mkdir(exist_ok=True)
# 保存净值曲线
equity_curve.to_csv(output_dir / "simple_rotation_equity.csv")
print(f"\n净值曲线已保存: {output_dir / 'simple_rotation_equity.csv'}")
# 保存持仓记录
positions = result['positions']
positions.to_csv(output_dir / "simple_rotation_positions.csv")
print(f"持仓记录已保存: {output_dir / 'simple_rotation_positions.csv'}")
print("\n" + "=" * 70)
print(" 回测完成!")
print("=" * 70)
if __name__ == "__main__":
run_backtest()