library(quantbox)
library(knitr)
knitr::opts_chunk$set(
  eval = FALSE,
  warning = FALSE
)

该文档旨在介绍国投瑞银量化投资部的多因子体系。

因子分类

由于因子众多,我们根据因子的数据源、因子特征,将因子分成8大类,涵盖市值、成长、估值、一致预期、盈利能力、交易行为、财务质量及其他。因子分类部分结果展示如下表。

ftable <- CT_GroupFactorLists()
ftable <- sample_n(ftable[,c("factorType","groupDesc","factorFun","factorDesc","wgt")],10)
kable(ftable,row.names = FALSE)

单因子检验

单因子检验是多因子研究的第一步。以预期类的一致预期目标涨幅因子为例,简单的展示单因子检验的流程,一致预期均采用朝阳永续的数据库。

begT <- as.Date('2010-12-31')
endT <- as.Date('2017-08-31')
RebDates <- getRebDates(begT,endT,rebFreq = 'month')
indexID <- 'EI000985'
TS <- getTS(RebDates,indexID)
TSF <- gf.F_target_rtn(TS,con_type = "1,2")
TSF <- transform(TSF,stock_code=NULL)
TSFR <- getTSR(TSF)

一致预期目标涨幅因子部分数据如下表。

kable(sample_n(TSF,15),row.names = FALSE)

从上面表格中可以看到,一致预期目标涨幅因子数据存在一定的缺失,因子缺失比例如下图所示。

chart.Fct_NA(TSF)

一致预期目标涨幅因子得分部分时间段的分布直方图如下所示。

TSF_sample <- TSF[TSF$date %in% sample(RebDates,5),]
chart.Fct_hist(TSF_sample)

一致预期目标涨幅因子历史IC如下图。

chart.IC(TSFR)

一致预期目标涨幅因子历史分组收益率如下图。

chart.Ngroup.overall(TSFR)

一致预期目标涨幅因子历史分组收益率如下图。

chart.Ngroup.spread(TSFR)

合成大类因子

单因子的波动率较高,并且同一类型的单因子相关性较高,需要将同一类型的单因子合并为大类因子。下面以一致预期因子为例。

factorIDs <- c("F000010","F000011","F000008","F000015","F000013","F000004","F000009")
FactorLists <- buildFactorLists_lcfs(factorIDs,factorRefine = refinePar_default('scale'))
mTSF <- getMultiFactor(TS,FactorLists)
mTSFR <- getTSR(mTSF)
TSFRs <- mTSF2TSFs(mTSFR)

一致预期类单因子的IC如下图所示。

MF.chart.IC(mTSFR,facet_by = 'fname')

一致预期类单因子的分组多空收益如下图所示。

MF.chart.Ngroup.spread(mTSFR)

单因子合成为大类因子,支持多种合成方式。

#maximize IC' sharpe
MC.wgt.CAPM(TSFRs)
#minimize IC' volatility
MC.wgt.CAPM(TSFRs,targetType = 'risk')
#control single factor's exposure in combined factor
MC.wgt.CAPM(TSFRs,wgtmin = 0.05,wgtmax = 0.5)

#get group factor
forTSF <- gf.FORECAST(TS)
forTSFR <- getTSR(forTSF)

合成的预期类因子的IC如下图所示,IC的稳定性明显提升。

chart.IC(forTSFR)

合成的预期类因子的分组收益如下图所示,分组的单调性明显提升。

chart.Ngroup.overall(forTSFR)

合成的预期类因子的分组多空收益如下图所示。

chart.Ngroup.spread(forTSFR)

Build and update local database's regression result tables.

MF.chart.Fct_box(mTSF)
MF.chart.Fct_corr(mTSF)
MF.chart.Fct_density(TSF)


#dealing with factor correlation
TSF <- factor_orthogon_single(TSF,y='ILLIQ',x = 'ln_mkt_cap_',sectorAttr = NULL)
TSF <- factor_orthogon_single(TSF,y='volatility_',x = 'liquidity_',sectorAttr = NULL)
TSFR <- na.omit(getTSR(TSF))


# build local database's regression tables
system.time(lcdb.build.RegTables(FactorLists=FactorLists))

# update local database's regression tables
system.time(lcdb.update.RegTables(FactorLists = FactorLists))

多因子检验

# get regression result
reg_results <- reg.TSFR(TSFR)

## show regression result
# regression's rsquare plot
chart.reg.rsquare(reg_results)
# regression's rsquare table
table.reg.rsquare(reg_results)
# correlation plot of factor's return 
MC.chart.regCorr(reg_results)
# pure factor's wealth index
chart.reg.fRtnWealthIndex(reg_results,facet = T)
# barplot of pure factor's return 
chart.reg.fRtnBar(reg_results)
# summarise table of pure factor's return 
table.reg.fRtn(reg_results)

组合优化

