Files
etf/docs/动态ETF池筛选引擎-调研与方案.md
aszerW 2829f80427 feat(backtest): 消除前视偏差,实现动态ETF池重建
消除回测前视偏差(Look-Ahead Bias):
- 新增 ETFDataCache 本地缓存系统,预下载全量ETF(含已退市)基础信息和日线数据
- 改造 ETFUniverseBuilder 支持纯历史模式,每个时间点只使用当时可获得的数据
- 动量.py 新增 dynamic 模式,回测中每60交易日动态重建ETF候选池
- momentum_experiment.py 同步支持动态重建
- 新增 ETF筛选引擎文档和动态池方案文档

无前视偏差实验结果(6组对比,2015-2026):
  A: 全仓1只       CAGR=3.32%, MaxDD=-63.19%, Sharpe=0.26
  B: 等权3只       CAGR=3.40%, MaxDD=-49.72%, Sharpe=0.30 ← 最优
  C: 反波动率3只   CAGR=1.73%, MaxDD=-38.59%, Sharpe=0.21
  D: 等权5只       CAGR=2.77%, MaxDD=-42.39%, Sharpe=0.29
  E: 反波动率5只   CAGR=-0.37%, MaxDD=-19.56%, Sharpe=-0.03
  F: 动量>0全选等权 CAGR=2.02%, MaxDD=-43.27%, Sharpe=0.24

最优方案: B(等权3只)夏普、Calmar、CAGR三项均最高
2026-04-29 22:15:01 +08:00

10 KiB
Raw Blame History

动态ETF池自动化筛选引擎 — 调研与方案

1. 问题背景

当前ETF轮动策略的标的池是人工预选的存在严重的幸存者偏差。回测对比实验显示:

标的池 累计收益 CAGR 最大回撤
9只精选ETF (全仓1只, 2015-2026) 2733.60% 34.38% -32.79%
20只行业ETF (全仓1只, 2015-2026) 208.16% 10.46% -67.16%
20只轮动ETF (等权5只, 2020-2026) 171.36% 17.48% -30.85%

结论: 标的池选择是策略最大的 alpha 来源,需要构建系统化、无偏差的动态筛选能力。


2. 学术论文与权威机构调研

2.1 TrendFolios (UCLA, 2024)

  • 论文: Lu et al. "TrendFolios: A Portfolio Construction Framework for Utilizing Momentum and Trend-Following In a Multi-Asset Portfolio"
  • 来源: arxiv:2506.09330
  • 核心方法:
    • 按资产类别的风险因子对ETF进行分类
    • Universe 随时间自然扩展 — 新ETF上市后才纳入杜绝前视偏差
    • 结合趋势跟踪信号与动量因子构建多资产组合
  • 对本方案的启发: Layer 3 资产标签化设计 + 滚动重建机制中的无前视偏差原则

2.2 AEGIS (2024)

  • 论文: Chakraborty & Singh. "Taming the Black Swan: A Momentum-Gated Hierarchical Optimisation Framework"
  • 来源: arxiv:2604.09060
  • 核心方法:
    • 流动性硬门槛: FALR (Fraction of Available Liquidity Ratio) >= 0.75
    • 每年根据动量领先者重建 universe
    • 分层优化框架: 先筛选 universe → 动量门控 → 层次化权重优化
  • 对本方案的启发: Layer 1 流动性过滤的硬门槛设计 + 定期重建机制

2.3 HRP — Hierarchical Risk Parity (Lopez de Prado, 2016)

  • 论文: Lopez de Prado. "Building Diversified Portfolios that Outperform Out-of-Sample"
  • 来源: SSRN:2708678
  • 核心方法:
    • 基于收益率相关性矩阵进行层次聚类Hierarchical Clustering
    • 将资产分为互不相关的簇,同簇内取代表性资产
    • 相比传统均值-方差优化HRP 在样本外表现更稳健,不依赖协方差矩阵求逆
  • 对本方案的启发: Layer 5 相关性优化选择算法的理论基础

