别再死记硬背Fama-French模型了!用Python实战拆解A股三因子(附代码与数据)
用Python实战拆解A股三因子模型:从理论到代码的完整指南
在量化投资领域,Fama-French三因子模型堪称经典,但很多初学者往往陷入"理论懂但不会用"的困境。本文将带你用Python完整实现这个模型在A股市场的应用,从数据获取到因子构建,再到回归分析和结果解读,每个步骤都配有可运行的代码片段。
1. 环境准备与数据获取
工欲善其事,必先利其器。我们需要先搭建好Python环境并获取必要的A股数据。
首先安装必要的Python库:
pip install pandas numpy statsmodels akshare matplotlib推荐使用AkShare获取A股数据,这是一个免费且维护良好的金融数据接口。以下是获取股票基础数据的代码示例:
import akshare as ak # 获取全部A股列表 stock_list = ak.stock_zh_a_spot() # 获取个股历史行情 stock_data = ak.stock_zh_a_daily(symbol="600519", adjust="hfq") # 以贵州茅台为例对于因子投资研究,我们通常需要以下类型的数据:
- 价格数据:日/周/月收益率
- 财务数据:账面市值比(BM)、盈利指标等
- 市场数据:市场收益率、无风险利率等
提示:A股市场存在停牌、ST股票等特殊情况,在数据处理时需要特别注意。
2. 三因子模型理论基础
Fama-French三因子模型在CAPM基础上增加了两个因子:
E(Ri) - Rf = βi*(E(Rm)-Rf) + βs*SMB + βv*HML + αi其中:
- 市场因子(Rm-Rf):市场超额收益
- 规模因子(SMB, Small Minus Big):小市值股票组合收益减去大市值股票组合收益
- 价值因子(HML, High Minus Low):高账面市值比股票组合收益减去低账面市值比股票组合收益
在A股市场应用时,需要考虑以下本土化特征:
- 市值效应:A股小盘股效应显著
- 价值因子:账面市值比的构建方式需要调整
- 流动性差异:A股个股流动性差异较大
3. 因子构建实战
3.1 市值因子(SMB)构建
市值因子反映的是小盘股相对于大盘股的超额收益。构建步骤如下:
- 每月末按市值将所有股票排序
- 分为三组:小(S)、中(M)、大(B)
- 计算小市值组合和大市值组合的收益率差
def build_smb_factor(data): # 按市值分组 data['市值分组'] = pd.qcut(data['流通市值'], q=3, labels=['S','M','B']) # 计算各组平均收益 group_returns = data.groupby('市值分组')['收益率'].mean() # SMB因子收益 smb = group_returns['S'] - group_returns['B'] return smb3.2 价值因子(HML)构建
价值因子反映的是高BM股票相对于低BM股票的超额收益。构建方法:
- 计算每只股票的账面市值比(BM)
- 按BM值排序并分组
- 计算高BM组合和低BM组合的收益率差
def build_hml_factor(data): # 计算BM值(需要财务数据) data['BM'] = data['账面价值'] / data['市值'] # 按BM分组(去除缺失值和极端值) valid_data = data[data['BM'].notna()] valid_data = valid_data[(valid_data['BM'] > valid_data['BM'].quantile(0.01)) & (valid_data['BM'] < valid_data['BM'].quantile(0.99))] valid_data['BM分组'] = pd.qcut(valid_data['BM'], q=3, labels=['L','M','H']) # HML因子收益 group_returns = valid_data.groupby('BM分组')['收益率'].mean() hml = group_returns['H'] - group_returns['L'] return hml3.3 市场因子构建
市场因子是市场组合收益率减去无风险利率:
def build_market_factor(market_return, risk_free_rate): return market_return - risk_free_rate4. 回归分析与模型检验
有了三个因子后,我们可以用statsmodels进行回归分析:
import statsmodels.api as sm # 准备数据 factors = pd.DataFrame({ 'MKT': market_factor, 'SMB': smb_factor, 'HML': hml_factor }) factors = sm.add_constant(factors) # 添加常数项 # 个股超额收益 stock_excess_return = stock_return - risk_free_rate # 回归分析 model = sm.OLS(stock_excess_return, factors) results = model.fit() print(results.summary())关键回归结果解读:
- Alpha(α):截距项,代表模型无法解释的超额收益
- 因子载荷(β):股票对各因子的敏感程度
- R-squared:模型解释力
注意:回归前需要检查多重共线性问题,可通过方差膨胀因子(VIF)诊断。
5. A股市场的特殊考量
在A股应用三因子模型时,需要特别注意:
停牌处理:
- 剔除长期停牌股票
- 对短期停牌采用最近价格填充
新股效应:
- A股新股上市初期波动剧烈
- 可考虑剔除上市不足半年的股票
财务数据时滞:
- A股财报披露有延迟
- 应采用最新可用数据而非实时数据
流动性差异:
- 小盘股流动性较差
- 可考虑加入流动性因子
# 流动性因子构建示例 def build_liquidity_factor(data): data['换手率'] = data['成交量'] / data['流通股本'] data['流动性分组'] = pd.qcut(data['换手率'], q=5, labels=['1','2','3','4','5']) group_returns = data.groupby('流动性分组')['收益率'].mean() liq_factor = group_returns['1'] - group_returns['5'] # 低流动性减高流动性 return liq_factor6. 模型优化与扩展
基础三因子模型可以进一步优化:
- 因子正交化:
- 消除因子间相关性
- 提高回归结果稳定性
from sklearn.decomposition import PCA # 因子正交化 pca = PCA(n_components=3) ortho_factors = pca.fit_transform(factors[['MKT','SMB','HML']])加入新因子:
- 动量因子(MOM)
- 盈利因子(RMW)
- 投资因子(CMA)
滚动回归:
- 观察因子暴露的时变性
- 识别市场风格变化
# 滚动回归示例 rolling_beta = pd.DataFrame(index=factors.index, columns=['MKT','SMB','HML']) for i in range(36, len(factors)): window = factors.iloc[i-36:i] # 3年滚动窗口 model = sm.OLS(stock_excess_return[i-36:i], window) results = model.fit() rolling_beta.iloc[i] = results.params[1:] # 排除截距项7. 结果可视化与分析
良好的可视化能更直观地展示分析结果:
import matplotlib.pyplot as plt # 因子收益率时序图 factors[['MKT','SMB','HML']].cumsum().plot(figsize=(12,6)) plt.title('三因子累积收益') plt.ylabel('累积收益') plt.show() # 因子暴露热力图 plt.figure(figsize=(10,6)) sns.heatmap(rolling_beta.corr(), annot=True, cmap='coolwarm') plt.title('因子暴露相关性') plt.show()关键分析要点:
- 因子显著性:t检验是否显著
- 模型解释力:R²大小
- 因子相关性:避免多重共线性
- 稳定性检验:不同时间段表现
8. 实战中的常见问题
在实际应用中,经常会遇到以下问题:
数据质量问题:
- 财务数据调整(如会计准则变化)
- 价格数据异常(如涨跌停、除权除息)
幸存者偏差:
- 仅使用现存股票会导致高估历史收益
- 应包含已退市股票数据
交易成本考量:
- 小盘股交易成本较高
- 需考虑换手率对收益的影响
参数敏感性:
- 分组数量(三分位vs五分位)
- 再平衡频率(月度vs季度)
# 幸存者偏差检查示例 def check_survivor_bias(original_returns, delisted_returns): combined = pd.concat([original_returns, delisted_returns]) bias = original_returns.mean() - combined.mean() print(f'幸存者偏差估计: {bias:.2%}') return bias9. 进阶方向与资源推荐
掌握基础三因子模型后,可以进一步探索:
五因子模型扩展:
- 加入盈利因子(RMW)
- 加入投资因子(CMA)
机器学习应用:
- 因子重要性排序
- 非线性关系建模
组合构建:
- 基于因子暴露的选股
- 风险平价配置
推荐学习资源:
书籍:
- 《主动投资组合管理》
- 《因子投资:方法与实践》
在线课程:
- Coursera上的"机器学习与量化投资"
- 量化投资实战网课
开源项目:
- Qlib:微软开发的量化平台
- backtrader:量化回测框架
10. 完整代码示例
以下是整合各步骤的完整代码框架:
import pandas as pd import numpy as np import akshare as ak import statsmodels.api as sm import matplotlib.pyplot as plt # 数据获取 def get_data(): # 实现数据获取逻辑 pass # 因子构建 def build_factors(data): # 实现三因子构建逻辑 pass # 回归分析 def run_regression(factors, stock_returns): # 实现回归分析逻辑 pass # 主程序 if __name__ == '__main__': # 获取并准备数据 raw_data = get_data() # 构建因子 factors = build_factors(raw_data) # 选择测试股票 test_stock = '600519' # 贵州茅台 stock_return = raw_data[raw_data['code']==test_stock]['return'] # 运行回归 results = run_regression(factors, stock_return) # 输出结果 print(results.summary()) # 可视化 factors.cumsum().plot(figsize=(12,6)) plt.title('Factor Cumulative Returns') plt.show()在实际项目中,这个框架可以根据具体需求进行扩展,比如添加更多因子、优化数据处理流程或引入更复杂的模型。
