之前听过用IC加权的方法,前几天在论坛里有大佬提供了IC和ICIR的计算代码,就来尝试一下使用IC值和ICIR值来对因子进行加权,这里基于伽利略策略进行改造,时间周期为周,先上代码:
import numpy as npimport pandas as pdimport warnings
warnings.filterwarnings('ignore')
pd.set_option('expand_frame_repr', False) # 当列太多时不换行
pd.set_option('display.max_rows', 5000) # 最多显示数据的行数
# 参数设定# 选股数量select_stock_num = 10# 选择回测开始时间start_date='20070101`# 交易费用c_rate = 1.5 / 10000 # 手续费t_rate = 1 / 1000 # 印花税slippage=0.01# 选择数据周期period_type = 'w' # W代表周,M代表月# IC.IR参数period_length = 5
# 导入整理好的数据
df = pd.read_hdf('整理好的HDF5文件路径', 'df')
# 删除一些空值和不选的股票
df.dropna(subset=["下周期每天涨跌幅"], inplace=True)
df = df[df["下日_是否交易"] == True]
df = df[df["下日_开盘涨停"] == False]
df = df[df["下日_是否ST"] == False]
df = df[df["下日_是否退市"] == False]
factor_list=['总市值','收盘价','成交额','量价相关系数','bias']
排名计算代码已修改:
df=df[df['交易日期']>pd.to_datetime('20070101')]
df['总市值排名'] = df.groupby('交易日期')['总市值'].rank()
df['收盘价排名'] = df.groupby('交易日期')['收盘价'].rank()
df['成交额排名'] = df.groupby('交易日期')['成交额'].rank()
df['量价相关系数排名'] = df.groupby('交易日期')['量价相关系数'].rank()
df['bias排名'] = df.groupby('交易日期')['bias'].rank()
# 计算下周期涨跌幅
df["下日_开盘买入涨跌幅"] = df["下日_开盘买入涨跌幅"].apply(lambda x: [x])
df["下周期每天涨跌幅"] = df["下周期每天涨跌幅"].apply(lambda x: x[1:])
df["下周期每天涨跌幅"] = df["下日_开盘买入涨跌幅"] + df["下周期每天涨跌幅"]
# 计算下周期每天的资金曲线
df['选股下周期每天资金曲线'] = df['下周期每天涨跌幅'].apply(lambda x: np.cumprod(np.array(list(x)) + 1))
# 计算下周期整体涨跌幅
df['选股下周期涨跌幅'] = df['选股下周期每天资金曲线'].apply(lambda x: x[-1] - 1)
在计算IC和RankIC的时候对为正值的IC值进行了处理,给其赋值为-0.01,是因为所使用的因子都是越小对收益有正向影响,所以IC为正时说明上一期IC的效果并不好,原因可能是该因子效果在那一期不好或者当时的整体股市环境就不好,那么就给这个因子权重一个很小的值。如果是大环境不好,那么所有的因子效果可能都会比较差,那么所有因子权重可能就都是0.01,这样加权的比例和原策略一样;如果是该因子本身解释力变差,其他因子的IC值较大,那么这个因子在权重中的加权系数就为0.01,从而使该因子的影响性变得很小
# 计算IC相关因子
analysis_df = pd.DataFrame()for i in factor_list:
# 皮尔逊相关系数IC
analysis_df[f"{i}IC"] = df.groupby("交易日期")[[f"{i}", "选股下周期涨跌幅"]].apply(lambda x: x[f"{i}"].corr(x["选股下周期涨跌幅"]))
# 席皮尔曼相关系数RankIC
analysis_df[f"{i}RankIC"] = df.groupby("交易日期")[[f"{i}", "选股下周期涨跌幅"]].apply(lambda x: x[f"{i}"].corr(x["选股下周期涨跌幅"], method="spearman"))
# 计算IC和RankIC均值
analysis_df[f"{i}IC_{period_length}"] = analysis_df[f"{i}IC"].rolling(period_length, min_periods=1).mean()
analysis_df[f"{i}RankIC_{period_length}"] = analysis_df[f"{i}RankIC"].rolling(period_length, min_periods=1).mean()
# IC大于零的时候说明该因子值对下一期的收益正相关,为避免负影响,将其赋值为-0.01
analysis_df.loc[analysis_df[f'{i}IC']>0,[f'{i}IC']]=-0.01
analysis_df.loc[analysis_df[f'{i}RankIC']>0,[f'{i}RankIC']]=-0.01
# 计算前一个周期的IC和RankIC绝对值
analysis_df[f"pre_{i}abs_IC"] = np.abs(analysis_df[f"{i}IC"]).shift()
analysis_df[f"pre_{i}abs_RankIC"] = np.abs(analysis_df[f"{i}RankIC"]).shift()
# IC和RankIC均值大于零的时候,将其赋值为-0.01
analysis_df.loc[analysis_df[f'{i}IC_{period_length}'] > 0, [f'{i}IC_{period_length}']] = -0.01
analysis_df.loc[analysis_df[f'{i}RankIC_{period_length}'] > 0, [f'{i}RankIC_{period_length}'