滚动单因子回归通常指在时间序列上用一个固定长度的窗口不断向后滑动,
每个窗口内做一次一元线性回归,得到随时间变化的 alpha、beta 等系数。
滚动单因子回归常见于 CAPM 滚动 beta、动态因子暴露、业绩归因等。
1 计算方式
1)模型
模型为:
其中每个滚动窗口内估计一组。
例如是资产超额收益,
是市场超额收益,则
是滚动 CAPM beta,
是滚动 Jensen alpha。
2)计算
对每个窗口:
一元回归下:
所以如果只需要 alpha、beta、R²,可以用 pandas 的滚动协方差/方差快速算。
2 向量化实现
1)Python基础实现
参考以上计算公式,Python向量化实现如下所示。
这样得到的每个值对应窗口的最后一天的对应参数值。
import pandas as pd import numpy as np # 假设 df 有两列:asset 是资产收益,factor 是因子收益 # index 是日期 window = 60 # 例如 60 个月、252 个交易日等 df = df.dropna() df['beta'] = df['asset'].rolling(window).cov(df['factor']) / df['factor'].rolling(window).var() df['alpha'] = df['asset'].rolling(window).mean() - df['beta'] * df['factor'].rolling(window).mean() df['r2'] = df['asset'].rolling(window).corr(df['factor']) ** 2 print(df[['alpha', 'beta', 'r2']].dropna().tail())如果要用作信号,通常还要向后平移一天,避免前视偏差:
df['beta_signal'] = df['beta'].shift(1)2)statsmodels实现
用statsmodels获取 t 值等完整结果,实现示例如下。
import pandas as pd import statsmodels.api as sm def rolling_ols(y, x, window): out = [] for end in range(window, len(y) + 1): yw = y.iloc[end - window:end] xw = x.iloc[end - window:end] X = sm.add_constant(xw) fit = sm.OLS(yw, X).fit() out.append({ 'date': y.index[end - 1], 'alpha': fit.params.iloc[0], 'beta': fit.params.iloc[1], 'alpha_t': fit.tvalues.iloc[0], 'beta_t': fit.tvalues.iloc[1], 'r2': fit.rsquared, 'nobs': window }) return pd.DataFrame(out).set_index('date') result = rolling_ols(df['asset'], df['factor'], window=60) print(result.tail())如果担心残差自相关,可以把fit = sm.OLS(...).fit()改成 HAC/Newey-West:
fit = sm.OLS(yw, X).fit( cov_type='HAC', cov_kwds={'maxlags': int(window ** 0.25)} )3 注意事项
1)窗口长度权衡
窗口太短,beta 噪声大,不稳定。
窗口太长,反应慢,无法捕捉结构变化。
常见,60 个月、36 个月、252 个交易日、120 个交易日。
2)数据频率要一致
月频因子就用月频收益,日频就用日频收益,不要混用。
3)前视偏差
滚动回归结果基于窗口末端数据,实盘使用时通常要shift(1)。
4)重叠窗口导致自相关
滚动 beta 序列通常高度平滑、自相关,做统计推断时最好用 Newey-West 或 bootstrap。
5)超额收益问题
如果 \(y\) 和 \(x\) 都是超额收益,alpha 是 Jensen alpha。
如果没有减去无风险利率,截距含义会不同。
6)多因子扩展
把一元回归换成多元回归即可:
reference
---
Rolling Beta Exposure
https://github.com/quantskills/skill-rolling-beta-exposure/blob/main/README.en.md
quantskills /skill-rolling-beta-exposure
https://github.com/quantskills/skill-rolling-beta-exposure/blob/main/examples/run_demo.py
skill-rolling-beta-exposure
GitHub - quantskills/skill-rolling-beta-exposure · GitHub