halo 的技术博客

返回

如果你只做过「12 个月动量」, 大概率有过这种困惑:

教科书说「过去涨得多的股票, 未来继续涨」。可你一做回测, 刚追进去就挨打——尤其持有期只有一两个月的时候, 往往反而是「上个月赢家下个月回吐」。同一套「买赢家卖输家」的逻辑, 怎么一会儿灵、一会儿不灵?

答案不在策略本身, 而在持有期 h。动量(momentum)和反转(reversal)不是两个互斥的策略, 而是同一个排序信号在不同期限上的两张脸:

  • 持有 1 个月, 过去赢家倾向于回吐 —— 反转占优;
  • 持有 12 个月, 过去赢家倾向于延续 —— 动量占优。

中间存在一个拐点持有期 h*: 越过它, 排序信号的赢面就从负翻成正, 并且随 h 继续增强。本文用一套合成面板, 把这个拐点算出来, 并讲清它为什么存在。

一、为什么会有拐点: 两个隐藏成分#

任何一只股票的月度收益, 都能拆成两个隐藏的、跨月演化的成分:

  1. 短期「过度反应」成分 O: 行为金融里的反应过度/流动性冲击。它只造成一期反转——本月的过度上涨, 在下一个月被部分回吐。用月度冲击 OmiidO_m\sim iid 表示, 反转成分写为 Rm=θOm1+OmR_m = -\theta\,O_{m-1} + O_m。它的自协方差很干净:只在 lag-1 为负(γR(1)=θσO2<0\gamma_R(1)=-\theta\sigma_O^2<0), lag≥2 直接归零——没有振荡尾巴。它带来反转
  2. 长期「信息动量」成分 M: 基本面信息的缓慢扩散, 是持久的 AR(1), ϕM>0\phi_M>0。自协方差 γM(h)=σM2ϕMh\gamma_M(h)=\sigma_M^2\phi_M^{|h|} 恒为、且衰减慢。它带来动量

横截面上, 我们按「过去 h 个月累计收益」排序、买赢家卖输家, 这个策略的赢面, 根本上由月度收益的自协方差 γ(h)\gamma(h) 决定:

γ(1)=θσO2+σM2ϕM(lag-1: 反转负项 vs 动量正项 直接对撞)\gamma(1) = -\theta\sigma_O^2 + \sigma_M^2\phi_M \quad\text{(lag-1: 反转负项 vs 动量正项 直接对撞)} γ(h2)=σM2ϕMh(lag≥2: 反转项已归零, 只剩恒正的动量项)\gamma(h\ge 2) = \sigma_M^2\phi_M^{h} \quad\text{(lag≥2: 反转项已归零, 只剩恒正的动量项)}

于是出现一个必然结果:

h=1 时, 反转负项与动量正项直接对撞, 若反转压过, 则 γ(1)<0\gamma(1)<0反转赢面; h≥2 时, 反转项已消失, 只剩恒正、衰减慢的动量项 → γ(h)>0\gamma(h)>0动量赢面, 且随 h 累积增强。

lag-1 是这场对撞的唯一战场, lag≥2 动量接管——这就是拐点存在的数学根源。下面用数据把它坐实。

二、合成面板与持有期扫描#

我们造一个干净的合成面板: 300 只股票、2982 个交易日(142 个月), 每只股票的月度收益 = 一个一期反转成分(θ=0.65\theta=0.65, 月度冲击波动 5%) + 一个持久动量成分(ϕM=0.62\phi_M=0.62, 月度波动 3.5%) + 日度特异噪声。然后做最朴素的扫描: 对每个持有期 h{1,2,,12}h\in\{1,2,\dots,12\} 月, 在每个 formation 月, 按过去 h 月累计收益排序, 买前 10% 赢家、卖后 10% 输家, 持有 1 个月, 记录组合收益与横截面 rank-IC。

核心的「自协方差结构」长这样——

自协方差结构: lag-1 为负(反转), lag≥2 转正(动量) —— 拐点 band≈3-6

红色一根是反转项, 只在 lag-1 为负; 绿色曲线是动量项, 恒正、缓慢衰减; 蓝色虚线是二者合成——lag-1 压在 0 轴下方(反转结构), lag≥2 全部翻到上方(纯动量)。拐点不是一个凭空出现的魔法点, 而是「lag-1 反转对撞」与「lag≥2 动量接管」的结构性切换, 落在 h*≈3 附近。

三、rank-IC 与 L-S 收益的双重印证#

自协方差是「聚合层面」的证据。在横截面层面, 两个指标同样给出干净的翻转:

  1. rank-IC(h): 过去 h 月收益与下月收益的排序相关系数。h=1 时为负(-0.109), 即「上月赢家下月输」的反转信号; h=12 时为正(0.012), 即动量信号。中间平滑翻号。
  2. L-S 月均收益: 买赢家卖输家的实打实月均收益。h=1 时为 -3.23%/月(亏), h=12 时为 0.33%/月(赚), 且随 h 从 2 增大到 12 持续增强——这正是动量项累积、反转项只活在 lag-1 的题中之义。

横截面 rank-IC(h): 1 月为负(反转)→ 12 月为正(动量)

持有期扫描: L-S 月均收益在 h=3 翻正并随 h 增强

