原标题:【中金固收·量化】债市多因子探究——基于Python实践
长久以来,固收+的投资者往往将超额回报的重点放在权益和转债上——毕竟这两部分更容易得到差异化的结果。但前提是权益市场收益风险比高,尤其是可以更为灵活调整的转债,能提供一些“进可攻退可守”:显然这些条件不一定时刻满足。但毕竟即便是固收+投资者,债券的仓位也相对更重。此时我们不妨也着眼于纯债本身的因子回报,这里我们进行了一系列尝试。
报告逻辑示意图
资料来源:中金公司研究部
显然,相比于股票、转债而言,债券数据的标准化程度不高、因子的说服力也可能相对弱。但我们的目标并不太高,我们希望因子模型能够帮助我们:
1)更定量化地理解市场超额回报的来源,并能帮我们也更好刻画相关产品,如普通债基;
2)在此基础上观察是否有可行的因子策略。
一、基于指数表现的因子遴选
虽然个券数据与股票相比标准性欠佳,但借助债券市场丰富的指数体系,我们可以比较简单直观地观察到债券市场的因子特征
。我们将2017年以来93组中债净价指数的周度收益率进行聚类计算。聚类图除了能直观展现各指数的相关性,还能依据其相关性进行多层分类。从结果来看:
1、
期限、信用和流动性
是较显著的因子,如下聚类图依据此也做了各级分类;
2、期限因子的重要性较高,在关键期限如1、5、7年,都对指数的回报有明显影响;
图表1:中债各净价指数聚类图
资料来源:万得资讯,中金公司研究部
3、信用因子相较期限因子影响并没有那么大,
信用债与利率债整体上会有一定差异,同时利率债内部金融债和国债(以及地方债)有明显区分;
而信用债指数内部,评级的影响存疑;
4、流动性因子,相对影响微弱,实用性一般。
聚类图中,农发与口行债指数往往在最后还是会与国开债指数被区分开。
图表2:各期限净价曲线(左)与金融债换手率(右)
资料来源:万得资讯,中金公司研究部
二、因子编写的具体方式
不难看出期限、信用的影响力较强,同时,我们还加入动量因子。
在这个基础框架下,参照Fama-French-Carhart四因子的构建方式,以期限、信用和动量作为非市场因子,构建一个债市多因子模型。
1、期限因子LMS(LongMinusShort):我们参照
平均待偿期(年)
。我们先将长期限各评级加总的收益率,与短期限各评级加总的收益率相减得到【期限和信用的交叉项】;再将长期限各动量加总的收益率,与短期限各动量加总的收益率相减得到【期限和动量的交叉项】,最后将两个交叉项平均值认定为期限因子。
2、信用因子GMP(GoodMinusPoor):我们直接参照平均派息率(%)而非隐含评级,以此能够区分利率债和信用债的情况,具体算法与期限类似。
3、动量因子HMW(HighMinusWeek):我们参照指数前一个月的涨跌幅作为的动量划分。
此外,对于因子的计算,我们标的为
中债各财富指数
,并采用
指数总市值加权
。
具体计算逻辑如下:
图表3:债市因子构建方式(示意图)
资料来源:中金公司研究部
图表4:债市因子构建方式(程序示意图)
def
computerBondFactor
(obj, startDate, momwindow=
20
, window=
20
)
:
# 储存固定周期的涨跌幅数据并计算动量,以及后续我们因子构建是按照市值加权的
startDate = pd.to_datetime(startDate).strftime(
'%Y/%#m/%#d'
)
ret = obj.DB[
'CLOSE'
].pct_change(window).loc[startDate::window]
wgt = obj.DB[
'AMT'
].loc[startDate::window]
obj.DB[
'1Mmom'
] = obj.DB[
'CLOSE'
].pct_change(momwindow).shift(window +
1
)
dictRawdf = {
'ptm'
: {
'dfRank'
: obj.DB[
'MATURITY'
].loc[startDate::window].rank(pct=
True
, axis=
1
),
'mat'
: [
None
,
None
,
None
]},
'credit'
: {
'dfRank'
: obj.DB[
'DIVIDEND'
].loc[startDate::window].rank(pct=
True
, axis=
1
),
'mat'
: [
None
,
None
,
None
]},
'mom'
: {
'dfRank'
: obj.DB[
'1Mmom'
].loc[startDate::window].rank(pct=
True
, axis=
1
),
'mat'
: [
None
,
None
,
None
]}}
# 将每个周期依照期限、信用和动量进行三分(以30%与70%为界)
for
k, v
in
dictRawdf.items:
dfRaw = v[
'dfRank'
]
v[
'mat'
][
0
] = dfRaw.applymap(
lambda
x:
1
if
x >
0.7
else
np.nan)
v[
'mat'
][
1
] = dfRaw.applymap(
lambda
x:
1
if
(x <=
0.7
) & (x >=
0.3
)
else
np.nan)
v[
'mat'
][
2
] = dfRaw.applymap(
lambda
x:
1
if
x <
0.3
else
np.nan)
dictFactors = {
'LMS'
: {
'keydf'
:
'ptm'
,
'comdf'
: [
'credit'
,
'mom'
],
'values'
:
None
},
'GMP'
: {
'keydf'
:
'credit'
,
'comdf'
: [
'ptm'
,
'mom'
],
'values'
:
None
},
'HMW'
: {
'keydf'
:
'mom'
,
'comdf'
: [
'ptm'
,
'credit'
],
'values'
:
None
}}
# 依据类似Carhart四因子方式构建期限、信用和动量三大因子(市值加权计算因子)
for
k, v
in
dictFactors.items:
factorValue =
None
for
num, com
in
enumerate(v[
'comdf'
]):
pctDiff =
None
for
i
in
[
0
,
2
]:
pct =
None
for
j
in
[
0
,
1
,
2
]:
mat = dictRawdf[v[
'keydf'
]][
'mat'
][i] * dictRawdf[com][
'mat'
][j]
pctwgtMean = (ret * mat * wgt).sum(axis=
1
) / (wgt * mat).sum(axis=
1
)
pct = pctwgtMean
if
j ==
0
else
pct + pctwgtMean
pct.fillna(
0
, inplace=
True
)
pctDiff = pct
if
i ==
0
else
pctDiff - pct
pctDiff.fillna(
0
, inplace=
True
)
factorValue = pctDiff
if
num ==
0
else
factorValue + pctDiff
v[
'values'
] = factorValue /
6.
dfRet = pd.DataFrame(columns=dictFactors.keys)
for
k
in
dfRet.columns:
dfRet[k] = dictFactors[k][
'values'
]
dfRet.index = [pd.to_datetime(d)
for
d
in
dfRet.index]
return
dfRet
资料来源:万得资讯,中金公司研究部
依据2010年以来的因子收益情况,我们观察到
1)
期限因子是存在一定周期性的,
信用因子长期暴露下优势相对有限,
而动量因子暴露优势比较显著;
2)月度来看信用因子与期限因子存在一定正相关。
而无论周度还是月度,动量因子整体与期限/信用因子存在一定负相关。
图表5:债市各主要因子收益率
资料来源:万得资讯,中金公司研究部;注:数据区间为2009年12月30日至2022年5月18日
图表6:债市各主要因子相关性情况
资料来源:万得资讯,中金公司研究部;注:数据区间为2009年12月30日至2022年5月18日
面对目前已有的因子数据,我们以下将进行两方面的探索:
1)依据债市多因子,我们可以对债基进行风险归因,并以周度或月度的频率,关注债基的行为与丰富对其的评价维度;
2)对于各因子再进行探究,挖掘因子增强的量化策略。
三、基于债市多因子的债基评价
模仿Carhart模型,我们搭建以下债市四因子模型:
其中,我们使用
中债-新综合财富(总值)指数(CBA00101)的收益率,相较于一年期存款利率的超额收益,来构建市场因子。
依据模型,我们对市场中几个典型的纯债产品(简称中不含“信用”),自2016年以来的月度收益,进行了风险拆解。我们观察到
1)模型对于各基金解释能力普遍较强,R-Squared基本维持到85%及以上;
2)债基在alpha层面不太明显;
3)市场因子对基金业绩解释能力较强,beta值能一定程度体现债基对纯债资产的风险暴露水平,基本与杠杆有一定挂钩;
4)债基在期限因子层面暴露相对有限,p-value呈现出来的显著值并不高。此外,基金平均而言,有做陡曲线的倾向。
5)信用因子解释力度较强,beta值均为正;而动量因子的稳定暴露较难,样本中仅有一只产品动量暴露偏显著,其收益率是全样本中最高的。
图表7:纯债基月度收益风险拆解
资料来源:万得资讯,中金公司研究部;注:样本债基选取2016年以来综合规模排名处于前列的中长期纯债基;测算周期为2016年1月4日至2022年5月18日
图表8:纯债基月度滚动(24个月)收益风险拆解
资料来源:万得资讯,中金公司研究部;注:市场/信用beta剔除当期p-value小于2%的例
而动态来看,模型整体解释力度仍不弱,此外我们观察到1)市场beta近年有所走弱;2)信用beta也处于趋缓的节奏,而且产品间差距比较大。
四、有关债市多因子量化策略的探究
以上我们主要就多因子在债基评价方面进行定量分析。而再回顾我们所拆解的多因子收益情况,实际上
若对于个别因子能做好一定程度的择时,那么对于固收产品而言或许会有显著增强效果。
这也是我们开篇所提到的——我们希望在债市因子层面做不同程度的暴露,以此达到另一种维度的“固收+”。以下,我们就期限、信用和动量因子的增强暴露策略做一定的尝试。
1、期限择时策略:
我们将“10年与隔夜利率差”作为基准标量,当其滚动40日均值显著低于滚动120日线,则买入短期限指数;若短均线显著高于长均线,则买入长期限指数。经过测算,策略在收益端的增厚较为显著,2012年迄今年化回报在5.16%(综合指数4.58%,加权平均综合指数4.57%),同时
在子类中,该期限策略仍具备显著增强效果。
图表9:期限策略对组合的增强效果
资料来源:万得资讯,中金公司研究部;注:以上回测结果测算周期为2011年12月29日至2022年5月18日;
期限切换与各平均策略以指数样本券10日结算量加权
;换仓周期为40日
具体操作上,我们短均线使用40日平均,长均线使用120日平均,显著与否参照的是0.5倍120日标准差。
图表10:期限策略的代码实现
def
maturityStrategySimple
(obj, codes, date, tempCodes, dfAssetBook)
:
# 计算10Y与隔夜利差
srs = (obj.DB[
'TermStructure'
][
10
] - obj.DB[
'TermStructure'
][
0
]).loc[:date]
srsShort = srs.rolling(
40
).mean.iloc[
-1
]
srsLong = srs.rolling(
120
).mean.iloc[
-1
]
srsLongstd = srs.rolling(
120
).std.iloc[
-1
]
tempCodes = obj.DB[
'MATURITY'
].columns
srsMat = obj.DB[
'MATURITY'
].loc[date, tempCodes].dropna
# 短均线显著低于长均线,则买入短久期指数,反之则买入长久期指数
if
srsShort <= srsLong - srsLongstd *
0.5
:
t = srsMat[srsMat < srsMat.quantile(
0.3
)].index
elif
srsShort >= srsLong + srsLongstd *
0.5
:
t = srsMat[srsMat > srsMat.quantile(
0.3
)].index
else
:
t = tempCodes
return
t
资料来源:中金公司研究部
2、动量因子控制策略:
对于动量因子而言,结果与我们此前报告中提及的“大级别趋势必惩、小趋势顺势可为”基本一致。因此我们在对债市做因子选择时,从进攻性上仍然偏好短期动量,而回撤端我们则考虑市场当前交易量是否处于历史相对高位。
图表11:动量策略的有效性
资料来源:万得资讯,中金公司研究部;注:2012年以来策略区间为2011年12月29日至2022年5月18日;2018年以来策略区间为2017年12月29日至2022年5月18日;策略均为21天换仓,均以各财富指数的市值加权处理
图表12:动量策略的评价结果
资料来源:万得资讯,中金公司研究部;注:2012年以来策略区间为2011年12月29日至2022年5月18日;2018年以来策略区间为2017年12月29日至2022年5月18日;策略均为21天换仓,均以各财富指数的市值加权处理
具体操作上,我们先选择动量处于前1/3的指数,在这个基础上剔除交易量处于250个交易日80%分位数及以上的。
图表13:动量控制策略的程序实现
def
momStrategyMax
(obj, codes, date, tempCodes, dfAssetBook)
:
date = offset(obj, date)
idx = obj.DB[
'CLOSE'
].index.get_loc(date)
srs = obj.DB[
'CLOSE'
].iloc[idx -
21
:idx
][tempCodes].pct_change(
20
).iloc[-
1
].rank
t = srs[srs > srs.quantile(
0
.
333
)].index
srsVol = obj.DB[
'VOL'
].iloc[idx -
251
: idx][t].rank(axis=
0
).iloc[-
1
] /
252
.
t = srsVol[srsVol <
0
.
8
].index
return
t
资料来源:中金公司研究部
3、信用因子:
在经过期限因子与动量因子调整后,
同等条件下
做多高票息的策略或许是有效的。因此我们在编制信用因子相关策略时,会先基于期限因子的选择,再在其中选择高票息的,最后选剩余指数中具备动量优势的。
图表14:高票息策略的有效尝试
资料来源:万得资讯,中金公司研究部;注:上图中年化回报/波动/最大回撤单位均为%,2012年以来策略区间为2011年12月29日至2022年5月18日;2018年以来策略区间为2017年12月29日至2022年5月18日;策略均为21天换仓,均以各财富指数的市值加权处理;中债信用债指数中期限最长,隐含评级最低的中债-市场隐含评级AA信用债财富(10年以上)指数,2018年以来年化回报6.43%,Calmar为4.94x;2016年8月成立以来年化回报4.34%,Calmar为0.33x。
图表15:高票息策略的程序实现
def
creditStrategy
(obj, codes, date, tempCodes, dfAssetBook)
:
tempCodes = maturityStrategySimple(obj, codes, date, tempCodes, dfAssetBook)
date = offset(obj, date)
srs = obj.DB[
'DIVIDEND'
].loc[date, tempCodes].dropna
t = srs[srs > srs.quantile(
0.5
)].index
return
momStrategyMax(obj, codes, date, t, dfAssetBook)
资料来源:中金公司研究部
五、利用债市多因子构建的组合
以上我们所作的因子增强策略,均是以各财富指数为标的。而落实到实务层面,大部分纯债债券是没法像转债一样有标准的结构数据,以此直接做量化策略。同时个券流动性偏弱,所以个券做量化策略的效果可能也并不理想。
因此对于纯债投资者,或许可以参照以上因子增强策略在久期、信用层面的选择,落到个券上再有动量考虑;而对于能投债基的投资者,例如FOF、保险、理财等,可以找相应的指数债基操作,也可以依据因子增强策略的选择,选择在某因子上有稳定暴露的产品。以下,我们梳理在信用与动量层面有稳定暴露的纯债基产品。
图表16:信用因子暴露稳定的债基
资料来源:万得资讯,中金公司研究部
图表17:动量因子暴露相对稳定的债基
资料来源:万得资讯,中金公司研究部
因子出现较大变动,货币政策出现较大转向,信用债出现超预期风险
本文摘自:2022年5月27日已经发布的《债市多因子探究——基于Python实践
》
向上滑动参见完整法律声明及二维码
返回搜狐,查看更多
责任编辑:
声明:该文观点仅代表作者本人,搜狐号系信息发布平台,搜狐仅提供信息存储空间服务。
发布于:
山西省