我是靠谱客的博主 单纯花卷,最近开发中收集的这篇文章主要介绍基于收益率的基金绩效归因目的常用绩效归因模型模型分析及程序实现测试注意事项,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目的

使用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 RRf=α+β(RmRf)+ϵ

解读:
β 说 明 在 市 场 风 险 上 的 暴 露 , α 代 表 选 股 能 力 。 α > 0 代 表 有 正 向 选 股 能 力 beta说明在市场风险上的暴露,alpha代表选股能力。alpha>0代表有正向选股能力 βαα>0
每 个 参 数 对 应 的 p 值 代 表 结 果 是 否 显 著 , p < 0.05 表 示 显 著 每个参数对应的p值代表结果是否显著,p<0.05表示显著 pp<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 RRf=α+β1(RmRf)+β2(RmRf)2+ϵ
解读
α 显 著 大 于 0 说 明 有 选 股 能 力 , β 1 表 示 在 市 场 风 险 的 暴 露 , β 2 显 著 大 于 0 说 明 有 择 时 能 力 alpha显著大于0说明有选股能力,\ beta_1表示在市场风险的暴露,beta_2显著大于0说明有择时能力 α0β1,β20

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 RRf=α+β1(RmRf)+β2(RmRf)D+ϵ

其中:
当 R m − R f > 0 时 D = 1 , 否 则 D = 0 当R_m-R_f>0时D=1,否则D=0 RmRf>0D=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 RRf=α+β1×min(0,RmRf)+β2×max(0,RmRf)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 RRf=α+β1(RmRf)+β2(RmRf)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 RRf=α+β1(RmRf)+β2(RmRf)D+θ1SMB+θ2HML+ϵ

解读:
当 R m − R f > 0 时 D = 1 , 否 则 D = 0 当R_m-R_f>0时D=1,否则D=0 RmRf>0D=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 RRf=α+β1×min(0,RmRf)+β2×max(0,RmRf)+θ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']]

此处以大成高新技术产业股票型证券投资基金为例。

测试结果:

alphabetabeta1beta2p_alphap_betap_beta1p_beta2R2
CAPM15.94%81.22%//0.01%0.00%//74.25%
TM22.08%/80.61%-143.65%0.00%/0.00%0.14%74.44%
HM26.76%/83.22%-7.43%0.00%/0.00%2.91%77.54%
CL29.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,说明没有择时能力。 α20p0.05TMHMβ2p0.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']]

测试结果:

alphabetabeta1beta2theta1theta2p_alphap_beta1p_beta2p_theta1p_theta2R2
TM21.00%/79.32%-91.90%17.79%-11.40%0.00%0.00%2.95%0.00%0.00%77.53%
HM26.76%/83.22%-7.43%17.89%-11.44%0.00%0.00%2.91%0.00%0.00%77.54%
CL26.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θ10θ20

注意事项

虽然本次测试效果较好,但是要注意净值归因的主要缺陷,回归统计有可能因为各因子的共线性存在误差,另外在混合基金尤其是灵活配置基金上,因为基金配置了债券,回归效果不好。

最后

以上就是单纯花卷为你收集整理的基于收益率的基金绩效归因目的常用绩效归因模型模型分析及程序实现测试注意事项的全部内容,希望文章能够帮你解决基于收益率的基金绩效归因目的常用绩效归因模型模型分析及程序实现测试注意事项所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

评论列表共有 0 条评论

立即
投稿
返回
顶部