概述
目的
使用Python和Tushare数据,基于基金净值分析基金选股、择时能力。
常用绩效归因模型
- CAPM模型
- TM模型
- HM模型
- CL模型
- TM-FF3模型
- HM-FF3模型
- CL-FF3模型
模型分析及程序实现
使用到的库
#t导入ushare库
import tushare as ts
pro = ts.pro_api('your token')
#导入统计库
import statsmodels.api as sm
#导入pandas
import pandas as pd
#统一起见,无风险收益率设为年化3%
rf=1.03**(1/250)-1
通用函数
获取指数日收益率序列
def get_index_price(code,start_date,end_date):
"""
功能:获取指定指数一定时间段内日收益率序列
输入:
code:指数代码
start_date:开始日期
end_date:结束日期
返回:
DataFrame,index=日期,columns='close'
"""
#使用tushare获取数据。
df=pro.index_daily(**{"ts_code":code,"start_date":start_date,"end_date":end_date},fields=["trade_date","close"])
#设置日期为索引
df.set_index('trade_date',inplace=True)
#按升序排列
df.sort_index(ascending=True,inplace=True)
#计算每日收益率
result=df/df.shift(1)-1
#去掉空值
result.dropna(inplace=True)
#返回数据
return result['close']
获取基金日收益率序列
def get_fund_netvalue(code,start_date,end_date):
"""
功能:获取指定基金一定时间段内每日收益率序列
输入:
code:基金代码
start_date:开始日期
end_date:结束日期
返回:
Series,index=日期
"""
df=pro.fund_nav(**{"ts_code":code,"start_date":start_date,"end_date":end_date},fields=["nav_date","accum_nav"])
df.set_index('nav_date',inplace=True)
df.sort_index(ascending=True,inplace=True)
result=df/df.shift(1)-1
result.dropna(inplace=True)
return result['accum_nav']
CAPM模型
公式:
R
−
R
f
=
α
+
β
(
R
m
−
R
f
)
+
ϵ
R-R_f=alpha+beta(R_m-R_f)+epsilon
R−Rf=α+β(Rm−Rf)+ϵ
解读:
β
说
明
在
市
场
风
险
上
的
暴
露
,
α
代
表
选
股
能
力
。
α
>
0
代
表
有
正
向
选
股
能
力
beta说明在市场风险上的暴露,alpha代表选股能力。alpha>0代表有正向选股能力
β说明在市场风险上的暴露,α代表选股能力。α>0代表有正向选股能力
每
个
参
数
对
应
的
p
值
代
表
结
果
是
否
显
著
,
p
<
0.05
表
示
显
著
每个参数对应的p值代表结果是否显著,p<0.05表示显著
每个参数对应的p值代表结果是否显著,p<0.05表示显著
#CAPM模型计算
def CAPM(data):
"""
功能:使用CAPM模型计算选股能力
输入:
data:DataFrame,index=日期
columns包括:
fund_rtn:Series,基金日收益率序列
index_rtn:Series,指数日收益率序列
输出:
字典,key=alpha,beta,p_alpha,p_beta
"""
#计算R-Rf,Rm-Rf
y=data['fund_rtn']-rf
x=data['index_rtn']-rf
#添加约束
x=sm.add_constant(x)
#回归计算
cal_result=sm.OLS(y,x).fit()
#取得结果
result={}
result['alpha']=(1+cal_result.params['const'])**250-1#年化alpha
result['beta']=cal_result.params['index_rtn']
result['p_alpha']=cal_result.pvalues['const']
result['p_beta']=cal_result.pvalues['index_rtn']
result['R2']=cal_result.rsquared
return result
TM模型
公式
R
−
R
f
=
α
+
β
1
(
R
m
−
R
f
)
+
β
2
(
R
m
−
R
f
)
2
+
ϵ
R-R_f=alpha+beta_1(R_m-R_f)+beta_2(R_m-R_f)^2+epsilon
R−Rf=α+β1(Rm−Rf)+β2(Rm−Rf)2+ϵ
解读
α
显
著
大
于
0
说
明
有
选
股
能
力
,
β
1
表
示
在
市
场
风
险
的
暴
露
,
β
2
显
著
大
于
0
说
明
有
择
时
能
力
alpha显著大于0说明有选股能力,\ beta_1表示在市场风险的暴露,beta_2显著大于0说明有择时能力
α显著大于0说明有选股能力,β1表示在市场风险的暴露,β2显著大于0说明有择时能力
def TM(data):
"""
功能:使用CAPM模型计算选股能力
输入:
data:DataFrame,index=日期
columns包括:
fund_rtn:基金日收益率序列
index_rtn:指数日收益率序列
输出:
字典,key=alpha,beta1,beta2,p_alpha,p_beta1,p_beta2,R2
"""
#计算R-Rf,Rm-Rf
y=data['fund_rtn']-rf
x1=data['index_rtn']-rf
x2=x1**2
#整合rm数据
x_data=pd.DataFrame()
x_data['rm1']=x1
x_data['rm2']=x2
#添加约束
x=sm.add_constant(x_data)
#回归计算
cal_result=sm.OLS(y,x).fit()
#取得结果
result={}
result['alpha']=(1+cal_result.params['const'])**250-1
result['beta1']=cal_result.params['rm1']
result['beta2']=cal_result.params['rm2']
result['p_alpha']=cal_result.pvalues['const']
result['p_beta1']=cal_result.pvalues['rm1']
result['p_beta2']=cal_result.pvalues['rm2']
result['R2']=cal_result.rsquared
return result
HM模型
公式
R
−
R
f
=
α
+
β
1
(
R
m
−
R
f
)
+
β
2
(
R
m
−
R
f
)
D
+
ϵ
R-R_f=alpha+beta_1(R_m-R_f)+beta_2(R_m-R_f)D+epsilon
R−Rf=α+β1(Rm−Rf)+β2(Rm−Rf)D+ϵ
其中:
当
R
m
−
R
f
>
0
时
D
=
1
,
否
则
D
=
0
当R_m-R_f>0时D=1,否则D=0
当Rm−Rf>0时D=1,否则D=0
α , β 含 义 与 T M 相 同 alpha,beta含义与TM相同 α,β含义与TM相同
def HM(data):
"""
功能:使用CAPM模型计算选股能力
输入:
data:DataFrame,index=日期
columns包括:
fund_rtn:基金日收益率序列
index_rtn:指数日收益率序列
输出:
字典,key=alpha,beta1,beta2,p_alpha,p_beta1,p_beta2,R2
"""
#计算R-Rf,Rm-Rf
y=data['fund_rtn']-rf
x1=data['index_rtn']-rf
x2=x1.copy()
x2[x2<=0]=0
#整合rm数据
x_data=pd.DataFrame()
x_data['rm1']=x1
x_data['rm2']=x2
#添加约束
x=sm.add_constant(x_data)
#回归计算
cal_result=sm.OLS(y,x).fit()
#取得结果
result={}
result['alpha']=(1+cal_result.params['const'])**250-1
result['beta1']=cal_result.params['rm1']
result['beta2']=cal_result.params['rm2']
result['p_alpha']=cal_result.pvalues['const']
result['p_beta1']=cal_result.pvalues['rm1']
result['p_beta2']=cal_result.pvalues['rm2']
result['R2']=cal_result.rsquared
return result
CL模型
公式
R
−
R
f
=
α
+
β
1
×
m
i
n
(
0
,
R
m
−
R
f
)
+
β
2
×
m
a
x
(
0
,
R
m
−
R
f
)
D
+
ϵ
R-R_f=alpha+beta_1times min(0,R_m-R_f)+beta_2times max(0,R_m-R_f)D+epsilon
R−Rf=α+β1×min(0,Rm−Rf)+β2×max(0,Rm−Rf)D+ϵ
解读
β 1 代 表 空 头 市 场 β , β 2 代 表 多 头 市 场 β , β 2 − β 1 > 0 说 明 有 择 时 能 力 beta_1代表空头市场beta,beta_2代表多头市场beta,beta_2-beta_1>0说明有择时能力 β1代表空头市场β,β2代表多头市场β,β2−β1>0说明有择时能力
def CL(data):
"""
功能:使用CAPM模型计算选股能力
输入:
data:DataFrame,index=日期
columns包括:
fund_rtn:基金日收益率序列
index_rtn:指数日收益率序列
输出:
字典,key=alpha,beta1,beta2,beta,p_alpha,p_beta1,p_beta2,R2。其中beta=beta2-beta1代表择时能力
"""
#计算R-Rf,Rm-Rf
y=data['fund_rtn']-rf
x1=data['index_rtn']-rf
x2=x1.copy()
#计算beta1对应的收益率,当收益率大于0时为0
x1[x1>0]=0
#计算beta2对应的收益率,当收益率小于0时为0
x2[x2<=0]=0
#整合rm数据
x_data=pd.DataFrame()
x_data['rm1']=x1
x_data['rm2']=x2
#添加约束
x=sm.add_constant(x_data)
#回归计算
cal_result=sm.OLS(y,x).fit()
#取得结果
result={}
result['alpha']=(1+cal_result.params['const'])**250-1
result['beta1']=cal_result.params['rm1']
result['beta2']=cal_result.params['rm2']
result['beta']=result['beta2']-result['beta1']
result['p_alpha']=cal_result.pvalues['const']
result['p_beta1']=cal_result.pvalues['rm1']
result['p_beta2']=cal_result.pvalues['rm2']
result['R2']=cal_result.rsquared
return result
FF3模型
前面的TM、HM、CL模型都只考虑了市场影响,而没有考虑基金在某种风格上的暴露。
Fama和French引入了公司规模因子(SMB)和账面市值因子(HML),就是常说的大盘、小盘、价值、成长风格,建立了TM-FF3、HM-FF3、CL-FF3模型。
SMB和HML因子收益率有很多方法,比如大中小盘用市值最大的前200只为大盘,200-500为中盘,501以后为小盘,然后每个市值分组中再按估值、利润增速、营收增速等综合打分确定价值成长风格,然后用不同分组收益率相减得到该风格收益率。这种方法需要的数据量太大(全市场数据),tushare上取得这些数据需要的积分太高,所以此处使用简化方法:SMB收益率用巨潮小盘指数-巨潮大盘指数收益率,HML收益率用国证成长指数-国证价值指数收益率代替。
TM-FF3模型
首先看TM-FF3模型
公式:
R
−
R
f
=
α
+
β
1
(
R
m
−
R
f
)
+
β
2
(
R
m
−
R
f
)
2
+
θ
1
S
M
B
+
θ
2
H
M
L
+
ϵ
R-R_f=alpha+beta_1(R_m-R_f)+beta_2(R_m-R_f)^2+theta_1SMB+theta_2HML+epsilon
R−Rf=α+β1(Rm−Rf)+β2(Rm−Rf)2+θ1SMB+θ2HML+ϵ
其中 θ 1 和 θ 2 分 别 表 示 在 大 小 盘 风 格 、 价 值 成 长 风 格 上 的 暴 露 theta_1和theta_2分别表示在大小盘风格、价值成长风格上的暴露 θ1和θ2分别表示在大小盘风格、价值成长风格上的暴露
def TM_FF3(data):
"""
功能:使用CAPM模型计算选股能力
输入:
data:DataFrame,index=日期
columns包括:
fund_rtn:基金日收益率序列
index_rtn:指数日收益率序列
HML_rtn:价值成长指数日收益率序列
SMB_rtn:大小盘指数日收益率序列
输出:
字典,key=alpha,beta1,beta2,p_alpha,p_beta1,p_beta2,R2
"""
#计算R-Rf,Rm-Rf
y=data['fund_rtn']-rf
x1=data['index_rtn']-rf
x2=x1**2
#整合rm数据
x_data=pd.DataFrame()
x_data['rm1']=x1
x_data['rm2']=x2
x_data['HML']=data['HML_rtn']
x_data['SMB']=data['SMB_rtn']
#添加约束
x=sm.add_constant(x_data)
#回归计算
cal_result=sm.OLS(y,x).fit()
#取得结果
result={}
result['alpha']=(1+cal_result.params['const'])**250-1
result['beta1']=cal_result.params['rm1']
result['beta2']=cal_result.params['rm2']
result['theta1']=cal_result.params['SMB']
result['theta2']=cal_result.params['HML']
result['p_alpha']=cal_result.pvalues['const']
result['p_beta1']=cal_result.pvalues['rm1']
result['p_beta2']=cal_result.pvalues['rm2']
result['p_theta1']=cal_result.pvalues['SMB']
result['p_theta2']=cal_result.pvalues['HML']
result['R2']=cal_result.rsquared
return result
HM-FF3模型
公式
R
−
R
f
=
α
+
β
1
(
R
m
−
R
f
)
+
β
2
(
R
m
−
R
f
)
D
+
θ
1
S
M
B
+
θ
2
H
M
L
+
ϵ
R-R_f=alpha+beta_1(R_m-R_f)+beta_2(R_m-R_f)D+theta_1SMB+theta_2HML+epsilon
R−Rf=α+β1(Rm−Rf)+β2(Rm−Rf)D+θ1SMB+θ2HML+ϵ
解读:
当
R
m
−
R
f
>
0
时
D
=
1
,
否
则
D
=
0
当R_m-R_f>0时D=1,否则D=0
当Rm−Rf>0时D=1,否则D=0
def HM_FF3(data):
"""
功能:使用CAPM模型计算选股能力
输入:
data:DataFrame,index=日期
columns包括:
fund_rtn:基金日收益率序列
index_rtn:指数日收益率序列
HML_rtn:价值成长指数日收益率序列
SMB_rtn:大小盘指数日收益率序列
输出:
字典,key=alpha,beta1,beta2,p_alpha,p_beta1,p_beta2,R2
"""
#计算R-Rf,Rm-Rf
y=data['fund_rtn']-rf
x1=data['index_rtn']-rf
x2=x1.copy()
x2[x2<=0]=0
#整合rm数据
x_data=pd.DataFrame()
x_data['rm1']=x1
x_data['rm2']=x2
x_data['HML']=data['HML_rtn']
x_data['SMB']=data['SMB_rtn']
#添加约束
x=sm.add_constant(x_data)
#回归计算
cal_result=sm.OLS(y,x).fit()
#取得结果
result={}
result['theta1']=cal_result.params['SMB']
result['theta2']=cal_result.params['HML']
result['alpha']=(1+cal_result.params['const'])**250-1
result['beta1']=cal_result.params['rm1']
result['beta2']=cal_result.params['rm2']
result['p_alpha']=cal_result.pvalues['const']
result['p_beta1']=cal_result.pvalues['rm1']
result['p_beta2']=cal_result.pvalues['rm2']
result['p_theta1']=cal_result.pvalues['SMB']
result['p_theta2']=cal_result.pvalues['HML']
result['R2']=cal_result.rsquared
return result
CL-FF3模型
公式
R
−
R
f
=
α
+
β
1
×
m
i
n
(
0
,
R
m
−
R
f
)
+
β
2
×
m
a
x
(
0
,
R
m
−
R
f
)
+
θ
1
S
M
B
+
θ
2
H
M
L
+
ϵ
R-R_f=alpha+beta_1times min(0,R_m-R_f)+beta_2times max(0,R_m-R_f)+theta_1SMB+theta_2HML+epsilon
R−Rf=α+β1×min(0,Rm−Rf)+β2×max(0,Rm−Rf)+θ1SMB+θ2HML+ϵ
解读
β 1 代 表 空 头 市 场 β , β 2 代 表 多 头 市 场 β , β 2 − β 1 > 0 说 明 有 择 时 能 力 beta_1代表空头市场beta,beta_2代表多头市场beta,beta_2-beta_1>0说明有择时能力 β1代表空头市场β,β2代表多头市场β,β2−β1>0说明有择时能力
def CL_FF3(data):
"""
功能:使用CAPM模型计算选股能力
输入:
data:DataFrame,index=日期
columns包括:
fund_rtn:基金日收益率序列
index_rtn:指数日收益率序列
HML_rtn:价值成长指数日收益率序列
SMB_rtn:大小盘指数日收益率序列
输出:
字典,key=alpha,beta1,beta2,beta,p_alpha,p_beta1,p_beta2,R2。其中beta=beta2-beta1代表择时能力
"""
#计算R-Rf,Rm-Rf
y=data['fund_rtn']-rf
x1=data['index_rtn']-rf
x2=x1.copy()
#计算beta1对应的收益率,当收益率大于0时为0
x1[x1>0]=0
#计算beta2对应的收益率,当收益率小于0时为0
x2[x2<=0]=0
#整合rm数据
x_data=pd.DataFrame()
x_data['rm1']=x1
x_data['rm2']=x2
x_data['HML']=data['HML_rtn']
x_data['SMB']=data['SMB_rtn']
#添加约束
x=sm.add_constant(x_data)
#回归计算
cal_result=sm.OLS(y,x).fit()
#取得结果
result={}
result['alpha']=(1+cal_result.params['const'])**250-1
result['beta1']=cal_result.params['rm1']
result['beta2']=cal_result.params['rm2']
result['beta']=result['beta2']-result['beta1']
result['theta1']=cal_result.params['SMB']
result['theta2']=cal_result.params['HML']
result['p_alpha']=cal_result.pvalues['const']
result['p_beta1']=cal_result.pvalues['rm1']
result['p_beta2']=cal_result.pvalues['rm2']
result['p_theta1']=cal_result.pvalues['SMB']
result['p_theta2']=cal_result.pvalues['HML']
result['R2']=cal_result.rsquared
return result
测试
获取数据
fund_code='000628.OF'#基金代码,以大成高新技术产业股票型证券投资基金为例
base='000300.SH'#市场基准指数用沪深300
index_B='399314.SZ'#巨潮大盘指数
index_S='399316.SZ'#巨潮小盘指数
index_H='399371.SZ'#国证价值指数
index_L='399370.SZ'#国证成长指数
start_date='20160729'
end_date='20220601'
data=pd.DataFrame()
data['fund_rtn']=get_fund_netvalue(fund_code,start_date,end_date)
data['index_rtn']=get_index_price(base,start_date,end_date)
#SMB因子收益
data['SMB_rtn']=get_index_price(index_S,start_date,end_date)-get_index_price(index_B,start_date,end_date)
#HML因子收益
data['HML_rtn']=get_index_price(index_H,start_date,end_date)-get_index_price(index_L,start_date,end_date)
data.dropna(inplace=True)
不考虑风格因子
result={}
result['CAPM']=CAPM(data)
result['TM']=TM(data)
result['HM']=HM(data)
result['CL']=CL(data)
result=pd.DataFrame(result).T.applymap(lambda x:"{:.2%}".format(x)).replace('nan%','/')
result[['alpha','beta','beta1','beta2','p_alpha','p_beta','p_beta1','p_beta2','R2']]
此处以大成高新技术产业股票型证券投资基金为例。
测试结果:
alpha | beta | beta1 | beta2 | p_alpha | p_beta | p_beta1 | p_beta2 | R2 | |
---|---|---|---|---|---|---|---|---|---|
CAPM | 15.94% | 81.22% | / | / | 0.01% | 0.00% | / | / | 74.25% |
TM | 22.08% | / | 80.61% | -143.65% | 0.00% | / | 0.00% | 0.14% | 74.44% |
HM | 26.76% | / | 83.22% | -7.43% | 0.00% | / | 0.00% | 2.91% | 77.54% |
CL | 29.16% | -10.10% | 85.99% | 75.89% | 0.00% | / | 0.00% | 0.00% | 74.39% |
年 化 α 几 个 模 型 都 在 20 以 上 , 且 p 值 小 于 0.05 , 说 明 选 股 能 力 不 错 。 T M 、 H M 模 型 的 β 2 为 负 数 , 且 p 值 小 于 0.05 , 说 明 没 有 择 时 能 力 。 年化alpha几个模型都在20以上,且p值小于0.05,说明选股能力不错。\ TM、HM模型的beta2为负数,且p值小于0.05,说明没有择时能力。 年化α几个模型都在20以上,且p值小于0.05,说明选股能力不错。TM、HM模型的β2为负数,且p值小于0.05,说明没有择时能力。
考虑风格因子
result={}
result['TM']=TM_FF3(data)
result['HM']=HM_FF3(data)
result['CL']=CL_FF3(data)
result=pd.DataFrame(result).T.applymap(lambda x:"{:.2%}".format(x)).replace('nan%','/')
result[['alpha','beta','beta1','beta2','theta1','theta2','p_alpha','p_beta1','p_beta2','p_theta1','p_theta2','R2']]
测试结果:
alpha | beta | beta1 | beta2 | theta1 | theta2 | p_alpha | p_beta1 | p_beta2 | p_theta1 | p_theta2 | R2 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
TM | 21.00% | / | 79.32% | -91.90% | 17.79% | -11.40% | 0.00% | 0.00% | 2.95% | 0.00% | 0.00% | 77.53% |
HM | 26.76% | / | 83.22% | -7.43% | 17.89% | -11.44% | 0.00% | 0.00% | 2.91% | 0.00% | 0.00% | 77.54% |
CL | 26.76% | -7.43% | 83.22% | 75.78% | 17.89% | -11.44% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 77.54% |
α 结 果 与 不 考 虑 风 格 因 子 接 近 , β 2 也 说 明 没 有 择 时 能 力 。 θ 1 显 著 大 于 0 , 说 明 市 值 风 格 偏 向 大 盘 。 θ 2 显 著 小 于 0 , 说 明 价 值 成 长 风 格 偏 向 成 长 。 alpha结果与不考虑风格因子接近,beta2也说明没有择时能力。\ theta1显著大于0,说明市值风格偏向大盘。\ theta2显著小于0,说明价值成长风格偏向成长。 α结果与不考虑风格因子接近,β2也说明没有择时能力。θ1显著大于0,说明市值风格偏向大盘。θ2显著小于0,说明价值成长风格偏向成长。
注意事项
虽然本次测试效果较好,但是要注意净值归因的主要缺陷,回归统计有可能因为各因子的共线性存在误差,另外在混合基金尤其是灵活配置基金上,因为基金配置了债券,回归效果不好。
最后
以上就是单纯花卷为你收集整理的基于收益率的基金绩效归因目的常用绩效归因模型模型分析及程序实现测试注意事项的全部内容,希望文章能够帮你解决基于收益率的基金绩效归因目的常用绩效归因模型模型分析及程序实现测试注意事项所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复