基金评价专题6:单因子构建及rankic评价

编程入门 行业动态 更新时间:2024-10-18 20:20:35

基金<a href=https://www.elefans.com/category/jswz/34/1767599.html style=评价专题6:单因子构建及rankic评价"/>

基金评价专题6:单因子构建及rankic评价

目录

1. 因子构建

1.1 因子解释

1.2 因子作用

1.3 因子刻画

2. 因子评价

2.1 Rank IC 解释

2.2 计算Rank IC值

2.3 Rank ICIR 解释

 2.4 计算 Rank ICIR 值


免责声明:本文由作者参考相关资料,并结合自身实践和思考独立完成,对全文内容的准确性、完整性或可靠性不作任何保证。同时,文中提及的基金仅作为举例使用,不构成推荐;文中所有观点均不构成任何投资建议。请读者仔细阅读本声明,若读者阅读此文章,默认知晓此声明。

1. 因子构建

1.1 因子解释

    因子,实际上就是一个由计算公式构建的指标(用于预测的一个变量)。通过抽象化的思维,来刻画描述对象存在的特征和规律,根据对应的规律可以挖掘出有用的信息。比如,常听说的动量因子,反转因子,市值因子,流动性因子等。从理论上理解起来相对有些抽象,接下来通过实际的案例来分析。因子主要

1.2 因子作用

   因子主要有两个作用:1.通过因子来遴选标的,这个是量化的常用方法。以本文为例,测算基金的某个因子值,通过因子值来遴选相应的基金。2.通过因子来进行风险识别和控制,这个是风控常用的方法。以Barra模型为例,通过测算投资组合的风险因子值,来识别当前组合在各个因子上的风险暴露,对于暴露超出预期的因子,需要在组合内进行相应的控制。

1.3 因子刻画

    夏普比率自身作为一个指标,因此可以直接作为一个因子。选取10只偏股型基金(此处需要注意,由于本文仅是举例,所以样本量控制的较小,在实际使用中,样本量应该足够大,在初筛或者没有其他约束条件的情况下最好是接近于全量,否则测算的结果很可能是无效的),计算其在2021年整年的夏普比率(无风险利率假设2%)。

import akshare as ak
import pandas as pd
import numpy as np
from scipy.stats import spearmanrdef get_data(code, year, dt=None):# 获取基金一整年的收益率或者夏普比率# code:str,基金代码,例如'000001'# year:int,年份,格式如2022# dt:str,输出数据的选择# 由于可能出现数据缺失的情况,因此添加异常处理try:data = ak.fund_open_fund_info_em(fund=code, indicator="累计净值走势")data['year'] = data['净值日期'].apply(lambda x: pd.to_datetime(x).year)new_data = data.loc[data['year'] == year]new_data = new_data.sort_values(['净值日期'], ascending=True)new_data['return'] = new_data['累计净值'].pct_change().fillna(0)annual_volatility = new_data['return'].std() * np.sqrt(252)annual_return = new_data['累计净值'].values[-1] / new_data['累计净值'].values[0] - 1rf = 0.02sharpe_ratio = (annual_return - rf) / annual_volatilityexcept:sharpe_ratio = 9999annual_return = 9999if dt == None:one_df = pd.DataFrame({'基金代码': [code], str(year) + '收益率': [annual_return]})elif dt == 'sharpe':one_df = pd.DataFrame({'基金代码': [code], str(year) + '夏普比率': [sharpe_ratio]})return one_dfif __name__ == '__main__':code_list = ['001552', '001726', '001628', '001736', '001643','001556', '001521', '001528', '001541', '001542']year = 2021all_df = pd.DataFrame()for code in code_list:print(code)one_df = get_data(code, year, 'sharpe')all_df = all_df.append(one_df)

    由于数据可能存在缺失,为避免报错,添加异常处理:将出现异常后的结果设置为9999,便于后续清洗过滤。 

  得到的结果下:

2. 因子评价