2.4 Faber GTAA — Global Tactical Asset Allocation (2006)

  • 论文: Faber. "A Quantitative Approach to Tactical Asset Allocation"
  • 来源: SSRN:962461
  • 核心方法:
    • 选择 5-13 个大类资产ETF每个代表一个独立的经济驱动因子
    • 用 10 个月移动平均线作为趋势信号(价格 > MA10 则持有,否则转现金)
    • 关键洞察: 资产类别的覆盖度比选择数量更重要
  • 对本方案的启发: Universe 设计原则 — 确保风险因子全覆盖股票、债券、商品、REITs、外汇

2.5 Antonacci Dual Momentum (2012)

  • 论文: Antonacci. "Risk Premia Harvesting Through Dual Momentum"
  • 来源: SSRN:2042750
  • 核心方法:
    • 绝对动量 (时间序列动量): 资产自身是否处于上升趋势
    • 相对动量 (横截面动量): 资产间的相对强弱排序
    • 资产对pairs作为构建模块每对代表一个风险溢价
    • 当绝对动量为负时,转入债券避险
  • 对本方案的启发: 跨资产分散化设计理念 — 每个资产类别用"对"来覆盖

2.6 Jegadeesh & Titman (1993) — 动量效应经典文献

  • 论文: "Returns to Buying Winners and Selling Losers: Implications for Stock Market Efficiency"
  • 来源: Journal of Finance, 48(1), 65-91
  • 核心发现:
    • 买入过去 3-12 个月的赢家、卖出输家,可获得显著超额收益
    • 动量效应在不同市场、不同时期持续存在
    • 这是所有动量策略的学术基石

2.7 华宝基金动量优选基金 (业界实践)

  • 来源: 华宝基金动量优选混合型基金招募说明书
  • 实践方法:
    • 年度 ETF 池调整(非固定池)
    • 行业、风格、主题多维度覆盖
    • 定量筛选 + 基金经理主观判断结合
  • 对本方案的启发: 实业级重建周期参考(年度/季度)

3. 方案设计:多层漏斗筛选

3.1 架构概览

全量ETF (~1000只)
    |
    v  [Layer 1] 基础过滤 (流动性/类型/上市时间)
约300只
    |
    v  [Layer 2] 同指数去重 (每个指数只留1只最优ETF)
约200只
    |
    v  [Layer 3] 大类资产标签化 (自动分类)
约200只 (含标签)
    |
    v  [Layer 4] 类内预筛选 (每类留Top-N)
约30-50只
    |
    v  [Layer 5] 相关性优化选择 (贪心/HRP聚类)
10-15只 最终池

3.2 Layer 1 — 基础过滤(硬性门槛)

过滤条件 原因
上市满1年 新基金数据不足,无法计算有效因子
日均成交额 > 5000万 流动性不足会导致冲击成本过大 (参考AEGIS的FALR门槛)
非货币/非债券增强类 货币基金无轮动意义
非杠杆/非反向ETF 杠杆ETF不适合持有
有明确跟踪指数 需要指数数据计算因子

3.3 Layer 2 — 同指数去重

一个指数可能有 20+ 只 ETF 跟踪如沪深300有30+只),按 index_code 分组每组选1只

  1. 优先选日均成交额最大的(流动性最好)
  2. 同等条件下选管理费最低
  3. 同等条件下选上市时间最早的(历史数据最长)

3.4 Layer 3 — 大类资产标签化

根据指数名称和类别,自动打上资产大类标签(参考 Faber GTAA 的风险因子覆盖思想):

ASSET_CLASS_RULES = {
    'A股宽基':   ['沪深300', '中证500', '中证1000', '创业板', '上证50', '科创50'],
    'A股行业':   ['银行', '证券', '医疗', '白酒', '军工', '新能源', '芯片', '煤炭', ...],
    'A股主题':   ['红利', '消费', '科技', '央企', '国企', ...],
    '港股':      ['恒生', '港股', 'H股'],
    '美股':      ['纳斯达克', '纳指', '标普', '美股'],
    '全球/其他':  ['日经', '德国', '法国', '越南', '印度', 'MSCI'],
    '商品':      ['黄金', '白银', '原油', '有色', '豆粕'],
    '债券':      ['国债', '利率债', '信用债', '可转债'],
}

3.5 Layer 4 — 类内预筛选

