Files
etf/docs/strategy_summaries/strategy_summary_20260606_ca933e4.md
aszerW 7b229ced14 docs: add strategy summary snapshot (2026-06-06, ca933e4)
First stage summary documenting core strategy logic, key design
decisions, and select_num/weight backtest comparison results.
Stored in dedicated docs/strategy_summaries/ directory with
date + commit hash naming for reproducibility.
2026-06-06 23:59:41 +08:00

8.6 KiB
Raw Blame History

ETF 轮动策略阶段总结

生成日期2026-06-06 Git Commitca933e4 复现方式git checkout ca933e4 后运行 rotation/simple_rotation.py


1. 策略概述

定位:基于动量因子的跨市场 ETF 轮动策略,通过每日截面排名在 11 个全球资产中选择强势标的,利用动量效应获取超额收益。

资产池11 个信号标的,覆盖 A 股、港股、美股、日股、欧洲、商品、债券七个大类。

大类 信号标的 交易 ETF 说明
A 股 399006.SZ 创业板指 159915.SZ 创业板 ETF
A 股 H30269.CSI 红利低波 512890.SH 红利低波 ETF
港股 HSI 恒生指数 159920.SZ 恒生 ETF
港股 HSTECH.HK 恒生科技 513130.SH 恒生科技 ETF 2020-07 上市
美股 NDX 纳指 100 513100.SH 纳指 ETF
日股 N225 日经 225 513520.SH 日经 ETF
欧洲 GDAXI 德国 DAX 513030.SH 德国 ETF
商品 GC=F 黄金期货 518880.SH 黄金 ETF
商品 HG=F 铜期货 159980.SZ 有色 ETF
商品 CL=F 原油期货 160723.SZ 嘉实原油
债券 931862.CSI 短债指数 931862.CSI 短债指数 防御配置

回测区间2020-01-10 ~ 2026-06-05共 1549 个交易日。


2. 核心逻辑流程

2.1 每日时间线

T 日 09:00  信号生成(使用 T-1 日及之前的收盘价)
     ↓
T 日 09:30  执行调仓(如触发)
     ↓
T 日 15:00  计算当日收益,更新 NAV

2.2 信号生成

动量因子:当前使用 slope_r2slope ×25 天回看窗口。

slope_r2_score = 10000 × slope × R²

其中:
  slope: 对归一化价格 p/p[0] 做线性回归的斜率
  R²:    回归决定系数(拟合优度)

该因子的设计意图:

  • slope 捕捉趋势方向和强度
  • 衡量趋势质量(高 R² = 趋势稳定,低 R² = 噪声大)
  • 二者相乘实现"趋势强度 × 拟合质量"的双重过滤

其他可用因子(通过配置切换):

因子 公式 特点
momentum (p[-1] / p[0]) - 1 简单收益率
weighted_momentum annualized_return × 加权回归
slope_r2 10000 × slope × 当前默认
standardized_slope slope / SE(slope) t 统计量
vol_adjusted_momentum (return / vol) × 类夏普构造

2.3 持仓选择

信号生成采用大类竞争 + 动态阈值 + 债券填充三层机制:

  1. 大类竞争:每个 group 内选动量 score 最高的标的作为 winner
  2. 动态阈值:非 BOND 组 winner 的 raw_momentum 必须 >= bond_momentum × ratio当前 ratio=1.0),否则被过滤
  3. 截面排名:所有通过阈值的 winner 按 score 降序排列,选 top-Nselect_num
  4. 债券填充:若 winner 数量不足 select_num用债券填充剩余 slot

债券的双重角色

  • 阈值过滤器:债券动量作为其他标的入选的动态门槛
  • 仓位填充:市场弱势时(多数标的动量低于债券),作为防御性持仓

2.4 调仓判定

is_rebalance = (sorted(new_holdings) != sorted(current_holdings)) and len(current_holdings) > 0

当新选出的持仓与当前持仓不同时触发调仓。调仓时扣除交易成本(默认 0.1%)。

2.5 仓位加权

支持两种模式,仅在调仓日更新权重(权重锁定机制):

equal等权

weight_i = 1/N

rank排名加权

weight_i = (N - i) / triangular(N)

其中 triangular(N) = N × (N + 1) / 2

以 select_num=3 为例:第 1 名 50%,第 2 名 33%,第 3 名 17%。

权重锁定机制

_generate_signals()  →  计算 _pending_weights每天仅用于信号选择
         ↓
run() 主循环         →  is_rebalance?
                       ├─ 是: active_weights = _pending_weights  (锁定新权重)
                       └─ 否: 保持 active_weights 不变           (权重不变)

这确保了持仓不变时,仓位权重不会因排名顺序变化而波动。

