200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > 【基金量化研究系列】大类资产配置研究(二)——股债二八轮动策略

【基金量化研究系列】大类资产配置研究(二)——股债二八轮动策略

时间:2023-12-26 03:03:00

相关推荐

【基金量化研究系列】大类资产配置研究(二)——股债二八轮动策略

文章目录

1. 引言2. 股债二八轮动策略3. 动态再平衡股债二八轮动策略4. 基于python的策略实现4.1 策略代码4.2. 运行结果实证分析5. 总结写在最后

1. 引言

在上一篇文章中,我们研究了股债二八策略和股债风险平价策略。(详情请见:【基金量化研究系列】大类资产配置研究(一)——股债二八配置策略与股债风险平价策略)在这篇文章中,我们仍以“易方达沪深300ETF(510310)”与“国泰上证5年国债ETF(511010)”作为股票市场与债券市场的基准可投标的,来引入一种新的策略——股债二八轮动策略

本文仍延续前文的基本假设,规定:

(1)市场中不允许融资做多与融券做空;

(2)建仓调仓过程中不允许借款、参与国债回购;

(3)每日仅在收盘时间以收盘价格进行交易;

(4)未特别规定,忽略调、建仓手续费。

2. 股债二八轮动策略

所谓股债二八轮动策略,顾名思义,就是股票和债券“换着”配以20%和80%的仓位,而对仓位进行调节的“转换信号”就是基于“价格动量”指标。

策略如下:以前m个交易日作为窗口期,若沪深300ETF在窗口期中的收益率高于国债ETF对应的收益率,则认为在股票市场相比于债券市场有更强的上升趋势,并在当日收盘时将沪深300ETF的仓位调整为80%,并将国债ETF的仓位调整为20%,以博取更高收益;反之,若沪深300ETF在窗口期中的收益率高于国债ETF对应的收益率,则认为股市走弱,并在当日收盘时将沪深300ETF的仓位调整为20%,并将国债ETF的仓位调整为80%,以规避风险。

策略的伪代码如下:

Step 0初始化参数:规定调仓频率(以日频为例),并规定回看窗口期长度为m(即m个单位的调仓周期),规定t= 0;

Step 1在t个交易周期,计算股票和债券的窗口期累计收益率Rs(t) 与RB(t):

RS(t)=∏k=t−mt−1[1+rS(k)]−1=PS(t−1)PS(t−m)−1R_S(t) = \prod_{k = t-m}^{t-1} [1+r_S(k)] -1 = \frac{P_S(t-1)}{P_S(t-m)} - 1 RS​(t)=k=t−m∏t−1​[1+rS​(k)]−1=PS​(t−m)PS​(t−1)​−1RB(t)=∏k=t−mt−1[1+rB(k)]−1=PB(t−1)PB(t−m)−1R_B(t) = \prod_{k = t-m}^{t-1} [1+r_B(k)] -1 = \frac{P_B(t-1)}{P_B(t-m)} - 1 RB​(t)=k=t−m∏t−1​[1+rB​(k)]−1=PB​(t−m)PB​(t−1)​−1

其中:

·rS(t) 为股票在第t个子周期内收益率;

·rB(t) 为债券在第t个子周期内收益率;

·PS(t) 为股票在第t个子周期收盘价格;

·PB(t) 为债券在第t个子周期收盘价格。

Step 2比较Rs 与RB 的大小。若Rs >RB,则规定ωS(t) = 0.8,ωB(t) = 0.2;若Rs ≤RB,则规定ωS(t) = 0.2,ωB(t) = 0.8;

Step 3令t=t+ 1,重复Step 1直至回测结束。

实现的python代码请见第四章。

我们不难发现,这一“轮动策略”的思想实际上就是希望利用股票市场中的“动量效应(Momentum Effect)”,在股票市场走牛的时候获取更高的收益,并且在走熊的时候及时止损

3. 动态再平衡股债二八轮动策略

