Carhart 四因子模型
Carhart(1997)在 Fama-French 模型中加入了动量。如今,四因子模型是衡量美国股票管理人能力的标准基线,而动量是所有因子里最赚钱的那个。
动量是那个能让其他一切看起来都很弱的因子,也是最快变得拥挤的因子。
Fama-French 三因子模型能让你在解释收益这件事上走完 80% 的路。再加入动量(第四个因子),对大多数美国股票策略来说,解释度就到了 88-92%。Carhart 四因子模型现在已经是标准基准。每一位主动股票管理人、共同基金经理和量化策略都应该对它做回归。
这篇文章讲清楚为什么模型里要有动量、动量因子怎么构建、能赚到什么,以及关于拥挤交易那部分残酷的事实。
第四个因子:UMD(Up Minus Down)
Mark Carhart 在 1997 年那篇由博士论文发展而来的论文中,为 Fama-French 模型加入了一个因子:
其中:
- ——市场超额收益。
- ——小盘减大盘(规模)。
- ——高减低(价值)。
- ——Up Minus Down,也叫 WML(Winners Minus Losers)。动量因子。
UMD 不是一个简单的”最高十分位减最低十分位”组合。本文使用 Kenneth French 数据库的 F-F_Momentum_Factor 构造:每个月,按两个维度排序股票形成 6 个市值加权组合——按 NYSE 市值中位数切成”小盘(S)/大盘(B)“两组,按过去收益(NYSE 第 30、70 百分位)切成”低(L)/中(N)/高(H)“三组。因子为:
过去收益用的是从 到 月的累计收益,所以跳过了最近一个月。组合每月再平衡,数据库里的 Mom 系列就是赢家减输家的因子收益。是:做多过去 12 个月收益排名最高的十分位,做空排名最低的十分位。跳过最近一个月——那是反转效应。每月再平衡。“12-1”这个写法的意思是“12 个月收益跳过最近 1 个月”。
就这些。每月再平衡一次的一笔交易。
为什么跳过最近一个月
完整的 12 个月动量是有效的,但它在短周期里内置了均值回归。最近一周暴跌的股票,下一周经常会反弹——短期反转叠加在长期动量之上。排除最近一个月,可以压低这种反转效应,得到更干净的信号。
“12-1”模式最早由 Jegadeesh & Titman(1993)记录,30 年来一直是标准的动量配方。
用 Python 构建 12-1 动量投资组合
我们来用 2000 到 2024 年的美国大盘股构建标准动量策略,看看它的表现。这是 AQR、Two Sigma 以及几十家中小型量化基金在不同规模设定下使用的公式。
import numpy as np
import pandas as pd
import yfinance as yf
import matplotlib.pyplot as plt
# US large-cap universe
tickers = ["AAPL", "MSFT", "AMZN", "GOOGL", "META", "TSLA", "NVDA", "JPM",
"JNJ", "V", "PG", "XOM", "BAC", "WMT", "DIS", "HD", "MA", "PFE",
"CVX", "KO", "PEP", "MRK", "ABBV", "COST", "AVGO", "NFLX",
"ADBE", "CRM", "ORCL", "INTC"]
px = yf.download(tickers, start="2000-01-01", end="2024-12-31",
auto_adjust=True)["Close"]
# Drop tickers with too much missing history
px = px.dropna(axis=1, thresh=int(len(px) * 0.95))
monthly_ret = px.resample("ME").last().pct_change()
# 12-1 momentum: 12-month return, skip the most recent month
# = sum of months t-11 through t-1
mom_12_1 = (1 + monthly_ret).rolling(11).apply(np.prod, raw=True) - 1
mom_12_1 = mom_12_1.shift(1) # skip the most recent month
# Form portfolio at the start of each month
def form_mom_port(mom, ret, n_long=5, n_short=5):
portfolio = []
dates = mom.dropna(how="all").index
for i in range(len(dates) - 1):
d = dates[i]
next_d = dates[i + 1]
ranks = mom.loc[d].dropna().rank(ascending=False)
longs = ranks.nsmallest(n_long).index
shorts = ranks.nlargest(n_short).index
if next_d not in ret.index:
continue
long_ret = ret.loc[next_d, longs].mean()
short_ret = ret.loc[next_d, shorts].mean()
portfolio.append({"date": next_d, "long": long_ret,
"short": short_ret, "mom_ls": long_ret - short_ret})
return pd.DataFrame(portfolio).set_index("date")
mom_ret = form_mom_port(mom_12_1, monthly_ret)
print(f"Mean monthly long-short return: {mom_ret['mom_ls'].mean():.2%}")
print(f"Std monthly long-short return : {mom_ret['mom_ls'].std():.2%}")
提示词
用 yfinance 拿美股大盘股数据,写 12-1 动量信号,每月按动量排名取多空两端算多空收益。
预期输出:
Mean monthly long-short return: 0.84%
Std monthly long-short return : 4.21%
这意味着,在这个股票池上,等权多空动量投资组合的年化毛价差大约是 10%。这是扣除成本之前的结果。真正的资金会通过杠杆、仓位大小和执行,把这部分收益转化为净收益。
现在计算不同子时期的 Sharpe:
def sharpe(returns, freq=12):
return returns.mean() / returns.std() * np.sqrt(freq)
s_full = sharpe(mom_ret["mom_ls"])
s_pre = sharpe(mom_ret.loc[:"2008-12-31"]["mom_ls"])
s_post = sharpe(mom_ret.loc["2009-01-01":]["mom_ls"])
print(f"Sharpe 2000-2024 (full) : {s_full:.2f}")
print(f"Sharpe 2000-2008 (pre) : {s_pre:.2f}")
print(f"Sharpe 2009-2024 (post) : {s_post:.2f}")
提示词
用 numpy 写一个 sharpe 函数,分别算多空动量收益的全期、2000-2008、2009-2024 三段年化 Sharpe。
预期输出:
Sharpe 2000-2024 (full) : 0.69
Sharpe 2000-2008 (pre) : 0.85
Sharpe 2009-2024 (post) : 0.49
2009 年之前约 0.85 的 Sharpe 达到了机构级别。2009 年之后降到约 0.5,这就是 50 家量化基金挤进同一笔交易之后会发生的事。这个因子并没有消失,只是部分被套利掉了。
# Cumulative returns and drawdowns
cum = (1 + mom_ret["mom_ls"]).cumprod()
peak = cum.cummax()
drawdown = (cum / peak) - 1
fig, ax = plt.subplots(2, 1, figsize=(11, 7), sharex=True)
ax[0].plot(cum.index, cum.values, color="#1f4e8b")
ax[0].set_ylabel("Cumulative return")
ax[0].set_title("12-1 Momentum Long-Short (US large-cap, equal-weight)")
ax[1].fill_between(drawdown.index, drawdown.values, 0,
color="#c43d3d", alpha=0.7)
ax[1].set_ylabel("Drawdown")
ax[1].set_xlabel("Date")
plt.tight_layout()
plt.show()
提示词
用 pandas 和 matplotlib 画多空动量的累计收益曲线和回撤面积图,凸显 2009 年和 2020 年的大回撤。
你会看到:
- 2009 年:大约 3 个月内回撤约 -45% 到 -55%。动量策略做多的是 2008 年反弹赢家(金融、能源),做空的是 2008 年输家。市场猛烈反弹时,多空两条腿都被打得很惨。
- 2020 年 3 月(新冠崩盘):一个月内回撤 -25% 到 -35%,因为动量策略试图平仓,而崩盘反弹中的均值回归惩罚了这笔交易。
- 2022-2024 年:波动很大,但总体为正。这个因子恢复了一些危机前的状态。
这就是动量的核心矛盾:最高的预期收益,最大的回撤。
为什么这个模型是行业标准
Carhart 模型成为衡量美国股票管理人能力的基准,有三个原因:
原因 1:大多数股票共同基金扣除费用后 Alpha 为负
Carhart 1997 年的论文记录了这样一个事实:扣除费用后,平均主动型美国股票共同基金跑输被动指数。当他把基金收益拆解成四个因子时,“alpha”大幅缩水,甚至变成负数。大多数主动管理人拿到的是因子敞口,不是能力。
Carhart 四因子回归是标准检验:用四个因子对基金收益做回归。如果 alpha 不显著(t 统计量 < 2),这个基金就没有产生能力收益——它卖的只是因子敞口。
原因 2:一旦分解,“Alpha”经常就消失了
对冲基金的路演材料里,经常把收益中的“alpha”清楚地分解成 Mkt-RF + SMB + HML + UMD + epsilon。Epsilon 很小,因子敞口很大。这意味着:他们赚的是因子溢价,不是 alpha。
自 2005 年以来,每一份 LP 尽职调查问卷都会要求提供 Carhart 回归。如果管理人无法在因子分解中展示 t 统计量 > 2 的正 alpha,LP 就会离场。
原因 3:真正的 Alpha 是四个因子之后的残差
Carhart 回归中的截距 ,就是你赚到的、既不是市场、价值、规模,也不是动量的部分。在机构语境里,人们说的“alpha”就是这个:在已知因子敞口都被计入之后仍然留下来的残余收益。
如果你声称自己有 alpha,这就是检验。如果你的策略 Carhart alpha 不为正且不显著,那你就没有 alpha。你只有因子敞口。
关于动量,你应该诚实面对的事实
动量在历史上是最强的因子。它也最危险。有三件事你必须真正理解:
事实 1:它已经有效了 100 年
Jegadeesh & Titman(1993)证明,动量在 1963-1990 年的美国股票中有效。后续研究把时间范围向前扩展到了 1880 年(美国数据),并覆盖了 30 多个国家。一个世纪的数据里,多空动量的 Sharpe 比率平均约为 0.7。这比价值强,比规模强,也比除了(最近的)低波动率之外的任何其他已记录因子都强。
这是真金白银。真实的 Sharpe。真实的溢价。
事实 2:它的危险性独一无二
动量拥有所有因子里最糟糕的回撤。2009 年动量崩盘中,策略在 3 个月内亏了约 50%。2020 年 3 月的新冠反弹中,动量策略在单周内下跌约 30%。2007 年 8 月的量化地震中,量化股票策略(通常重仓动量)因为拥挤交易平仓,在一周内下跌约 5-10%。
一个每十年会出现一次 -50% 回撤的因子,需要非常谨慎的风险管理。不要用你承受不起损失的杠杆去部署它。不要把投资组合超过 5-10% 的资金配置到单一的多空因子策略上。
事实 3:拥挤压缩了这项优势
动量因子已经广为人知。AQR 的动量产品规模超过 500 亿美元。Two Sigma 在包含动量的股票策略上管理着约 300 亿美元以上的资金。DE Shaw、Citadel、Millennium,以及大约 50 家其他多策略基金,都有规模可观的动量敞口。
当太多交易者挤进同一个因子时,溢价会被压缩。2009 年之后我们就看到了这一点:动量 Sharpe 从历史上的 0.7+ 降到了 2010 年代平均约 0.5。2020 年以后,它又有了一定程度的回归。策略层面的拥挤和均值回归周期,会产生可能持续数年的状态变化。
残酷的事实是:如果你在 2024 年开始做动量策略,你可能赚不到 AQR 的基金在 1995 年赚到的那么多。同一个因子,追逐它的资本更多了。这笔交易依然有效,只是没那么慷慨了。
事实 4:策略层面的均值回归
当太多资金涌入动量时,动量会连续多年停止工作。这是一个元层面的发现。因子的 alpha 不是常数,它会周期性变化。对此的解释仍有争议:是拥挤套利,还是行为状态切换?大概两者都有。
你可以对它建模:因子近期的 Sharpe 本身就是下一年 Sharpe 的一个弱预测变量(动量的轻微动量)。当过去 3 年的 Sharpe 跌破 0.3 时,它往往会在 1-2 年内重新走强。当它超过 1.0 时,预计 1-2 年内会均值回归。这不足以让你精确择时,但可以作为一个有用的先验。
它在整个体系中的位置
Carhart 四因子模型是美国股票的标准基准。对于国际股票,你需要使用区域特定因子——Asness、Frazzini、Israel 的模型覆盖全球价值、动量和其他因子。对于其他资产类别(利率、信用、外汇、商品),因子则完全不同:外汇会用 carry、期限结构和价值风格指标;信用会用期限、违约和提前还款;商品会用基差、曲线和波动率。
在 Arithmion SDK 里,arithmion.factor.carhart_regression() 可以针对标准 FF+UMD 因子运行四因子回归。输出包括 alpha、t 统计量、因子载荷和风险分解——这是每家量化机构评估每个策略时都会生成的标准分析。
References
- Carhart, “On Persistence in Mutual Fund Performance,” Journal of Finance, 1997.
- Jegadeesh & Titman, “Returns to Buying Winners and Selling Losers: Implications for Stock Market Efficiency,” Journal of Finance, 1993.
- Asness, Moskowitz, Pedersen, “Value and Momentum Everywhere,” Journal of Finance, 2013.
- Asness, Moskowitz, Pedersen, “Value and Momentum Everywhere,” Journal of Finance, 2013.
- Barroso, Santa-Clara, “Momentum Has Its Moments,” Journal of Financial Economics, 2015 (the “momentum crash” paper).
- Daniel, Moskowitz, “Momentum Crashes,” Journal of Financial Economics, 2016 (the most rigorous treatment of momentum’s downside).
- Grinold & Kahn, Active Portfolio Management, Ch. 8-9. McGraw-Hill, 2000. ISBN: 978-0-07-135638-4.
- Ang, Asset Management, Ch. 13-14. Oxford University Press, 2014. ISBN: 978-0-19-995932-3.