Skip to content

第 8 讲:进入主线——动量轮动

本讲要点

不猜单票买卖点,而在股票池里按相对强弱定期换仓。


1. 和前 7 讲什么关系

前 7 讲用一只指数 ETF 练完了研究纪律,并亲眼看到:

规则说清 → 回测 → 有基准 → 样本内选参 → 换窗后参数过拟合

结论已经写在第 7 讲:单一标的上叠规则、调参数,风险很大。从这一讲起,进入本书主线:池内动量轮动
对象从「一只 ETF」换成「一篮子可投资标的」;评价从「单票画线」换成「整个组合」。


2. 动量轮动 在干什么

拆成三步就够了:

  1. 定池子(Universe):先约定哪些票/ETF 可以买(例如一篮子行业 ETF,或筛选后的优良股)
  2. 算动量:看过去一段时间谁涨得相对更强(常用过去 N 日收益率)
  3. 轮动持有:每隔固定周期(如每月),只持有排名靠前的若干只,其余清掉或换出

这就是横截面上的「比谁更强」,不是纵向堆 MACD + RSI + KDJ。

单票叠指标池内动量轮动
问的问题这只票该不该买?池子里此刻相对最强的是谁?
持仓往往盯一只持有排名靠前的一组
动作猜拐点定期按排名再平衡

3. 最小可运行例子(用几只 ETF 演示)

下面用几只常见 ETF 演示「月末按近 20 日收益排序,持有最强的 2 只、等权」。
真实课程里可以把 ETF 换成你筛选后的优良股池;流程一样

python
import numpy as np
import pandas as pd
import yfinance as yf

symbols = ["510300.SS", "510500.SS", "159915.SZ", "518880.SS"]  # 沪深300 / 中证500 / 创业板 / 黄金
start, end = "2021-01-01", "2026-03-04"
download_end = (pd.Timestamp(end) + pd.Timedelta(days=1)).strftime("%Y-%m-%d")

raw = yf.download(
    symbols, start=start, end=download_end,
    auto_adjust=True, progress=False,
)["Close"].loc[:end].dropna(how="all")

# 每月最后一个交易日再平衡
month_end = raw.resample("ME").last().dropna()
lookback = 20  # 用日频算动量时,先对齐到调仓日附近的收益
# 简化:用「调仓日相对上个调仓日」的月收益当动量
mom = month_end.pct_change()

top_n = 2
weights = pd.DataFrame(0.0, index=mom.index, columns=mom.columns)

for dt, row in mom.iloc[1:].iterrows():  # 第一期没有动量
    ranked = row.dropna().sort_values(ascending=False)
    picks = ranked.head(top_n).index
    if len(picks) == 0:
        continue
    weights.loc[dt, picks] = 1.0 / len(picks)

# 下期收益 × 本期权重(常见的一期滞后,避免偷看当月)
next_ret = month_end.pct_change().shift(-1)
port_ret = (weights * next_ret).sum(axis=1).dropna()
equity = (1 + port_ret).cumprod()

print("调仓次数:", int((weights.sum(axis=1) > 0).sum()))
print("累计收益:", f"{equity.iloc[-1] - 1:.2%}")
print("最近一期持仓:")
print(weights.iloc[-2][weights.iloc[-2] > 0])  # -1 常因 shift 无收益,看倒数第二期

完整脚本:easy-quant/code/08_momentum_rotation.py(含等权全池、沪深300买入持有对照与图)。


4. 运行结果

固定窗口 2021-01-012026-03-04,池子为沪深300 / 中证500 / 创业板 / 黄金 ETF:

text
窗口: 2021-01-01 → 2026-03-04
股票池: 沪深300, 中证500, 创业板, 黄金
规则: 月末按上月收益排序,等权持有 Top-2
调仓次数(有持仓的月末): 62
持仓成员变化次数: 51
计入收益的期数: 62
轮动累计收益: 63.56%
轮动年化(近似): 9.99%
轮动最大回撤: -24.14%
等权持有全池: 48.20%
沪深300买入持有: -4.72%
相对等权全池: +15.36%
各标的入选次数:
  沪深300 (510300.SS): 29/62 (46.8%)
  中证500 (510500.SS): 34/62 (54.8%)
  创业板 (159915.SZ): 22/62 (35.5%)
  黄金 (518880.SS): 39/62 (62.9%)
最近一期持仓:
  沪深300: 50%
  黄金: 50%
指标数值
调仓次数(月末再平衡)62
持仓成员相对上月发生变化51
轮动累计收益63.56%
轮动年化(近似)9.99%
轮动最大回撤−24.14%
等权持有全池48.20%
沪深300买入持有−4.72%
相对等权全池+15.36%
标的入选次数入选占比
黄金39/6262.9%
中证50034/6254.8%
沪深30029/6246.8%
创业板22/6235.5%

动量轮动 vs 基准

读法:

  • 调仓次数 62:约每个月末都再平衡一次(样本内有持仓的月末数)。
  • 成员变化 51 次:多数月份 Top-2 名单相对上月有调整,轮动并不「躺平」。
  • 本窗口内轮动累计收益高于等权全池,也明显高于单持沪深300;但这是样本内演示,池子、回看窗口与 Top-N 均可调,仍须做基准与样本外检验。
  • 黄金入选最频繁,说明本段路径上贵金属动量多次排进前二——换窗后未必如此。

5. 验收时盯什么

不要只看「最终赚了多少」。至少问:

  1. 相对谁:相对等权持有全池、或一只宽基指数,有没有优势?
  2. 换手高不高:本例成员变化 51/62,轮动较勤,成本与滑点会侵蚀账面收益(后面讲执行时再细算)
  3. 样本外还在不在:换一段时间、换一版池子,排名逻辑是否仍成立?

前 7 讲练过的「怀疑漂亮曲线」,在这里同样适用——只是对象从均线参数,换成了池子、回看窗口、持有数量、调仓频率


6. 本讲小结

  • 主线是 动量轮动:池内比强弱,定期换仓
  • 先定 Universe,再排名,再持有 Top-N
  • 用组合指标验收,并继续做样本外检验

上一讲:过拟合 · 下一讲:股票池 Universe · 目录