# 实验 007:动量因子回看窗口优化研究 **实验日期**:2026-06-12 **实验目标**:研究动量因子回看窗口(n_days)的选择方法,评估多周期融合对策略表现的影响 **实验结论**:多周期融合不适用于本策略,维持 25 天单窗口 --- ## 一、问题背景 ### 1.1 当前配置 策略使用 `slope_r2` 因子,全局统一 25 天回看窗口: ```yaml factor: n_days: 25 type: slope_r2 ``` ### 1.2 发现的问题 从回测数据的因子分布分析发现: | 标的 | IQR(波动代理) | 中位数 | 正得分% | 特征 | |------|----------------|--------|---------|------| | 创业板指 | 28.23 | 0.00 | 51.0% | 高波动,趋势间歇性强 | | 恒生科技 | 20.71 | -0.01 | 44.0% | 高波动,趋势弱 | | 纳指100 | 20.10 | 4.31 | 67.4% | 高波动,趋势强 | | 短债 | 0.38 | 0.68 | 97.9% | 低波动,几乎无趋势 | | 黄金 | 13.39 | 0.77 | 60.7% | 中等波动,趋势持续 | **核心问题**:不同资产的趋势周期差异很大,统一 25 天窗口是否合理? --- ## 二、学界与业界调研 ### 2.1 经典文献的标准做法 #### 横截面动量(Cross-Sectional Momentum) **Jegadeesh & Titman (1993)** 开创性研究: - **标准窗口**:12-1 月(过去12个月收益,跳过最近1个月) - **金融语义**:跳过最近1个月是因为存在短期反转效应(1周-1个月),而中期(3-12个月)存在动量效应 - **原理**:信息扩散慢 → 价格对新信息反应不足 → 形成中期趋势 **Asness, Moskowitz & Pedersen (2013)** "Value and Momentum Everywhere": - 股票:12-1 月 - 债券:12-1 月或 6-1 月 - 商品:12 月(不跳过,因为商品市场短期反转弱) - 货币:12 月 - **核心观点**:不同资产类别的最优窗口不同,但 12 月是一个稳健的起点 #### 时间序列动量(Time-Series Momentum / TSMOM) **Moskowitz, Ooi & Pedersen (2012)**: - **标准窗口**:12 月(用于期货) - **金融语义**:TSMOM 关注资产自身的绝对收益,不与其他资产比较 - **关键发现**:1-12 月窗口都有效,但 12 月最稳健 - **波动率调整**:用实现波动率标准化头寸规模,使得不同资产可比 ### 2.2 窗口选择的金融语义 #### 不同窗口对应的市场微观结构 | 窗口长度 | 捕捉的效应 | 金融解释 | 风险 | |---------|-----------|---------|------| | 1周-1月 | 短期反转 | 流动性冲击、过度反应修正 | 高换手、交易成本 | | 1-3月 | 早期动量 | 信息扩散初期、盈余公告后漂移 | 容易被打断 | | 3-12月 | 经典动量 | 信息扩散慢、机构调仓周期 | 最稳健 | | 12-24月 | 长期动量 | 经济周期、企业基本面变化 | 均值回归开始显现 | | >24月 | 长期反转 | 估值回归、经济周期反转 | 动量效应消失 | #### 不同资产类别的特征周期 | 资产类别 | 特征周期 | 推荐窗口 | 理由 | |---------|---------|---------|------| | **股票指数** | 季度财报+机构调仓 | 6-12月 | 信息扩散慢,机构季度调仓 | | **债券** | 央行政策周期 | 3-6月 | 利率变化快,久期短 | | **商品** | 供需周期+季节性 | 6-12月 | 供需调整慢,但有季节性 | | **货币** | 利差+央行政策 | 3-6月 | 政策变化快 | ### 2.3 避免过拟合的原则 #### 先验选择 vs 数据挖掘 **过拟合的做法**: ```python # 在历史数据上测试 5, 10, 15, 20, 25, 30... 天,选最好的 for window in [5, 10, 15, 20, 25, 30, 60, 120]: backtest(window) best_window = argmax(results) # 过拟合! ``` **有金融语义的做法**: ```python # 基于资产类别选择窗口 window_map = { 'equity_index': 252, # 12月(252交易日) 'bond': 126, # 6月 'commodity': 252, # 12月 'currency': 126, # 6月 } ``` #### 稳健性检验原则 **学界推荐的做法**: 1. **选择有理论支撑的窗口**:12月、6月、3月是标准选择 2. **测试邻域稳健性**:如果 12 月好,11 月和 13 月也应该不差 3. **多窗口平均**:用 3-12 月的多个窗口取平均,降低单窗口风险 4. **样本外验证**:在不同时间段、不同市场验证 **AQR 的实践建议**: - 不要优化到极端值(如 17 天、23 天) - 选择"足够好"的标准窗口(如 252 天而非 247 天) - 关注经济解释而非统计显著性 ### 2.4 多窗口融合方法 #### 1. 等权平均(Simple Ensemble) ```python windows = [63, 126, 252] # 3月、6月、12月 momentum = mean([return(p, w) for w in windows]) ``` **优点**: - 降低单窗口风险 - 捕捉不同周期的趋势 - 无需优化参数 **缺点**: - 等权可能不合理 - 可能引入噪音窗口 #### 2. 波动率加权(Volatility-Weighted) ```python # 波动率低的窗口权重更高(更稳定) weights = 1 / vol(window_i) momentum = weighted_mean(momentum_i, weights) ``` **金融语义**:低波动窗口的信号更可靠 #### 3. 自适应窗口(Adaptive Window) **基于波动率的自适应**: ```python # 高波动时缩短窗口(快速反应),低波动时延长(过滤噪音) if realized_vol > threshold: window = 63 # 3月 else: window = 252 # 12月 ``` **基于机制转换(Regime Switching)**: ```python # 用 HMM 识别市场状态 regime = detect_regime(market_data) if regime == 'trending': window = 252 # 趋势市用长窗口 elif regime == 'mean_reverting': window = 21 # 震荡市用短窗口或反转 ``` ### 2.5 多周期融合为什么有效? #### 1. 信息扩散有多个时间尺度 - **短期(1-4周)**:流动性冲击、技术性买卖、短期情绪(噪音) - **中期(1-6月)**:盈余公告、行业数据、政策变化(信息扩散) - **长期(6-12月)**:经济周期转换、产业趋势、估值重定价 单一窗口只能捕捉一个尺度的信息。多窗口融合等于同时监听多个信息频段。 #### 2. 市场参与者的决策周期不同 | 参与者 | 决策周期 | 影响的价格趋势 | |--------|---------|--------------| | 高频/量化 | 天-周 | 短期噪音 | | 共同基金 | 月-季 | 中期动量 | | 养老金/保险 | 季-年 | 长期趋势 | | 主权基金 | 年+ | 结构性变化 | 当多个周期的信号一致时,意味着不同时间维度的市场参与者方向一致——这是最强的趋势确认。 #### 3. 统计角度:偏差-方差权衡 - **短窗口**:低偏差(快速捕捉趋势变化),高方差(容易被噪音干扰) - **长窗口**:高偏差(趋势转折时反应慢),低方差(噪音被平滑掉) 多窗口融合相当于对偏差-方差做了平均,短窗口提供灵敏度,长窗口提供稳定性。 #### 4. 信号处理的类比 把价格序列想象成一个信号,不同窗口就是不同频率的带通滤波器: ``` 价格信号 = 高频噪音 + 中期趋势 + 长期趋势 + 周期性波动 25天窗口 → 带通滤波器:主要透过高频成分 126天窗口 → 带通滤波器:主要透过中期成分 252天窗口 → 低通滤波器:只保留长期趋势 ``` 多个滤波器融合 = 宽频带接收,信息更完整。 ### 2.6 多周期融合对 slope_r2 偏好的影响 slope_r2 真正偏好的是**趋势性波动高的资产**(高波动+有方向),而不是单纯的高波动。 多周期融合的预期影响: | 资产类型 | 单窗口(25天) | 多周期融合 | 变化方向 | |---------|-------------|-----------|---------| | 高波动+持续趋势(纳指) | 高分 | 高分 | 不变 | | 高波动+间歇趋势(创业板) | 不稳定高分 | 中等分 | **下降** | | 低波动+持续趋势(黄金) | 中等分 | 中等偏高分 | **上升** | | 低波动+无趋势(短债) | 低分 | 低分 | 不变 | | 高波动+无趋势(恒生科技) | 低分 | 低分 | 不变 | **核心预期**:融合会让 slope_r2 的偏好从"高波动+趋势性"转向"持续性趋势"——不管波动高低,只要趋势持续就得分高。 --- ## 三、实验设计 ### 3.1 实验一:IDM 信息离散动量融合 #### 方法 **IDM(Information Dispersal Momentum)**:正收益天数占比,衡量上涨的持续性 ```python def info_dispersal_momentum(prices: np.ndarray) -> float: returns = np.diff(prices) positive_days = np.sum(returns > 0) return positive_days / len(returns) ``` **方式一:乘法融合** ```python def slope_r2_idm_score(prices: np.ndarray) -> float: sr2 = slope_r2_score(prices) idm = info_dispersal_momentum(prices) return sr2 * idm # IDM 作为折扣系数 ``` **方式三:阈值过滤** ```python def slope_r2_idm_filter_score(prices: np.ndarray, threshold: float = 0.5) -> float: idm = info_dispersal_momentum(prices) if idm < threshold: return 0.0 # 上涨天数不足阈值则清零 return slope_r2_score(prices) ``` #### 实验配置 - **方式一**:`type: slope_r2_idm` - **方式三**:`type: slope_r2_idm_filter`,测试阈值 0.4/0.5/0.6 ### 3.2 实验二:多周期融合 #### 方法 ```python def slope_r2_ensemble_score(prices: np.ndarray, windows: list = None) -> float: if windows is None: windows = [63, 126, 252] # 3月、6月、12月 scores = [] for w in windows: if len(prices) >= w: window_prices = prices[-w:] score = slope_r2_score(window_prices) scores.append(score) return sum(scores) / len(scores) if scores else 0.0 ``` #### 实验配置 - **配置**:`type: slope_r2_ensemble` - **窗口**:63/126/252 天(3月/6月/12月) - **数据预加载**:504 天(2倍最大窗口) --- ## 四、实验结果 ### 4.1 实验一:IDM 融合结果 #### 方式一:乘法融合 | 指标 | slope_r2 (baseline) | slope_r2_idm | 变化 | |------|---------------------|--------------|------| | 总收益 | 288.30% | 296.55% | +8.25% | | 年化收益 | 24.61% | 25.03% | +0.42% | | 最大回撤 | -16.27% | -16.19% | 略改善 | | Sharpe | 1.17 | 1.20 | +0.03 | | Calmar | 1.51 | 1.55 | +0.04 | | 胜率 | 53.74% | 54.48% | +0.74% | | 调仓次数 | 363 | 374 | +11 | **结论**:方式一(乘法融合)全面小幅优于 baseline。 #### 方式三:阈值过滤 | 阈值 | 总收益 | 年化 | 最大回撤 | Sharpe | Calmar | 胜率 | |------|--------|------|----------|--------|--------|------| | 0.4 | 297.88% | 25.10% | -16.27% | 1.19 | 1.54 | 53.87% | | 0.5 | 205.38% | 19.85% | -17.90% | 1.00 | 1.11 | 53.35% | | 0.6 | 69.75% | 8.96% | -24.77% | 0.58 | 0.36 | 56.87% | **结论**:方式三(过滤器)阈值敏感,0.5 和 0.6 明显变差,容易过拟合。 ### 4.2 实验二:多周期融合结果 #### 绩效对比 | 指标 | slope_r2 (25天) | slope_r2_ensemble (63/126/252) | 变化 | |------|----------------|-------------------------------|------| | 总收益 | 288.30% | 182.82% | **-105.48%** | | 年化收益 | 24.61% | 18.36% | **-6.25%** | | 最大回撤 | -16.27% | -21.61% | **恶化 5.34%** | | Sharpe | 1.17 | 0.96 | **-0.21** | | Calmar | 1.51 | 0.85 | **-0.66** | | 胜率 | 53.74% | 55.47% | +1.73% | | 调仓次数 | 363 | 167 | **-196** | #### 持仓频率变化 | 标的 | baseline 占比 | ensemble 占比 | 变化 | 资产类型 | |------|--------------|--------------|------|---------| | 纳指100 | 44.7% | 53.3% | **+8.6%** | 高波动+持续趋势 | | 黄金 | 21.0% | 35.8% | **+14.8%** | 低波动+持续趋势 | | 创业板指 | 29.9% | 40.2% | **+10.3%** | 高波动+间歇趋势 | | 日经225 | 31.0% | 37.7% | +6.7% | 中波动+持续趋势 | | 德国DAX | 27.8% | 33.1% | +5.3% | 中波动+持续趋势 | | **短债指数** | **32.0%** | **16.6%** | **-15.4%** | 防御填充 | | 红利低波 | 24.3% | 11.9% | **-12.4%** | 低波动+持续趋势 | | 有色金属 | 18.1% | 12.8% | -5.3% | 高波动+周期趋势 | #### 与预期对比 | 预期 | 实际 | 符合? | |------|------|--------| | 纳指100 和黄金占比上升 | 纳指+8.6%,黄金+14.8% | ✓ 符合 | | 红利低波占比上升 | 红利低波-12.4% | ✗ 不符合 | | 创业板指占比下降 | 创业板指+10.3% | ✗ 不符合 | | 整体表现改善 | 收益降6%,回撤增5% | ✗ 不符合 | --- ## 五、结论与分析 ### 5.1 IDM 融合结论 **推荐方案**:方式一(乘法融合) **理由**: 1. 全面小幅优于 baseline,无需调参 2. IDM 作为折扣系数,逻辑简洁 3. 过滤方式(方式三)阈值敏感,容易过拟合 **保留代码**: - `slope_r2_idm_score` 函数已实现 - `FactorType.SLOPE_R2_IDM` 枚举已添加 - 可通过配置 `type: slope_r2_idm` 启用 ### 5.2 多周期融合结论 **结论**:不适用于本策略 **原因分析**: 1. **长窗口反应太慢**:252 天窗口在趋势转折时严重滞后。2022 年全球熊市、2024 年风格切换时,ensemble 无法及时退出 2. **调仓次数骤降**:从 363 次降到 167 次,说明信号太稳定了,错过了很多轮动机会。这个策略的核心价值就是**轮动**,过于稳定的信号反而不利 3. **短债填充减少**:从 32% 降到 16.6%,说明 ensemble 在弱势市场中也倾向于持有风险资产(因为长窗口记忆了之前的上涨趋势),导致回撤增大 4. **创业板指上升的原因**:2024-2025 年创业板有持续上涨趋势,ensemble 的长窗口恰好捕捉到了这个趋势,但这不是"持续性偏好",而是"恰好匹配" **核心问题**: 这个策略的 alpha 来源是**中短期轮动**(25 天窗口),不是长期趋势跟踪。ensemble 把因子变成了半趋势跟踪因子,与策略的核心逻辑冲突。 ### 5.3 最终决策 **维持现有配置**: ```yaml factor: n_days: 25 type: slope_r2 ``` **理由**: 1. 25 天窗口与策略的轮动逻辑匹配 2. 多周期融合与策略核心逻辑冲突 3. IDM 融合虽然有效,但提升有限,暂不启用 --- ## 六、参考资料 ### 学术文献 1. **Jegadeesh, N., & Titman, S. (1993)**. Returns to Buying Winners and Selling Losers: Implications for Stock Market Efficiency. *Journal of Finance*, 48(1), 65-91. 2. **Asness, C. S., Moskowitz, T. J., & Pedersen, L. H. (2013)**. Value and Momentum Everywhere. *Journal of Finance*, 68(3), 929-985. 3. **Moskowitz, T. J., Ooi, Y. H., & Pedersen, L. H. (2012)**. Time Series Momentum. *Journal of Financial Economics*, 104(2), 228-250. ### 业界实践 - [Momentum Factor Investing: 30 years of Out of Sample Data](https://alphaarchitect.com/momentum-factor-investing-30-years-of-out-of-sample-data/) - [Systematic Trend-Following with Adaptive Portfolio Construction](https://arxiv.org/html/2602.11708v1) - [Value and Momentum Everywhere - AQR Capital Management](https://www.aqr.com/Insights/Research/Journal-Article/Value-and-Momentum-Everywhere) --- ## 七、附录:代码实现 ### 7.1 IDM 融合因子 ```python def info_dispersal_momentum(prices: np.ndarray) -> float: """Information Dispersal Momentum (IDM): 正收益天数占比""" if len(prices) < 2: return 0.0 returns = np.diff(prices) positive_days = np.sum(returns > 0) return positive_days / len(returns) def slope_r2_idm_score(prices: np.ndarray) -> float: """Slope * R² * IDM: 趋势强度 × 拟合质量 × 上涨持续性""" sr2 = slope_r2_score(prices) idm = info_dispersal_momentum(prices) return sr2 * idm ``` ### 7.2 多周期融合因子 ```python def slope_r2_ensemble_score(prices: np.ndarray, windows: list = None) -> float: """多窗口 slope_r2 等权融合""" if windows is None: windows = [63, 126, 252] # 3月、6月、12月 scores = [] for w in windows: if len(prices) >= w: window_prices = prices[-w:] score = slope_r2_score(window_prices) scores.append(score) return sum(scores) / len(scores) if scores else 0.0 ``` --- **文档版本**:v1.0 **最后更新**:2026-06-12 **实验状态**:已完成