股债二八轮动策略跟上一篇文章中的股债二八策略一样有一个缺陷,就是这个“二八”配置比例是基于欧美市场的实证经验而得来的,直接套用中国市场仍然有一种“拍脑门”的嫌疑。因此,我们需要一款更适应于A股市场情况的配置比例。

其中一种想法是:我们可以在保留“动量效应”的基础上加入“风险平价”配置比例,即:

ωS(t)={σS(t)σS(t)+σB(t)ifRS(t)>RB(t)σB(t)σS(t)+σB(t)ifRS(t)≤RB(t)\omega_S(t) = \begin{cases} \frac{\sigma_S(t)}{\sigma_S(t) + \sigma_B(t)} &\text{if } R_S(t) > R_B(t) \\ \frac{\sigma_B(t)}{\sigma_S(t) + \sigma_B(t)} &\text{if } R_S(t) ≤ R_B(t) \end{cases} ωS​(t)={σS​(t)+σB​(t)σS​(t)​σS​(t)+σB​(t)σB​(t)​​ifRS​(t)>RB​(t)ifRS​(t)≤RB​(t)​ωB(t)=1−ωS(t)\omega_B(t) = 1 - \omega_S(t) ωB​(t)=1−ωS​(t)

利用上述公式代替传统股债二八轮动策略中计算权重的方式,即可得到“升级版”模型——动态再平衡股债二八轮动策略

:该策略为笔者原创策略。

4. 基于python的策略实现

4.1 策略代码

话不多说,让我们上码跑一跑,看看各种策略的表现如何吧!

# -*- coding: utf-8 -*-# author: Mikey_Sun time: 5/15/# all copyright belongs to the author. NO COPY ALLOWED.from EmQuantAPI import * #使用chioce数据库。详细使用说明请查阅百度import numpy as npimport pandas as pdimport matplotlib.pyplot as plt# Module 1: 下载数据,并存储到本地def download_data_from_choice():loginresult = c.start()codes = "510310.SH,511010.SH" # 所需数据的代码。510310为沪深300ETF,511010为五年国债ETFindicators = "open,high,low,close" # 需要下载的数据指标startdate = "0101" # 回测起始时间,可自行修改enddate = "" # 回测结束时间,可自行修改data = c.csd(codes=codes, indicators=indicators, startdate=startdate, enddate=enddate,options=("Ispandas,1")) # 导入数据,以pd.DataFrame类型格式存储path = '你数据的存储地址' # 将数据保存到你的本地地址(需自行修改)data.to_excel(path, index=True, header=True)download_data_from_choice() #下载数据path = '你数据的存储地址'data = pd.read_excel(path) #读取数据data.set_index(data["DATES"], inplace=True) #设置数据索引为交易日HS300ETF = pd.DataFrame(data[data["CODES"] == '510310.SH']["CLOSE"].astype(float)) #沪深300ETF专属数据结构。仅保留收盘价格GZ5yETF = pd.DataFrame(data[data["CODES"] == '511010.SH']["CLOSE"].astype(float)) #国债ETF专属数据结构。仅保留收盘价格td_dates = HS300ETF.index #记录交易日信息,方便以后进行查找n = len(td_dates)# Module2: 计算收益率pd.set_option('mode.chained_assignment', None)# 创建收益率序列HS300ETF['RETURN'] = 0 #创建收益率序列GZ5yETF['RETURN'] = 0 #创建收益率序列HS300ETF['RETURN'].astype(float)#设定格式为浮点GZ5yETF['RETURN'].astype(float)#设定格式为浮点# 计算收益率HS300ETF["RETURN"][td_dates[1:]] = np.array(HS300ETF["CLOSE"][td_dates[1:]]) / np.array(HS300ETF["CLOSE"][td_dates[:-1]]) - 1 #计算HS300ETF日收益率GZ5yETF["RETURN"][td_dates[1:]] = np.array(GZ5yETF["CLOSE"][td_dates[1:]]) / np.array(GZ5yETF["CLOSE"][td_dates[:-1]]) - 1 #计算GZ5yETF日收益率# 将收益率序列单独存储至returnsreturns = pd.DataFrame({'510310.SH':HS300ETF["RETURN"], '511010.SH':GZ5yETF["RETURN"]},index= td_dates)#print(returns.head()) #打印表头查看# Module 3: 纯股与纯债策略nv_HS300ETF = [1] #记录全仓股票策略净值nv_GZ5yETF = [1] #记录全仓债券策略净值r_HS300ETF = [] #记录全仓股票策略收益率r_GZ5yETF = [] #记录全仓债券策略收益率for i in range(n):nv_HS300ETF.append( nv_HS300ETF[i] *(1 + returns['510310.SH'][td_dates[i]]))nv_GZ5yETF.append( nv_GZ5yETF[i] *(1 + returns['511010.SH'][td_dates[i]]))r_HS300ETF.append(returns['510310.SH'][td_dates[i]])r_GZ5yETF.append(returns['511010.SH'][td_dates[i]])# Module 4: 计算窗口期收益率与波动率函数# 定义计算移动平均波动率函数:def Sigma_MA(t, return_series, type):"""t: 回溯窗口长度return_series: 收益率序列type: 输出序列格式。支持list格式与pd.DataFrame格式"""td_dates = return_series.indexreturn_seires = list(return_series)n = len(return_series)sigma_series = []for i in range(t, n):sigma_series.append(np.std(return_series[i-t:i]))if type == "list":return sigma_serieselif type == "DataFrame":return pd.DataFrame({"sigma_series":sigma_series}, index = td_dates[t:n])else:return "Type Input Error!"def Momentum_MA(t, return_series, type):"""t: 回溯窗口长度return_series: 收益率序列type: 输出序列格式。支持list格式与pd.DataFrame格式"""td_dates = return_series.indexreturn_seires = list(return_series)n = len(return_series)momentum_series = []for i in range(t, n):momentum = 1for j in range(i-t, i):momentum *= 1 + return_series[td_dates[j]]momentum_series.append(momentum)if type == "list":return momentum_serieselif type == "DataFrame":return pd.DataFrame({"momentum_series":momentum_series}, index = td_dates[t:n])else:return "Type Input Error!"# Module 5: 计算策略净值与日收益率t = 20 #定义窗口期长度# Step 1: 计算动量序列与波动率序列:momentum_seires_HS300ETF = Momentum_MA(t = t, return_series = returns['510310.SH'], type = "DataFrame")['momentum_series']momentum_seires_GZ5yETF = Momentum_MA(t = t, return_series = returns['511010.SH'], type = "DataFrame")['momentum_series']sigma_seires_HS300ETF = Sigma_MA(t = t, return_series = returns['510310.SH'], type = "DataFrame")['sigma_series']sigma_seires_GZ5yETF = Sigma_MA(t = t, return_series = returns['511010.SH'], type = "DataFrame")['sigma_series']# Sstep 2: 计算各策略收益率与净值序列:nv_strategy_momentum = [1] # 记录股票动量策略净值nv_strategy_2080 = [1] # 记录股债二八策略净值nv_strategy_28rotate = [1] # 记录股债二八轮动策略净值nv_strategy_28rotate_rebalance = [1] # 记录动态再平衡股债二八轮动策略净值r_strategy_momentum = [] # 记录股票动量策略收益率r_strategy_28rotate = [] # 记录股债二八策略收益率r_strategy_2080 = [] # 记录股债二八轮动策略收益率r_strategy_28rotate_rebalance = [] # 记录动态再平衡股债二八轮动策略收益率for i in range(n):nv_strategy_2080.append(nv_strategy_2080[i] * (1 + 0.2 * returns['510310.SH'][td_dates[i]] + 0.8 * returns['511010.SH'][td_dates[i]]))r_strategy_2080.append(0.2 * returns['510310.SH'][td_dates[i]] + 0.8 * returns['511010.SH'][td_dates[i]])# 由于这一策略对样本有损耗,因此需要单独计算if td_dates[i] in momentum_seires_HS300ETF.index:# 模型1:股债28轮动模型# 计算权重if momentum_seires_HS300ETF.loc[td_dates[i]] > momentum_seires_GZ5yETF.loc[td_dates[i]]:w_bond_daily = 0.2w_stock_daily = 1 - w_bond_dailyelse:w_bond_daily = 0.8w_stock_daily = 1 - w_bond_daily# 计算净值nv_strategy_28rotate.append(nv_strategy_28rotate[i] * ( 1 + w_stock_daily * returns['510310.SH'][td_dates[i]] + w_bond_daily * returns['511010.SH'][td_dates[i]]))r_strategy_28rotate.append(w_stock_daily * returns['510310.SH'][td_dates[i]] + w_bond_daily * returns['511010.SH'][td_dates[i]])# 模型2:股票纯动量模型if momentum_seires_HS300ETF.loc[td_dates[i]] > 0:nv_strategy_momentum.append(nv_strategy_momentum[i]* (1 + returns['510310.SH'][td_dates[i]] ))r_strategy_momentum.append( returns['510310.SH'][td_dates[i]] )else:nv_strategy_momentum.append(nv_strategy_momentum[i] * (1 + returns['511010.SH'][td_dates[i]]))r_strategy_momentum.append(returns['511010.SH'][td_dates[i]])# 模型3:组合策略# 计算权重if momentum_seires_HS300ETF.loc[td_dates[i]] > momentum_seires_GZ5yETF.loc[td_dates[i]]:w_stock_daily = sigma_seires_HS300ETF.loc[td_dates[i]] / (sigma_seires_HS300ETF.loc[td_dates[i]] + sigma_seires_GZ5yETF.loc[td_dates[i]])w_bond_daily = 1 - w_bond_dailyelse:w_bond_daily = sigma_seires_HS300ETF.loc[td_dates[i]] / (sigma_seires_HS300ETF.loc[td_dates[i]] + sigma_seires_GZ5yETF.loc[td_dates[i]])w_stock_daily = 1 - w_bond_daily# 计算净值nv_strategy_28rotate_rebalance.append(nv_strategy_28rotate_rebalance[i] * (1 + w_stock_daily * returns['510310.SH'][td_dates[i]] + w_bond_daily * returns['511010.SH'][td_dates[i]]))r_strategy_28rotate_rebalance.append(w_stock_daily * returns['510310.SH'][td_dates[i]] + w_bond_daily * returns['511010.SH'][td_dates[i]])else:nv_strategy_28rotate.append(nv_strategy_28rotate[i])r_strategy_28rotate.append(0)nv_strategy_momentum.append(nv_strategy_momentum[i])r_strategy_momentum.append(0)v_strategy_28rotate_rebalance.append(nv_strategy_28rotate_rebalance[i])r_strategy_28rotate_rebalance.append(0)# Step 3: 计算各策略日波动率sigmas = []sigmas.append(np.std(r_HS300ETF[t:n-t]))sigmas.append(np.std(r_GZ5yETF[t:n-t]))sigmas.append(np.std(r_strategy_momentum[t:n-t]))sigmas.append(np.std(r_strategy_2080[t:n-t]))sigmas.append(np.std(r_strategy_28rotate[t:n-t]))sigmas.append(np.std(r_strategy_28rotate_rebalance[t:n-t]))# Step 4: 计算各策略日收益率mean_returns = []mean_returns.append(np.mean(r_HS300ETF[t:n-t]))mean_returns.append(np.mean(r_GZ5yETF[t:n-t]))mean_returns.append(np.mean(r_strategy_momentum[t:n-t]))mean_returns.append(np.mean(r_strategy_2080[t:n-t]))mean_returns.append(np.mean(r_strategy_28rotate[t:n-t]))mean_returns.append(np.mean(r_strategy_28rotate_rebalance[t:n-t]))# Step 5: 计算各策略日夏普比率sharpe_ratios = []for i in range(len(sigmas)):sharpe_ratios.append(mean_returns[i] / sigmas[i])# Step 6: 打印结果,并绘制净值走势图outcome = pd.DataFrame({'mean_returns': mean_returns, 'sigmas': sigmas, 'sharpe_ratios': sharpe_ratios}, index = ['纯股','纯债','动量' ,'股债二八','二八轮动','平价轮动'])print(outcome)plt.plot(nv_HS300ETF[t:n], label = "nv_HS300ETF", color = "black")plt.plot(nv_GZ5yETF[t:n], label = "nv_GZ5yETF", color = "red")plt.plot(nv_strategy_2080[t:n], label = "nv_strategy_2080", color = "blue")plt.plot(nv_strategy_momentum[t:n], label="nv_strategy_momentum", color="purple")plt.plot(nv_strategy_28rotate[t:n], label = "nv_strategy_28rotate", color = "green")plt.plot(nv_strategy_28rotate_rebalance[t:n], label = "nv_strategy_28rotate", color = "grey")plt.show()

运行结果如下:

mean_returns sigmas sharpe_ratios纯股 0.000281 0.016301 0.017224纯债 0.000133 0.001754 0.076070动量 0.000281 0.016301 0.017224股债二八0.000163 0.003378 0.048229二八轮动0.000386 0.007622 0.050675平价轮动0.000475 0.008058 0.058903Process finished with exit code 0

图1 1月30日至5月11日各策略净值走势对比图(以1月29日为基日,定义净值为1。黑线为全股策略,红线为全债策略,紫线为股票动量策略,蓝线为股债二八策略,绿线为股债二八轮动策略,灰线为动态再平衡股债二八轮动策略)

4.2. 运行结果实证分析

从输出结果可以看出,相比于一般的股债二八模型和股债二八轮动模型,动态再平衡股债轮动模型有用最高的累计收益率:五年累计收益率达到80%(年化12.47%),远超纯股与纯债策略。同时,该策略亦拥有更高的日收益率和收益-风险比率。相比于纯股策略而言,其具有更高的收益水平和更低的波动率,因此是替代纯股策略的一个十分优秀的策略。

然而,通过净值走势图(图1)可以发现,该策略大部分收益是在股票大牛市的时候()获得的,在熊市阶段收益几乎腰斩,而在震荡市之中轮动策略并没有明显跑赢纯债策略和纯股策略。同时,轮动策略也会出现较长时间和较大幅度的回撤,对于一般的中小投资者很可能是无法容忍的。

此外,由于在回测过程中忽略了交易成本,因此动态再平衡策略相比于非动态调仓策略而言需要花费更多的手续费,在计算手续费的基础上动态再平衡策略很可能并没有显著的优势。

5. 总结

至此,在仅考虑股票和债券两类资产的前提下,我们已经介绍了:

股债二八策略股债风险平价策略动态再平衡股债风险平价策略股债二八轮动策略动态再平衡股债二八轮动策略

在上述策略中,风险平价策略可以理解为纯债策略的增厚,而轮动策略可以理解为纯股策略的增厚。

在后面的研究中,我们将加入更多类别的资产,从而进一步体验资产配置对风险对冲于收益增厚的重要作用吧!

写在最后

若想查阅本系列全部文章,请参见目录页:系列文章目录索引。

欢迎感兴趣的小伙伴来跟作者一起挑刺儿~ 包括但不限于语言上的、排版上的和内容上的不足和疏漏~ 一起进步呀!

有任何问题,欢迎在本文下方留言,或者将问题发送至勘误邮箱: mikeysun_bugfix@

谢谢大家!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。