两个视角在同一个 h*≈3 附近翻号, 之后随 h 同步增强——聚合自协方差、横截面 IC、实盘式 L-S 收益, 三者互相印证, 不是某一种统计的孤证。

# 持有期扫描(核心片段)
def scan_horizon(h):
    ls_rets, ics = [], []
    for m in range(h, M - 1):
        past = cum[:, m-h+1:m+1].sum(axis=1)   # 过去 h 月累计
        f    = cum[:, m+1]                      # 真实下月收益(无前视)
        ics.append(spearmanr(past, f).correlation)
        rk   = rankdata(past)
        top, bot = rk >= K*0.9, rk <= K*0.1
        ls_rets.append(f[top].mean() - f[bot].mean())   # 买赢家卖输家
    return np.mean(ls_rets), np.mean(ics)
python

四、三类持有期的净值对比#

把三个代表持有期各自跑一条累计净值: h=1(纯反转)、h=6(过渡带)、h=12(纯动量)。结果符合「层级」——

三类持有期累计净值: 反转亏钱、动量赚钱、过渡带最弱

  • h=1 反转: 年化约 -32.8%, 亏钱——反转是「捡过度反应的便宜」, 但 lag-1 的对手盘正是动量项的正贡献, 两者在 h=1 对撞, 净效应为负;
  • h=6 过渡带: 年化约 5.5%, 已经转正但幅度有限——反转项在 lag-1 之外已归零, 动量项刚开始累积, 是「刚翻正、还没长肥」的过渡段;
  • h=12 动量: 年化约 3.8%, 明显最强——动量项连续累积 12 个月, 信号最纯、空间最大。

这恰好点出实战的关键:拐点不是「最佳持有期」, 而是「最该分清边界」的地方。翻正之后(h≥3), 越往长拿, 动量贡献越纯粹——但很多人卡在 h=2~5 的过渡带, 收益鸡肋、噪声最大, 最容易误判「动量不灵」。

五、六类真实陷阱(实战必看)#

  1. 拐点是 band 不是点: 本文 h*≈3 是 L-S 月均收益翻正处; 但动量真正「长肥」要到 h≈6-12。把 h=2 当成「动量已成立」会踩进过渡带鸡肋区。
  2. 反转项只在 lag-1: 模型里反转是「一期回吐」。真实市场短期反转多在 1 月窗口, 2-3 月就弱; 若你的数据反转拖到 lag-3 仍有显著自协, 说明模型设定需加多期项。
  3. 样本长度吃掉长 lag: 动量项自协方差在长 lag 处方差爆炸, h=12 的估计比 h=2 抖得多。翻号结论要配合显著性检验, 不能只看一个点。
  4. 交易成本改变结论: 反转(h=1)换手极高, 真实手续费/冲击成本会吞掉大部分甚至全部收益; 动量(h=12)换手低, 净优势更大。比较必须扣成本。
  5. 横截面 vs 时序: 本文是横截面(每月换仓、多空对冲)。时序动量(直接持有一个资产的趋势)逻辑类似但数值不同, 别混用。
  6. 幸存者偏差: 合成面板无退市。真实回测若用存活股票, 反转/动量都被高估, 尤其小市值端。

六、小结: 拐点才是真结论#

动量还是反转? 这是一个错问题。正确的问题是——在你的持有期上, 哪个成分占优?

本文用合成面板把这件事量化: 月度收益自协方差 γ(1)=θσO2+σM2ϕM\gamma(1)=-\theta\sigma_O^2+\sigma_M^2\phi_M 在 lag-1 是反转与动量的对撞场, 而 γ(h2)=σM2ϕMh\gamma(h\ge 2)=\sigma_M^2\phi_M^h 是恒正、衰减慢的纯动量项。rank-IC 从 -0.109 翻到 0.012、L-S 月均收益由 -3.23%/月 翻到 0.33%/月, 拐点落在 h*≈3, 之后随 h 持续增强。它告诉我们两件事:

  • 反转和动量是一体两面, 由持有期这一个旋钮切换, 切换点就是 lag-1 对撞 vs lag≥2 动量接管;
  • 翻正之后别停在过渡带——h≈2-5 收益鸡肋、噪声最大, 真正干净的动量要 h≈6-12。

对因子研究和 CTA 择时而言, 先扫描持有期、找到自己的 h*, 比盲目追一个「动量因子」要扎实得多。


代码与图表均由自包含 Python(numpy/scipy/matplotlib)真实计算, 随机种子固定为 20260718, 可完整复现。所有统计数字(自协方差 lag-1 为负=-0.00、lag≥2 转正、rank-IC h=1 为 -0.109 / h=12 为 0.012、L-S 月均收益 h=1 为 -3.23%/月 / h=12 为 0.33%/月、拐点 h*≈3、三类持有期年化 -32.8%/5.5%/3.8%)均来自文中脚本输出。面板为合成过程(300 股 × 2982 日; 反转: θ=0.65, σ_O=5%; 动量: φ_M=0.62, σ_M=3.5%), 实战须用真实价格并滚动重估 h*、扣除交易成本。

动量反转的持有期边界:用持有期扫描找出动量转反转的拐点
https://blog.halo26812.eu.org/blog/momentum-reversal-horizon
Author halo
Published at 2026年7月18日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