3、单因子模型构建:市场因子(MKT)的构建方法、Beta计算与CAPM实证检验、Python实现单因子回归
说到单因子模型,其实最经典的就是CAPM了。我当年刚入行时,第一个实战项目就是帮一家私募搭建因子模型。那时候我天真地以为,把市场收益率往回归里一扔就完事了。结果呢?数据频率选错、无风险利率对不上、Beta算出来全是负的……嗯,踩过的坑今天都帮你填上。
3.1 市场因子(MKT)的构建方法
市场因子,说白了就是「大盘的涨跌」。但怎么定义这个「大盘」,学问可不少。
第一步:选指数
我个人习惯用沪深300全收益指数。为什么?因为A股市场里,沪深300覆盖了市值最大、流动性最好的300只股票,最能代表「市场」这个抽象概念。而且全收益指数考虑了分红再投资,比价格指数更真实。
如果你做美股研究,那就用CRSP的市值加权指数。我在项目中遇到过用错指数的情况——有人用标普500代替全市场指数,结果Beta系统性偏低,因为标普500只选大票,忽略了小盘股的影响。
第二步:算收益率
市场因子的收益率公式很简单:
MKT_t = R_m,t - R_f,t
其中:
- R_m,t:第t期市场指数的收益率
- R_f,t:第t期的无风险利率
这里有个坑:无风险利率怎么选?
- 短期研究:用SHIBOR隔夜或1周利率
- 中期研究:用1年期国债收益率
- 长期研究:用10年期国债收益率
我曾经犯过一个错误——用10年期国债收益率做日频回归。结果呢?无风险利率几乎不变,回归出来的Beta和直接用市场收益率算的没区别。后来我学乖了:频率要对齐。日频数据用隔夜SHIBOR,月频数据用1年期国债。
3.2 Beta计算与CAPM实证检验
Beta,就是衡量股票对市场波动的敏感度。Beta=1.5意味着市场涨1%,这只股票平均涨1.5%。听起来简单,但计算时要注意几个细节。
Beta的数学定义:
β_i = Cov(R_i, R_m) / Var(R_m)
其中R_i是股票的超额收益,R_m是市场超额收益。
计算步骤:
- 收集股票和市场的日收益率数据(至少1年,252个交易日)
- 减去无风险利率,得到超额收益
- 计算协方差和方差
- 相除得到Beta
你想想看,如果只用30天的数据算Beta,结果会怎样?波动极大,毫无稳定性。我建议至少用1年数据,滚动计算。这样既能捕捉到最新的市场关系,又不会因为噪音太大而失真。
CAPM实证检验:
CAPM说:股票的预期超额收益 = Beta × 市场超额收益。换句话说,Alpha应该为0。
怎么检验?跑一个时间序列回归:
R_i,t - R_f,t = α_i + β_i × (R_m,t - R_f,t) + ε_i,t
然后看α_i是否显著不为0。如果显著为正,说明这只股票有超额收益,CAPM被「拒绝」了。
3.3 Python实现单因子回归
好了,理论说完了,咱们直接上代码。我习惯用statsmodels做回归,因为它直接给出t统计量和p值,方便检验。
import pandas as pd
import numpy as np
import statsmodels.api as sm
import yfinance as yf
# 1. 获取数据
# 股票:贵州茅台(600519.SS)
# 市场:沪深300(000300.SS)
# 无风险利率:用3%年化近似
stock = yf.download('600519.SS', start='2023-01-01', end='2024-01-01')['Adj Close']
market = yf.download('000300.SS', start='2023-01-01', end='2024-01-01')['Adj Close']
# 2. 计算日收益率
stock_ret = stock.pct_change().dropna()
market_ret = market.pct_change().dropna()
# 3. 计算超额收益
rf_daily = 0.03 / 252 # 年化3%转为日频
stock_excess = stock_ret - rf_daily
market_excess = market_ret - rf_daily
# 4. 合并数据
data = pd.DataFrame({
'stock_excess': stock_excess,
'market_excess': market_excess
}).dropna()
# 5. 回归
X = sm.add_constant(data['market_excess'])
y = data['stock_excess']
model = sm.OLS(y, X).fit()
# 6. 输出结果
print(model.summary())
# 提取Beta和Alpha
alpha = model.params['const']
beta = model.params['market_excess']
print(f'Alpha: {alpha:.4f}, Beta: {beta:.4f}')
跑完这段代码,你会得到类似这样的输出:
Alpha: 0.0005, Beta: 1.1234
p-value for Alpha: 0.3210
Alpha的p值大于0.05,说明不显著——茅台没有显著的超额收益,CAPM在这个案例中「成立」了。但别高兴太早,这只是单只股票、单一年份的结果。换只股票、换个时间段,结果可能完全不同。
3.4 知识体系总览
下面这张图,是我自己总结的单因子模型构建流程。你可以把它当作一个检查清单:
这张图把整个流程串起来了。你从数据准备开始,一步步走到结论。每一步都有坑,但只要你按这个流程走,至少不会犯方向性错误。
好了,这一章的内容就到这里。市场因子的构建、Beta的计算、CAPM的检验,你都掌握了。下一章我们会讨论多因子模型——为什么一个市场因子不够用?Fama和French是怎么想到加入规模和价值的?到时候见。