RebDates <- getRebDates(as.Date('2014-01-31'),as.Date('2017-07-31'))
TS <- getTS(RebDates,indexID = 'EI000985')
tmp <- buildFactorLists(buildFactorList(factorFun = 'gf.NP_YOY',factorDir = 1,factorRefine = refinePar_default("scale")))
factorIDs <- c("F000006","F000008","F000013")
FactorLists <- buildFactorLists_lcfs(factorIDs,factorRefine = refinePar_default("scale"))
FactorLists <- c(tmp,FactorLists)
TSF <- getMultiFactor(TS,FactorLists)
TSFR <- getTSR(TSF)
re <- reg.TSFR(TSFR)
rtn_cov_delta <- f_rtn_cov_delta(reg_results=re)
fRtn <- rtn_cov_delta$fRtn
fCov <- rtn_cov_delta$fCov
constr <- constr_default(box_each = c(0,0.01))
constr <- addConstr_box(constr,ES33480000 = c(0,0.05),ES33490000 = c(0,0.03))
constr <- addConstr_group(constr,EI000300=c(0.8,0.95))
constr <- addConstr_fctExp_sector(constr,each = c(-0.05,0.05))
conslist <- buildFactorLists_lcfs("F000002",factorRefine = refinePar_default("scale"))
constr <- addConstr_fctExp_style(constr,conslist,-0.1,1)

#max return
port_opt4 <- getPort_opt(TSF,fRtn = fRtn,bmk="EI000300",constr = constr)

#max return minus risk
obj <- object_default()
obj <- addObj_risk(obj)
port_opt5 <- getPort_opt(TSF,fRtn = fRtn,fCov=fCov,bmk="EI000300",constr = constr,obj = obj)

# add turnover constraint
constr <- addConstr_turnover(constr,turnover_target = 0.25)
port_opt6 <- getPort_opt(TSF,fRtn = fRtn,fCov=fCov,bmk="EI000300",constr = constr,obj = obj)

# add trackingerror constraint
constr <- addConstr_trackingerror(constr)
delta <- rtn_cov_delta$Delta
port_opt7 <- getPort_opt(TSF,fRtn = fRtn,fCov=fCov,bmk="EI000300",constr = constr,obj = obj,delta=delta)




# port backtest and return summary
rtn1 <- port.backtest(port_opt4,fee.buy = 0.001)
rtn2 <- port.backtest(port_opt5,fee.buy = 0.001)
rtn3 <- port.backtest(port_opt6,fee.buy = 0.001)
rtn4 <- port.backtest(port_opt7,fee.buy = 0.001)
bmk <- getrtn.bmk(rtn1,bmk = 'EI000300')
rtn1 <- addrtn.hedge(rtn1,bmk)
rtn2 <- addrtn.hedge(rtn2,bmk)
rtn3 <- addrtn.hedge(rtn3,bmk)
rtn4 <- addrtn.hedge(rtn4,bmk)
allrtn <- merge(rtn1[,'hedge'],rtn2[,'hedge'])
allrtn <- merge(allrtn,rtn3[,'hedge'])
allrtn <- merge(allrtn,rtn4[,'hedge'])
ggplot.WealthIndex(allrtn)
rtn.summary(allrtn)
rtn.periods(allrtn)

traditional portfolio construction

#set modelPar
modelPar <- modelPar.default()
modelPar <- setmodelPar.time(modelPar,begT,endT)
modelPar <- setmodelPar.univ(modelPar,'EI000905')

#get factor wgt
factorIDs <- c("F000006","F000008","F000013","F000017")
tmp <- buildFactorLists_lcfs(factorIDs)
FactorLists <- buildFactorLists(
  buildFactorList(factorFun="gf.NP_YOY",
                  factorPar=list(),
                  factorDir=1),
    buildFactorList(factorFun="gf.ln_mkt_cap",
                  factorPar=list(),
                  factorDir=1))
FactorLists <- c(tmp,FactorLists)
MPs <- getMPs_FactorLists(FactorLists, modelPar)
TSFRs <- Model.TSFRs(MPs)
wgt <- MC.wgt.CAPM(TSFRs,wgtmin = 0.05,wgtmax = 0.3)

#get port and backtest
TS <- Model.TS(modelPar)
TSF2 <- getMultiFactor(TS,FactorLists = FactorLists,wgts = wgt)
port2 <- getPort(TSF2,topN = 100,pick.sectorNe = T)
port2 <- port2[,c('date','stockID')]
port2 <- addwgt2port(port2, wgt.sectorNe = T, wgtbmk = "EI000905")
re2 <- port.backtest(port2,fee.buy = 0.001)
benchrtn2 <- getrtn.bmk(re2, bmk = "EI000905")
allrtn2 <- addrtn.hedge(re2,benchrtn2)
allrtn2sum <- tables.longshort(allrtn2)
ggplot.WealthIndex(allrtn2)
rtn.summary(allrtn2)
rtn.periods(allrtn2)


raphael210/RFactorModel documentation built on May 26, 2019, 11:06 p.m.