克隆成功是否进入此策略?

确定取消

在R中计算因子IC的衰减曲线(20170827更新)

发布于2017-08-19 14:15 浏览 1620 评论 1 2 2 分享到:

一、IC介绍

(一)IC的定义和参数

信息系数,Information Coefficient (IC),是衡量因子有效性的一个重要指标,它等于某一时刻t1t_1的因子值和从该时刻开始至下一时刻[t1,t2][t_1, t_2]这个区间内的收益率之间的横截面相关性系数,

IC=cor(ft1,r[t1,t2])IC = cor(f_{t_1}, r_{[t_1, t_2]})

可以看出,如果使用不同的区间间隔,可以得到不同的IC,所以IC也可以定义为,

IC(k)=cor(ft,r[t,t+k])IC(k) = cor(f_{t}, r_{[t, t+k]})

其中kk为时间间隔的长度。

(二)IC评价因子有效性的应用

1、如何应用IC评价因子有效性

对于股票量化投资来说,我们构建量化股票模型和策略的一个重要核心目标就是希望利用现有信息对未来一段时间内的股票收益率有某种程度上的预期估计,而各种各样的因子正是构建这种模型和策略的基础原料(building blocks),所以每个因子在当期时刻所包含的信息和未来一段时间内的股票收益率的相关性(IC),自然而然的就是一个衡量因子forecasting能力的重要指标。

根据相关性系数的定义,它的取值范围为[-1, 1]:相关性系数越接近1,说明两个变量之间的正相关性越大;相关性系数越接近-1,说明两个变量之间的负相关性越大;相关性系数越接近0,说明两个变量之间的相关性越小。下面的图中列举了一些在不同相关性系数下,两个变量分布的例子。

1.png

IC本身就是相关性系数,所以它也完全具有上述的相关性系数的所有特征。值得注意的是,IC为负值并不是指因子无预测能力。不管是正相关还是负相关,只要因子和未来收益率的相关性越强,它就越具备好的预测潜力。

此外,因为IC本身跟定义的未来收益率的时间间隔有关,所以观察IC随时间间隔长短变化也是评价因子有效性中一项重要的步骤。下图是一个因子的IC随时间间隔的走势图,其中纵坐标为IC取值,横坐标为天数(譬如,10天表示当前因子值与未来10天的股票收益率的相关性)。图中黑线为真实IC曲线,红色曲线为平滑拟合之后的IC曲线,红色竖线表示平滑拟合后最大IC的位置。从图中可以看出:

  1. 短期内(10天之内)该因子与股票收益率为负相关性,然后随时间推移不断增加,由负转正。
  2. 在20天左右有较高的IC取值,说明它跟未来20天左右的股票收益率相关性最高。
  3. 30天之后该因子IC稳步下降,至70天之后基本跟股票收益率无相关性。

Rplot.png

天风金工有一篇关于应用IC信息构造多因子组合的文章大家可以看看:【天风金工吴先兴团队·专题报告十九】半衰IC加权在多因子选股中的应用。他们利用IC信息来分配多因子组合中每个因子的权重,他们相信较近期的IC意义大于历史远期的IC,所以利用IC的指数衰减平均结果来确定各因子在因子组合中的权重是更好的方法。

2、IC和IR的区别

信息比率,Information Ratio (IR),是一个容易和IC弄混淆的概念。两者的名称很接近,都跟“信息”有关,但从定义上看,两者没有任何关系:IC如前所述,是因子值和未来收益率的相关性;而IR是指股票组合的超额收益率(超过基准组合的收益率)的期望值与标准差的比值,即股票组合超额收益率经过风险调整之后的期望收益率。

IR=E(rprb)/SD(rprb)IR = E(r_p - r_b) / SD(r_p - r_b)

其中,rpr_p代表股票组合收益率,rbr_b代表基准收益率,E()E()代表期望值,SD()SD()代表标准差。

那么两者是不是完全没有关系呢?
我们来看一种特殊但是在测试因子有效性中常用的股票组合—因子值权重组合:使用因子值z-score作为权重的股票组合。
注意,这里指在横截面上对原始因子值做标准化得到z-score,ziz_i,那么必然有

z¯=zi=0,σz=SD(zi)=1\bar{z}=\sum z_i = 0, \sigma_z =SD(z_i) = 1

而因子值权重组合的收益率为,

rp=ziri=zi(rir¯)r_p = \sum z_i r_i = \sum z_i (r_i - \bar{r})

那么该组合的期望收益率为,

E(rp)=E(zi(rir¯))=E((ziz¯)(rir¯))cor(zi,ri)σzσrnσrIC\begin{aligned} E(r_p) &= E(\sum z_i (r_i - \bar{r})) \\ &= \sum E((z_i - \bar{z}) (r_i - \bar{r})) \\ &\approx \sum cor(z_i, r_i)\sigma_z \sigma_r \\ &\approx n \sigma_r IC \end{aligned}

当把上述结果拓展到多期时,可以得到,

E(rp,t)=nσrE(ICt)SD(rp,t)=nσrSD(ICt)\begin{aligned} E(r_{p,t}) &= n \sigma_r E(IC_t) \\ SD(r_{p,t}) &= n \sigma_r SD(IC_t) \end{aligned}

所以,

IRIC=E(ICt)SD(ICt)=E(rp,t)SD(rp,t)IR_{IC} = \frac{E(IC_t)}{SD(IC_t)} = \frac{E(r_{p,t})}{SD(r_{p,t})}

从上面的推理中可以看出,基于IC我们也可以算出一个IR指标(一般叫做IC_IR),它是对因子值权重组合的E(rp)SD(rp)\frac{E(r_p)}{SD(r_p)}的一个估计。

二、在R中实现IC衰减曲线