2.6 收益计算

场景 计算方式
调仓日 - 卖出 (open - prev_close) / prev_close × weight
调仓日 - 买入 (close - open) / open × weight
调仓日 - 调仓成本 -0.1%
非调仓日 - 持有 (close - prev_close) / prev_close × weight

3. 关键设计决策

决策 选择 原因
动量因子 slope × slope 捕捉趋势方向R² 过滤噪声趋势,双重过滤提升信噪比
回看窗口 25 天 中期动量(约 1 个月),平衡响应速度与噪声过滤
债券阈值 使用配置的因子函数 保持阈值两边量纲一致,仅在 VOL_ADJUSTED_MOMENTUM 时 fallback
权重锁定 仅调仓日更新 active_weights 避免持仓不变时权重随排名波动,减少无效换手
大类竞争 每组选 top 1 天然实现大类分散,避免同一大类集中持仓
交易成本 0.1% / 次 模拟真实 ETF 交易摩擦成本
信号时间 T-1 日收盘价 模拟 T 日 9:00 前可获取的信息,避免未来数据

4. 对比实验结果

4.1 实验矩阵

维度 取值
select_num 1, 2, 3
weight equal, rank
其他参数 与默认配置一致

共 6 组配置select_num=1 时 equal/rank 等价,实际 5 种独立结果)。

4.2 结果汇总

select_num weight 年化收益 夏普比率 最大回撤 Calmar
1 equal/rank 43.20% 1.246 -26.33% 1.641
2 equal 22.57% 1.082 -18.34% 1.230
2 rank 26.38% 1.117 -19.09% 1.382
3 equal 20.39% 1.160 -14.65% 1.392
3 rank 23.52% 1.150 -16.27% 1.446

4.3 关键发现

1. rank 加权系统性提升年化收益

在 select_num >= 2 时rank 加权相比 equal 加权:

  • select_num=226.38% vs 22.57%+3.81%
  • select_num=323.52% vs 20.39%+3.13%

原因rank 加权将更多仓位集中在排名最高的标的上,放大了动量最强的资产的收益贡献。

2. select_num=1 是收益天花板

单标的集中持仓实现了 43.20% 的年化收益,但代价是 -26.33% 的最大回撤。select_num=1 时 equal/rank 等价,因为只选 1 个标的。

3. equal 加权夏普比率略高

select_num equal 夏普 rank 夏普 差值
2 1.082 1.117 rank +0.035
3 1.160 1.150 equal +0.010

select_num=3 + equal 的夏普比率最高1.160),同时回撤最小(-14.65%),体现了分散化的风险调整优势。

4. Calmar 比率视角

  • select_num=1Calmar 1.641(收益/回撤最优)
  • select_num=3 + rankCalmar 1.446(多标的中最优)

5. 回撤控制

select_num 越大,回撤越小:

  • 1 标的:-26.33%
  • 2 标的:-18% ~ -19%
  • 3 标的:-14% ~ -16%

分散化有效降低了极端回撤。


5. 当前默认配置

rotation:
  diversified: true       # 大类竞争(每组选 top 1
  select_num: 3           # 持仓数量
  weight: rank            # 排名加权50%/33%/17%
  threshold:
    mode: dynamic
    dynamic:
      reference: 931862.CSI   # 债券作为动态阈值参考
      ratio: 1.0              # 阈值 = bond_momentum × 1.0
      fallback_enabled: true
      fallback_value: 0.0

factor:
  type: slope_r2          # 动量因子类型
  n_days: 25              # 回看窗口

rebalance:
  min_hold_days: 1
  trade_cost: 0.001       # 0.1% 交易成本

backtest:
  start_date: '2020-01-10'

benchmark:
  code: 000300.SH         # 沪深300作为基准

6. 代码文件索引

文件 职责
rotation/simple_rotation.py 核心策略引擎:动量因子、信号生成、回测主循环、收益计算
rotation/config_loader.py 配置加载Pydantic Schema、枚举类型、YAML 解析
rotation/config_simple.yaml 策略配置文件:资产池、因子、轮动、回测参数
rotation/backtest_viewer.html 回测可视化NAV 曲线、持仓明细、交易记录

核心函数速查

函数 位置 说明
slope_r2_score() simple_rotation.py 默认动量因子10000 × slope ×
compute_position_weights() simple_rotation.py 仓位加权equal / rank 两种模式
_generate_signals() simple_rotation.py 信号生成:大类竞争 + 阈值过滤 + 债券填充
_calculate_daily_return() simple_rotation.py 收益计算:调仓/持有两种场景
run() simple_rotation.py 回测主循环:每日迭代 + 权重锁定