2.1 Rank IC 解释

    Rank IC (信息系数)是一个统计量,用以刻画预测变量和实际结果之间的关系(评价因子的预测效果)。Rank IC 的计算方式是预测变量的排序值和实际结果排序值之间的相关关系(通常是spaerman秩相关系数)。

  关于Rank IC的值的使用方法,类似于皮尔逊相关系数,主要如下:

  1.Rank IC的值位于-1和1之间。

  2.Rank IC值为正,表明预测结果和实际结果之间是正向关系;值为负则表示为反向关系。

  3.Rank IC的绝对值越大,说明预测结果和实际结果之间的关系越强烈,预测的准确度越高。

  4.一般地,Rank IC的值大于5%,则说明因子是有效的(前提需要建立在大量样本的统计下)。

2.2 计算Rank IC值

   此处的预测变量指的就是我们的因子,而实际结果一般是使用未来的收益率(由于因子的统计区间是2021年一整年,因此本文设置2022年的收益率作为实际结果来检验评价因子的预测效果)。

   接下来,实现获取2022年收益率这一步。

    next_year = year + 1next_df = pd.DataFrame()for code in code_list:print(code)next_year_df = get_data(code, next_year)next_df = next_df.append(next_year_df)me_df = pd.merge(all_df, next_df, how='inner', on='基金代码').fillna(0)# 数据清洗new_df = me_df.loc[me_df[str(year) + '夏普比率'] != 9999]new_df = new_df.loc[new_df[str(next_year) + '收益率'] != 9999]

    此处代码续接前文。这里需要特别注意,必须要保证数据的完整性,即某只基金对应的因子值和实际结果都必须是存在的,如果是二者之间出现异常值,则需要过滤,避免影响后续IRank IC 的计算结果。

  得到的结果为:

   下一步,根据因子值(2021年夏普值)和实际结果(2022年收益率)对应的排序值(降序排列,即值越大,排序值越低),计算出对应的Rank IC的值。

    out_df = new_df.sort_values([str(year) + '夏普比率'], ascending=False)out_df['因子排序值'] = [x+1 for x in range(len(out_df))]out_df = out_df.sort_values([str(next_year) + '收益率'], ascending=False)out_df['实际结果排序值'] = [x+1 for x in range(len(out_df))]rank_ic = spearmanr(out_df['因子排序值'],out_df['实际结果排序值'])[0]

   out_df对应的结果为:

    对应得到的Rank IC的值为-0.38。因此在不考虑样本量较低的情况下,所选的样本中以及对应时间区间中,夏普比率是一个有效的负向因子,即2021年的夏普比率越高,整体在2022年的表现越差。

2.3 Rank ICIR 解释

   Rank ICIR(信息比率),计算的方式是Rank IC的均值除以Rank IC的标准差。单期的Rank IC值稳定性不足,因此需要关注多期Rank IC值的情况,以便更好的评价因子的效果。Rank ICIR是对Rank IC的进一步补充,其实用方法和Rank IC一样,此处不再进行重复叙述。 

 2.4 计算 Rank ICIR 值

    首先,获取多期的Rank IC值。为了代码的简洁,封装一个单期Rank IC的函数--get_Rank_Ic,然后根的循环年份来获取相应每期的Rank IC值。