在文中后面附加了在大宽R环境中计算IC以及IC衰减曲线的代码,本节对该代码进行简要的介绍。

1. 数据获取

代码中的第一部分是数据获取函数的定义,主要是用于获取大宽提供的阿尔法因子数据和股票日数据,相关函数分别为:GetData_AlphaFactor()和GetData_StockData()。

函数定义完成之后,接下来是数据获取部分。代码中的示例获取的是“”APTF_ATR””因子数据,即技术指标ATR,对于其他阿尔法因子的名称、因子代码和介绍信息,可以在大宽帮助文中找到,具体位置见下图。

  1. # get factor data:
  2. fname <- "APTF_ATR"
  3. factorData <- GetData_AlphaFactor(fname, startDate = begindate, endDate = enddate)
  4. # get stock data:
  5. stockData <- GetData_StockData(begindate, enddate)
  6. tradingdate <- sort(unique(stockData$TRADINGDATE))

2.png

2. IC计算

IC的计算通过IC_decay()函数完成,在该函数中:tradingdate, stockData, factorData为数据输入参数;ind_0表示计算IC序列的时间起点,以在tradingdate中序数(index)作为输入;nmax为最大计算多少天的IC。
函数计算逻辑:先是初始设置部分,在这里我们设置了初始日期(即当期时刻)以及在该时刻上的因子值和股票价格。这之后,是循环计算未来股票收益率及相应的IC的部分,IC结果存于cor_df变量之中。

  1. IC_decay <- function(tradingdate, stockData, factorData, ind_0, nmax){
  2. # set up:
  3. date_0 <- tradingdate[ind_0]
  4. stockdat_0 <- stockData[stockData$TRADINGDATE == date_0, c("SECUCODE", "AdjClose")]
  5. colnames(stockdat_0)[2] <- "AdjClose_0"
  6. factordat_0 <- factorData[factorData$TRADINGDATE == date_0, c("SECUCODE", fname)]
  7. dat_all_0 <- merge(factordat_0, stockdat_0, by = "SECUCODE", all = FALSE)
  8. # calculate IC for each day:
  9. nmax <- min(nmax, length(tradingdate) - ind_0)
  10. cor_df <- NULL
  11. for(i in 1:nmax){ # i = 1
  12. date <- tradingdate[ind_0 + i]
  13. stockdat <- stockData[stockData$TRADINGDATE == date, c("SECUCODE", "AdjClose")]
  14. dat_all <- merge(dat_all_0, stockdat, by = "SECUCODE", all = FALSE)
  15. dat_all$RTN <- (dat_all$AdjClose - dat_all$AdjClose_0) / dat_all$AdjClose_0
  16. cor_df <- rbind(cor_df, data.frame(NDAY = i, IC = cor(dat_all[, fname], dat_all$RTN)))
  17. }
  18. return(cor_df)
  19. }

3. 固定起点IC计算结果

我们通过设置IC_decay()函数中ind_0的取值来固定计算IC序列的起始日期,然后设置最多计算50天之后的IC(nmax = 50),计算得到IC序列cor_df,最后可视化显示(图中黑线为真实IC曲线,红色曲线为平滑拟合之后的IC曲线,红色竖线表示平滑拟合后最大IC的位置)。

  1. # calcualte IC time series for fixed startdate:
  2. cor_df <- IC_decay(tradingdate, stockData, factorData, ind_0 = 1, nmax = 50)
  3. # plot:
  4. plot(cor_df, type = "l")
  5. fit <- lm(IC~NDAY + I(NDAY^2) + I(NDAY^3) + I(NDAY^4), data = cor_df)
  6. lines(cor_df$NDAY, fitted(fit), col = 2, lty = 2)
  7. abline(v = cor_df$NDAY[which.max(fitted(fit))], col = 2, lty = 2)

1.png

3. 不同起点IC计算结果

通过一个循环,计算以不同日期作为计算IC序列的起始日期,所有结果存于res_IC_decay,最后可视化:图中大量的黑虚线表示不同起始日期的IC序列,红色粗线为它们的平均值,绿色的两条粗线为平均值正负1个标准差。

  1. # calcualte IC time series for different startdates:
  2. nmax <- 50
  3. res_IC_decay <- NULL
  4. for(i in 1:(length(tradingdate) - nmax)){
  5. cor_df <- IC_decay(tradingdate, stockData, factorData, ind_0 = i, nmax = nmax)
  6. colnames(cor_df)[2] <- tradingdate[i]
  7. if(i == 1){
  8. res_IC_decay <- cor_df
  9. } else{
  10. res_IC_decay <- merge(res_IC_decay, cor_df, by = "NDAY", all = TRUE)
  11. }
  12. }
  13. # get average and std of ICs:
  14. IC_avg <- apply(res_IC_decay[, -1], 1, mean)
  15. IC_sd <- apply(res_IC_decay[, -1], 1, sd)
  16. # plot:
  17. matplot(res_IC_decay[, -1], type = "l", lty = 3, col = 1,
  18. xlab = "NDAY", ylab = "IC")
  19. lines(res_IC_decay$NDAY, IC_avg, lwd = 3, col = 2)
  20. lines(res_IC_decay$NDAY, IC_avg + IC_sd, lwd = 2, col = 3)
  21. lines(res_IC_decay$NDAY, IC_avg - IC_sd, lwd = 2, col = 3)

2.png

1 个评论

感觉平均之后IC随时间变化的效应就不明显了,可能不同交易日因子的IC衰减结构都一样,实际策略中使用如何处理比较好呢?我的因子做过测试,可能在一些交易日衰减很好,但在有些交易日完全衰减不下来,后面一直在较平稳的震荡。怎么理解呢?
发表评论