跨资产宏观动量:把股、债、商品、外汇的趋势做成单一择时信号
单资产的时序动量(过去涨就继续做多、过去跌就做空)本身信号很弱,一到震荡就被反复打脸。真正的威力在『把它跨资产做』:股、债、商品、外汇四条腿各自打时序动量、各自做波动率目标化,再等风险聚合成一个『宏观动量』组合——不同资产的趋势彼此错开,某条腿被震荡打脸时另几条腿还在赚趋势的钱。本文用 12 年合成四资产面板演示:单资产择时 Sharpe 只有 1.1~1.3,聚合后组合 Sharpe 2.41、年化 12.5%、最大回撤只有 −9.6%,明显优于波动目标 buy&hold(Sharpe 1.95)与原始等权持有(Sharpe 1.48);并诚实交代趋势信号弱、切换成本、波动率目标的杠杆陷阱、相关性抱团四类实战问题(中阶)。
做趋势策略的人几乎都栽过同一个跟头:在一个标的上跑时序动量,回测漂亮,实盘一上就被震荡市来回打脸。
原因很简单——单个资产的趋势信号本来就弱。它有相当长的时间处在无趋势的震荡里,这时候「过去涨就追、过去跌就砍」的规则,只会在高点买、低点卖,一次次交手续费给市场送钱。
跨资产宏观动量(Cross-Asset Macro Momentum)要解决的,就是这个「单腿太脆」的问题:它不赌某一个市场的趋势,而是同时在股、债、商品、外汇四条腿上做同一套时序动量,再把它们按风险聚合成一个信号。四类资产的趋势往往彼此错开——股票震荡的时候债券在走趋势、商品见顶的时候外汇刚起步——聚合之后,单腿被打脸的噪声被摊薄,留下的是跨资产趋势的共性收益。
这也是 CTA / managed futures 这一整个行业几十年赖以生存的底层逻辑。
一、先说清楚:时序动量到底赌的是什么#
时序动量(Time-Series Momentum, TSMOM)和大家熟悉的「横截面动量」(买最强的、卖最弱的)不一样。它只跟资产自己的历史比:
- 过去 天(本文取 126 天,约 6 个月)累计收益为正 → 信号 ,做多;
- 累计收益为负 → 信号 ,做空;
- 第二天用这个信号持仓,信号滞后一期(避免用当天还没发生的收益)。
它赌的是一个非常朴素的经验规律:价格趋势有惯性。上涨的资产短期内倾向于继续涨,下跌的倾向于继续跌。这个效应在跨资产、跨市场、跨几十年的数据里被反复验证过(Moskowitz-Ooi-Pedersen 2012 的经典论文就是做这个),但它在任何单一资产上都很弱——弱到单腿的信噪比根本撑不起一个策略。
二、关键动作一:波动率目标化,让四条腿可比#
四类资产的波动天差地别:商品可能年化 20%,债券只有 6%。如果直接把它们的择时收益相加,那基本等于「商品说了算,债券的声音听不见」。
所以聚合前必须先做波动率目标化(volatility targeting):每类资产都缩放到同一个目标波动(本文取年化 10%)。
其中 是用近 60 天已实现波动估的、滞后一期的波动率。波动低的资产放大仓位、波动高的缩小仓位,让每条腿对组合的风险贡献大致相等。
import numpy as np
L = 126 # 动量回看窗口(~6 个月)
vol_win = 60 # 波动估计窗口
target_vol_d = 0.10 / np.sqrt(252) # 目标日波动(年化 10%)
# R: shape (T, n) 的四资产日收益矩阵
cum_mom = np.full_like(R, np.nan)
for t in range(L, T):
cum_mom[t] = R[t-L:t].sum(axis=0)
signal = np.sign(cum_mom) # +1 / -1
realized_vol = np.full_like(R, np.nan)
for t in range(vol_win, T):
realized_vol[t] = R[t-vol_win:t].std(axis=0, ddof=1)
pos = np.zeros_like(R)
for t in range(max(L, vol_win)+1, T):
scale = np.where(realized_vol[t-1] > 1e-9,
target_vol_d / realized_vol[t-1], 0.0)
scale = np.clip(scale, 0.0, 3.0) # 杠杆上限, 防波动趋 0 时爆仓
pos[t] = signal[t-1] * scale # 信号滞后一期python注意那句 np.clip(scale, 0.0, 3.0)——这不是可有可无的细节。当某个资产近端波动趋近于 0 时,target_vol / realized_vol 会飙到天上去,直接让仓位爆炸。波动率目标化的这个杠杆陷阱后面第六节会专门讲,它是这类策略最容易被忽略、也最容易翻车的地方。
三、关键动作二:跨资产聚合成单一信号#
四条腿都风险对齐之后,聚合就非常简单了——等权求平均:
r_timed = pos * R # 各资产择时收益
start = max(L, vol_win) + 1
r_macro = r_timed[start:].mean(axis=1) # 跨资产聚合(等权风险对齐)python这一步是整个策略的灵魂。单看每条腿,收益曲线都坑坑洼洼;但四条腿的坑往往不在同一个时点——分散化把彼此的震荡噪声摊平了,只留下跨资产共有的趋势收益。
四、结果:聚合之后信噪比明显跳升#
我用 12 年(3024 个交易日)的合成四资产面板跑了完整回测。特别说明:合成数据里我刻意把趋势幅度压到只有波动的约 18%——也就是说趋势信号很弱、很容易被噪声淹没,这才接近真实市场,否则动量会赢得不真实。