import akshare as ak
import pandas as pd
import numpy as np
from scipy.stats import spearmanrdef get_data(code, year, dt=None):# 获取基金一整年的收益率或者夏普比率# code:str,基金代码,例如'000001'# year:int,年份,格式如2022# dt:str,输出数据的选择# 由于可能出现数据缺失的情况,因此添加异常处理try:data = ak.fund_open_fund_info_em(fund=code, indicator="累计净值走势")data['year'] = data['净值日期'].apply(lambda x: pd.to_datetime(x).year)new_data = data.loc[data['year'] == year]new_data = new_data.sort_values(['净值日期'], ascending=True)new_data['return'] = new_data['累计净值'].pct_change().fillna(0)annual_volatility = new_data['return'].std() * np.sqrt(252)annual_return = new_data['累计净值'].values[-1] / new_data['累计净值'].values[0] - 1rf = 0.02sharpe_ratio = (annual_return - rf) / annual_volatilityexcept:sharpe_ratio = 9999annual_return = 9999if dt == None:one_df = pd.DataFrame({'基金代码': [code], str(year) + '收益率': [annual_return]})elif dt == 'sharpe':one_df = pd.DataFrame({'基金代码': [code], str(year) + '夏普比率': [sharpe_ratio]})return one_dfdef get_Rank_Ic(year, code_list):# 获取rankic的值all_df = pd.DataFrame()next_df = pd.DataFrame()next_year = year + 1for code in code_list:print(year, code)one_df = get_data(code, year, 'sharpe')next_year_df = get_data(code, next_year)next_df = next_df.append(next_year_df)all_df = all_df.append(one_df)me_df = pd.merge(all_df, next_df, how='inner', on='基金代码').fillna(0)# 数据清洗new_df = me_df.loc[me_df[str(year) + '夏普比率'] != 9999]new_df = new_df.loc[new_df[str(next_year) + '收益率'] != 9999]# 计算排序值out_df = new_df.sort_values([str(year) + '夏普比率'], ascending=False)out_df['因子排序值'] = [x + 1 for x in range(len(out_df))]out_df = out_df.sort_values([str(next_year) + '收益率'], ascending=False)out_df['实际结果排序值'] = [x + 1 for x in range(len(out_df))]rank_ic = spearmanr(out_df['因子排序值'], out_df['实际结果排序值'])[0]return rank_icif __name__ == '__main__':code_list = ['001552', '001726', '001628', '001736', '001643','001556', '001521', '001528', '001541', '001542']ic_df = pd.DataFrame()year_list = [2015 + x for x in range(0, 7)]for year in year_list:one_ic = get_Rank_Ic(year, code_list)one_df = pd.DataFrame({'年份': [year], 'ic值': [one_ic]})ic_df = ic_df.append(one_df)

  对应得到的结果是:

  接下来,分别求Rank IC的均值和标准差,然后计算Rank ICIR的值。

    ic_mean = ic_df['ic值'].mean()ic_std = ic_df['ic值'].std()Rank_Ic_Ir = ic_mean / ic_std

  对应的结果如下: 

  为了结果更加直观,对所得的结果进行可视化的展示。

    # 作图import matplotlib.pyplot as pltyear, ic = ic_df['年份'], ic_df['ic值']plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']plt.rcParams['axes.unicode_minus'] = Falseplt.title('因子评价' + '(' + 'IC均值:' + str(round(ic_mean, 4)) +';IC标准差:' + str(round(ic_std, 4)) + ';IR值:' + str(round(Rank_Ic_Ir, 4)) + ')')x = np.arange(len(year))plt.bar(x, ic, 0.5, label='逐年ic', tick_label=year)for i in range(len(ic)):plt.text(x[i], ic[i] + 0.01, round(ic[i], 4))plt.legend()plt.show()

  得到的结果如下:

   从结果来看:尽管Rank ICIR的值大于5%,但是Rank IC的标准差达到了32.7%;说明该因子具备较强的预测能力,但是稳定性不足,极端值较多。当然,出现这种结果是因为样本的数量较少。在实际的使用过程,除了需要较大的样本容量,还需要多个因子的组合来增加准确性。因为单个因子的预测作用有限,使用多因子组合可以有效提高预测的稳定性,后续将继续分享多因子组合。

本期分享结束,有何问题欢迎交流。

免责声明:本文由作者参考相关资料,并结合自身实践和思考独立完成,对全文内容的准确性、完整性或可靠性不作任何保证。同时,文中提及的基金仅作为举例使用,不构成推荐;文中所有观点均不构成任何投资建议。请读者仔细阅读本声明,若读者阅读此文章,默认知晓此声明。

更多推荐

基金评价专题6:单因子构建及rankic评价

本文发布于:2024-03-08 18:02:02,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1721720.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:评价   因子   基金   专题   rankic

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!