每个大类保留最具代表性的 Top-N 只,避免单一类别占满池子:

大类 保留数量 选择依据
A股宽基 3-5 按规模/流动性排序
A股行业 8-12 按行业分散度每个细分行业最多1只
A股主题 3-5 按流动性
港股 2-3 按流动性
美股 2-3 按流动性
全球/其他 2-3 按流动性
商品 2-3 按流动性
债券 2-3 按流动性

3.6 Layer 5 — 相关性优化选择(核心算法)

基于 HRP (Lopez de Prado) 的层次聚类思想用贪心最大分散化算法从30-50只候选中选出最终10-15只

def greedy_max_diversification(candidates, n_select, lookback_days=120):
    """
    1. 计算所有候选的 lookback_days 日收益率相关系数矩阵
    2. 先选入每个大类中流动性最好的1只确保类别覆盖
    3. 剩余名额贪心填充:
       - 对每个未选候选,计算其与已选集合的最大相关系数
       - 选入 max_corr 最小的(即与已有持仓最不相关的)
    4. 重复直到选满 n_select 只
    """

约束条件:

  • 每个大类至少1只确保资产类别覆盖
  • 任意两只的相关系数不超过 0.85(强制分散)
  • A股行业类别不超过总数的 50%避免A股过度集中

4. 定期重建机制

  • 重建周期: 每季度90个交易日重建一次
  • 平滑切换: 新旧池差异超过 30% 时才执行切换,避免频繁调整
  • 反前视偏差 (TrendFolios/AEGIS 强调): 重建时只用截止到重建日的历史数据Universe 随时间自然扩展
  • 退市ETF处理: 回测中需包含已退市ETF的历史数据避免幸存者偏差

5. 实现规划

5.1 独立脚本 scripts/build_etf_universe.py

class ETFUniverseBuilder:
    def __init__(self, config):
        self.min_trading_days = 250     # 上市满1年
        self.min_daily_amount = 5000    # 日均成交额万元
        self.n_select = 12              # 最终池大小
        self.max_corr = 0.85            # 最大相关系数
        self.lookback_days = 120        # 相关性计算窗口

    def run(self):
        raw = self.fetch_etf_universe()        # Layer 0: 获取全量
        filtered = self.basic_filter(raw)       # Layer 1: 基础过滤
        deduped = self.dedup_by_index(filtered) # Layer 2: 同指数去重
        labeled = self.label_asset_class(deduped) # Layer 3: 标签化
        shortlist = self.intra_class_select(labeled) # Layer 4: 类内筛选
        final = self.correlation_optimize(shortlist)  # Layer 5: 相关性优化
        self.save_results(final)
        return final

5.2 输出文件

  • data/etf_universe/universe_{date}.csv: 最终筛选结果
  • data/etf_universe/pipeline_log_{date}.txt: 每层过滤日志
  • data/etf_universe/corr_matrix_{date}.csv: 相关性矩阵

5.3 集成到动量策略

修改 动量.py,支持从动态池加载:

CONFIG = {
    'etf_pool': 'auto',           # 'auto' 表示使用动态池
    'rebuild_interval': 90,       # 每90个交易日重建
}

回测时每隔90天调用一次 ETFUniverseBuilder,用截止到当前回测日期的数据重建池子,确保不使用未来数据。


6. 参考文献

  1. Lu et al. (2024). "TrendFolios: A Portfolio Construction Framework for Utilizing Momentum and Trend-Following In a Multi-Asset Portfolio". arxiv:2506.09330
  2. Chakraborty & Singh (2024). "Taming the Black Swan: A Momentum-Gated Hierarchical Optimisation Framework". arxiv:2604.09060
  3. Lopez de Prado (2016). "Building Diversified Portfolios that Outperform Out-of-Sample" (HRP). SSRN:2708678
  4. Faber (2006). "A Quantitative Approach to Tactical Asset Allocation". SSRN:962461
  5. Antonacci (2012). "Risk Premia Harvesting Through Dual Momentum". SSRN:2042750
  6. Jegadeesh & Titman (1993). "Returns to Buying Winners and Selling Losers". Journal of Finance, 48(1), 65-91