结果很能说明问题:
| 组合 | 年化收益 | Sharpe | 最大回撤 |
|---|---|---|---|
| 跨资产宏观动量 | 12.5% | 2.41 | −9.6% |
| 波动目标等权 buy&hold | 10.1% | 1.95 | −12.6% |
| 原始等权持有 | 10.6% | 1.48 | −20.0% |
年化收益只领先一点点(12.5% vs 10.1%),但 Sharpe 从 1.95 跳到 2.41、最大回撤从 −12.6% 收窄到 −9.6%。这正是宏观动量的价值所在:它主要不是靠拉高收益取胜,而是靠在趋势反转段砍掉深跌、把整条净值曲线做平滑取胜。
把两条回撤曲线画在一起,差异更直观:

buy&hold 在几段趋势反转里被拖出深谷,而宏观动量的回撤曲线整体更浅、更快修复——因为趋势一旦转向,动量信号会翻仓离场,不会陪着一路跌到底。
更关键的一个数字:宏观动量组合和 buy&hold 的相关系数只有 0.21。这意味着它是一个和「一直满仓」低相关的收益来源——在真实组合里,这种低相关的腿比多几个点收益珍贵得多。
五、单腿有多弱?聚合有多神?#
把四类资产各自的「时序动量择时 vs 买入持有」摊开看:

单腿的时序动量 Sharpe 分别是:股票 1.28、债券 1.18、商品 1.28、外汇 1.11——没有一条腿的 Sharpe 超过 1.3。任何单独拿出来,都只是个平庸策略。
但四条腿聚合后 Sharpe 冲到 2.41。这个从 ~1.2 到 2.4 的跳升,几乎全部来自分散化,而不是来自某一条腿特别能打。 这就是「跨资产」三个字的全部意义:不是找到更强的信号,而是把弱信号叠够数量、让它们的噪声互相抵消。
再看综合宏观动量暴露——把四类资产的多空信号直接求和(范围 −4 到 +4):

绿色是净多头(风险偏好上行)、红色是净避险。可以看到组合极少同时把四条腿全押上或全砍掉——大部分时间是 +2、−1 这种不满仓状态,几条腿方向不一致时自然互相对冲。这正是它回撤小的直接原因。
六、四类真实陷阱(实战必看)#
1. 时序动量信号本身很弱,别指望它单挑。 本文合成数据里趋势幅度只有波动的 18%——这是刻意的,真实市场就这么弱。任何声称「单资产时序动量 Sharpe 3」的回测,大概率是数据太干净或有前视。这个策略的收益来自数量堆叠:腿越多、越分散,聚合信噪比越高。四条腿只是起步,真实 CTA 会跑几十个市场。
2. 换仓成本会吃掉一大块。 时序动量在震荡市会频繁翻转信号,每翻一次就是一次双边交易。本文回测没有计入交易成本和冲击成本——加上现实的手续费+滑点,Sharpe 会明显打折,尤其是流动性差的商品和外汇合约。降低换手的常见做法:给信号加缓冲区(接近 0 时不翻仓)、或用连续仓位而非 ±1 硬切。
3. 波动率目标化的杠杆陷阱。 target_vol / realized_vol 这个缩放在低波动期会把仓位放得很大。代码里的 np.clip(scale, 0, 3) 是保命的——没有这个上限,某条腿波动趋 0 时仓位会爆炸,一旦波动突然回归就是灾难性回撤。波动率目标化不是免费午餐:它在波动跳升的拐点会集中放大暴露,恰好是最危险的时刻。
4. 分散化在危机里会失效(相关性抱团)。 这个策略的全部前提是「四类资产趋势彼此错开」。但在系统性危机里(2008、2020 年 3 月),股债商品外汇可能一起崩、相关性瞬间冲到 1,四条腿同时被打脸,分散化荡然无存。本文合成数据的资产间相关性是温和的;真实极端行情下,你要有心理准备:宏观动量最深的回撤,往往就发生在所有资产同步反转的那几周。
七、小结:宏观动量赚的是「分散化的钱」#
跨资产宏观动量的逻辑链条非常清晰:
- 时序动量在任何单一资产上都很弱(本文四条腿 Sharpe 全在 1.1~1.3);
- 但股、债、商品、外汇的趋势彼此错开,把它们波动率目标化后聚合,噪声互相抵消;
- 聚合后 Sharpe 跳到 2.41、最大回撤收窄到 −9.6%、和 buy&hold 相关性只有 0.21;
- 它主要不靠拉高收益,而靠砍掉趋势反转段的深跌、把净值做平滑取胜。
对做实盘的意义:不要在单个市场上死磕时序动量——那是信噪比最差的用法。要把它当成一个「跨资产聚合器」来用,腿越多、越分散,越接近它真正的样子。想进一步的话:把等权聚合换成风险平价加权(见本专栏等风险贡献组合)、给信号加缓冲区降低换手、用多个回看窗口(1/3/6/12 月)做信号平均——这些都是把弱信号榨出稳定 alpha 的标准手艺。先把「单腿弱、聚合强」这件事想透,你就理解了整个 CTA 行业的立身之本。
代码与图表均由自包含 Python(numpy/matplotlib)真实计算,随机种子固定为 20260717,可完整复现。所有统计数字(宏观动量 Sharpe 2.41 / 年化 12.5% / 回撤 −9.6%,buy&hold Sharpe 1.95,单腿 Sharpe 1.1~1.3,组合-buy&hold 相关 0.21)来自文中脚本输出。模拟参数(趋势幅度、波动、分段长度)为演示设定,且刻意把趋势信号压到很弱以贴近真实;实盘需用真实历史收益校准,并计入交易成本。