Fama-French三因子模型
模型
tushare ID=399224
在多因子模型出现以前,CAPM模型被奉为典型,几乎所有定价均是按照CAPM模型计算的。后来学者们发现了各种异象,这些异象无法用CAPM模型解释。较为典型的有Basu发现的盈利市值比效应和Banz发现的小市值效应。遗憾的是,虽然单一异象被发现后都对CAPM提出了挑战,但并没有形成合力,直到Fama三因子模型出现。本文通过对沪深300指数成分的子集的三因子模型进行选股,后对筛选出的股票使用支持向量机进行短期预测。再三因子模型中以单个股票的无风险收益率作为因变量,沪深300指数日无风险收益率、SMB、HML为自变量的三因子模型。
下面为Fama-French三因子模型
E [ R i ] − R f = β i , M K T ( E [ R M ] − R f ) + β i , S M B E [ R S M B ] + β i , H M L E [ R H M L ] E[R_i]-R_f=\beta_{i,MKT}(E[R_M]-R_f)+\beta_{i,SMB}E[R_{SMB}]+\beta_{i,HML}E[R_{HML}] E[Ri]−Rf=βi,MKT(E[RM]−Rf)+βi,SMBE[RSMB]+βi,HMLE[RHML]
E [ R i ] 代 表 股 票 i 的 预 期 收 益 率 ; R f 代 表 无 风 险 收 益 率 ; E [ R M ] 为 市 场 组 合 预 期 收 益 率 ; E [ R S M B ] 为 规 模 因 子 收 益 率 ; E [ R H M L ] 为 价 值 因 子 预 期 收 益 率 ; E[R_i]代表股票i的预期收益率; R_f代表无风险收益率; E[R_M]为市场组合预期收益率; E[R_{SMB}]为规模因子收益率; E[R_{HML}]为价值因子预期收益率; E[Ri]代表股票i的预期收益率;Rf代表无风险收益率;E[RM]为市场组合预期收益率;E[RSMB]为规模因子收益率;E[RHML]为价值因子预期收益率;
为构建价值因子和规模因子,Fama选择BM和市值两个指标进行双重排序,将股票分为大市值B和小市值S;按照账面市值将股票分为BM高于70%分位数的H组,BM低于30%分位数的L组,BM处于二者之间的记为M组。如下表
BM分组 | ||||
H | M | L | ||
市值分组 | S | S/H | S/M | S/L |
B | B/H | B/M | B/L |
得到上述分组后,就可以构建规模和价值两个因子。
S
M
B
=
1
3
(
S
/
H
+
S
/
M
+
S
/
L
)
−
1
3
(
B
/
H
+
B
/
M
+
B
/
L
)
SMB=\frac{1}{3}(S/H+S/M+S/L)-\frac{1}{3}(B/H+B/M+B/L)
SMB=31(S/H+S/M+S/L)−31(B/H+B/M+B/L)
H M L = 1 2 ( S / H + B / H ) − 1 2 ( S / L + B / L ) HML=\frac{1}{2}(S/H+B/H)-\frac{1}{2}(S/L+B/L) HML=21(S/H+B/H)−21(S/L+B/L)
选股
在用三因子模型估算股票预期收益率时,经常会发现并非每只股票都能严格吻合式1,大部分股票都会存在一个Alpha_i截距项。当存在Alpha_i截距项时,说明股票当前价格偏离均衡价格。基于此,可以设计套利策略。
Alpha_i < 0时,说明股票收益率低于均衡水平,股票价格被低估,应该买入。
Alpha_i > 0时,说明股票收益率高于均衡水平,股票价格被高估,应该卖出。
因此,可以在股票池中获取Alpha_i 小于0的股票买入开仓。
加入Alpha_i后得到公式
E
[
R
i
]
−
R
f
=
α
i
+
β
i
,
M
K
T
(
E
[
R
M
]
−
R
f
)
+
β
i
,
S
M
B
E
[
R
S
M
B
]
+
β
i
,
H
M
L
E
[
R
H
M
L
]
E[R_i]-R_f=\alpha_{i}+\beta_{i,MKT}(E[R_M]-R_f)+\beta_{i,SMB}E[R_{SMB}]+\beta_{i,HML}E[R_{HML}]
E[Ri]−Rf=αi+βi,MKT(E[RM]−Rf)+βi,SMBE[RSMB]+βi,HMLE[RHML]
例子
下面使用python进行建模
数据来自tushare平台
如果没有账号点击此处创建:https://tushare.pro/register?reg=399224
# coding=utf-8
import math
import tushare as ts
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
#import talib
import pandas as pd
from datetime import datetime, date
from sklearn import datasets
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
matplotlib.rcParams['axes.unicode_minus']=False
plt.rcParams['font.sans-serif']=['SimHei']
ts.set_token('your token')#如果没有tushare账户需要进入平台进行注册
pro = ts.pro_api()
data = pro.stock_basic(exchange='', list_status='L', fields='ts_code,symbol,name,area,industry,list_date')
############################读取数据类###################################
class readData:
def read_index_daily(self,code,star,end):#指数数据
dsb = pro.index_daily(ts_code=code, start_date=star, end_date=end,fields='ts_code,trade_date,close,change')#默认读取三个数据
return dsb
def read_daily(self,code,star,end):
dsc1 = pro.daily(ts_code=code, start_date=star, end_date=end,fields='ts_code,trade_date,close')
return dsc1
def read_CPI(self,star,end):#时间格式start_cpi='201609'
dc=pro.cn_cpi(start_m=star, end_m=end,fields='month,nt_yoy')
return dc
def read_GDP(self,star,end):#时间格式star='2016Q4'
df1 = pro.cn_gdp(start_q=star, end_q=end,fields='quarter,gdp_yoy')
return df1
def read_bond(self,code,star,end):
df=pro.cb_daily(ts_code=code,start_date=star,end_date=end)
def read_base(self,code):
df=pro.query('daily_basic', ts_code=code,fields='close,ts_code,pb,total_mv,trade_date')
return df
#######################################################################################
start_time='20200226'#发布GDP需要时间,我们延迟1个月,即第一季度的GDP4月份才发布。
end_time="20200901"
dc=readData()
dsc1=readData()
dsb1=readData()
dsc=dsc1.read_index_daily('000300.SH',start_time,end_time)
dsc.set_index(['trade_date'],inplace=True)
###################计算alpha的值###########################################################
def alpha_fun(code):
dsb=dsb1.read_base(code) .fillna(0)
dsb.set_index(['trade_date'],inplace=True)
df=pd.merge(dsc, dsb, on='trade_date').fillna(0)
R=np.reshape(np.array([df.close_y]) , (-1,1) )
R_f=np.reshape(np.array([(df.change/(df.close_x.shift(-1))).fillna(0)]),(-1,1))#用0 填充nan
HMI=np.reshape(np.array([(1/df.pb).fillna(0)]),(-1,1))
SMB=np.reshape(np.array([df.total_mv]),(-1,1))
X=np.concatenate((R_f-4/252,HMI,SMB),axis=1)
y1=np.reshape(R,(1,-1)).T
X_train, X_test, y_train, y_test = train_test_split(X, y1, test_size=0.3, random_state=0)
linear = LinearRegression()#进行回归建模
linear.fit(X_train, y_train)
alpha=linear.intercept_-4/252
return alpha,linear.intercept_ ,linear.coef_,linear.score(X_test, y_test),df
############################计算篮子里的每只股票净值###############################################
def jinzhi_fun(code,start_time,end_time):#计算净值
df=pro.daily(ts_code=str(code), start_date=start_time, end_date=end_time)
df.index=pd.to_datetime(df.trade_date,format="%Y-%m-%d")
jinzhi=(df.close/df.close[-1])
return jinzhi
######################选股条件####################################################
co=pro.query('daily_basic', ts_code="",trade_date="20200226",fields='ts_code')
print(co.shape)
code_list=[]
N=40#股票池
k=0
JZ=0#组合净值
cum=0
for i in co.ts_code.values[0:N]:
try:
if alpha_fun(i)[0]<0:
k+=1
JZ=jinzhi_fun(str(i) ,start_time,end_time)+JZ
JZ=JZ.fillna( method='bfill')#用前后数据特征填充
print(str(i)[0:6])
code_list.append([str(i),alpha_fun(i)[0][0]])
except ValueError:
pass
continue
#########################计算权重收益净值#########################################
JZ=JZ.sort_index(axis=0,ascending=True)
JZ_avg=JZ/k#平均净值
cum=np.cumprod(JZ_avg)# 累计收益
####################计算收益率函数,如沪深300#####################################
def JZ_function(code,star,end):
df12 = pro.index_daily( ts_code=code, start_date=star, end_date=end)
df12=df12.sort_index( )
df12.index=pd.to_datetime(df12.trade_date,format='%Y-%m-%d')#设置日期索引
ret12=df12.close/df12.close[-1]
return ret12.dropna()
#############################策略的年化统计######################################
def Tongji(jz):
NH=(jz.dropna()[-1]-1)*100*252/len(jz.index)
BD=np.std(jz)*100*np.sqrt(252)
SR=(NH-400/252)/BD
return_list=jz.dropna()
MHC=((np.maximum.accumulate(return_list) - return_list) / np.maximum.accumulate(return_list)).max()*100
print("年化收益率:{:.2f}%:,年化夏普率:{:.2f},波动率为:{:.2f}%,最大回撤:{:.2f}%".format( NH,SR,BD,MHC))
############################################################################
if __name__=="__main__":
cum12=JZ_function('000300.SH',start_time,end_time)
Tongji(JZ_avg)
plt.plot(cum12,label="沪深300",color='b')
plt.plot(JZ_avg,label="股票组合",color='r')
plt.title("alpha股+指期对冲策略")
plt.legend()
plt.show()
结果
年化收益率:25.57%:
年化夏普率:0.21;
波动率为:114.43%;
最大回撤:14.14%;