【基金量化研究系列】大类资产配置研究(二)——股债二八轮动策略
文章目录
- 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)if RS(t)>RB(t)σB(t)σS(t)+σB(t)if RS(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)if RS(t)>RB(t)if RS(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/2020
# all copyright belongs to the author. NO COPY ALLOWED.from EmQuantAPI import * #使用chioce数据库。详细使用说明请查阅百度
import numpy as np
import pandas as pd
import 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 = "20150101" # 回测起始时间,可自行修改enddate = "20200511" # 回测结束时间,可自行修改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日收益率# 将收益率序列单独存储至returns
returns = 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 2015年1月30日至2020年5月11日各策略净值走势对比图(以2015年1月29日为基日,定义净值为1。黑线为全股策略,红线为全债策略,紫线为股票动量策略,蓝线为股债二八策略,绿线为股债二八轮动策略,灰线为动态再平衡股债二八轮动策略)
4.2. 运行结果实证分析
从输出结果可以看出,相比于一般的股债二八模型和股债二八轮动模型,动态再平衡股债轮动模型有用最高的累计收益率:五年累计收益率达到80%(年化12.47%),远超纯股与纯债策略。同时,该策略亦拥有更高的日收益率和收益-风险比率。相比于纯股策略而言,其具有更高的收益水平和更低的波动率,因此是替代纯股策略的一个十分优秀的策略。
然而,通过净值走势图(图1)可以发现,该策略大部分收益是在股票大牛市的时候(2015年)获得的,在熊市阶段收益几乎腰斩,而在震荡市之中轮动策略并没有明显跑赢纯债策略和纯股策略。同时,轮动策略也会出现较长时间和较大幅度的回撤,对于一般的中小投资者很可能是无法容忍的。
此外,由于在回测过程中忽略了交易成本,因此动态再平衡策略相比于非动态调仓策略而言需要花费更多的手续费,在计算手续费的基础上动态再平衡策略很可能并没有显著的优势。
5. 总结
至此,在仅考虑股票和债券两类资产的前提下,我们已经介绍了:
- 股债二八策略
- 股债风险平价策略
- 动态再平衡股债风险平价策略
- 股债二八轮动策略
- 动态再平衡股债二八轮动策略
在上述策略中,风险平价策略可以理解为纯债策略的增厚,而轮动策略可以理解为纯股策略的增厚。
在后面的研究中,我们将加入更多类别的资产,从而进一步体验资产配置对风险对冲于收益增厚的重要作用吧!
写在最后
若想查阅本系列全部文章,请参见目录页:系列文章目录索引。
欢迎感兴趣的小伙伴来跟作者一起挑刺儿~ 包括但不限于语言上的、排版上的和内容上的不足和疏漏~ 一起进步呀!
有任何问题,欢迎在本文下方留言,或者将问题发送至勘误邮箱: mikeysun_bugfix@163.com
谢谢大家!
【基金量化研究系列】大类资产配置研究(二)——股债二八轮动策略相关推荐
- (10)大类资产配置一升级版股债平衡
稳定获得高收益的秘密 正确答案是B 负相关性资产的组合更能获得稳定的收益. 稳定获得高收益的秘密 市场上的资金量是一定的,股票市场和债券市场通常是此消彼长的状态. 如何才能实现不同比例的资产配置? 5 ...
- 【基金量化研究系列】大类资产配置研究(一)——股债二八配置策略与股债风险平价策略
文章目录 1. 引言 1.1 资产配置简介 1.2 可投标的说明 1.3 市场基本情况与数据库使用的说明 1.4 本文策略基本假设 2. 资产配置策略一--股债二八策略 2.1 策略简介 2.2 基于 ...
- AI大类资产配置:从风险平价开始
原创文章第84篇,专注"个人成长与财富自由.世界运作的逻辑, AI量化投资". 昨天听刘润讲了一个故事:话说韩寒约九球天后潘晓婷打台球.韩寒觉得自己水平就算离潘有差距,但一战之力还 ...
- 用ETF做大类资产配置,夏普比1.84,附源码
原创文章第78篇,专注"个人成长与财富自由.世界运作的逻辑, AI量化投资". 财富自由与价值.专家有深刻的关联.成为专家,做生产者. 专家与专注,深度思考,长期主义关联. 成为对 ...
- 【投资策略】2022 年大类资产配置展望:稳中求进-中金公司
猜你喜欢 0.如果你想参与进元宇宙,究竟应该采取怎样的策略?1.未来10年,普通人的赚钱机会在哪里?2.华为2021数字化转型:从战略到执行.pdf3.2021抖音私域运营白皮书.pdf4.营销拓客思 ...
- 第三届大湾区杯B题思路及代码-基于宏观经济周期的大类资产配置策略构建
B 题 基于宏观经济周期的大类资产配置策略构建 赛题背景介绍: 赛题数据描述: 问题1. 寻找出高频有效的宏观经济指标,将 2001 年-2021 年国内的宏观经济运行状况划 分成不同的经济状态:(比 ...
- 大类资产配置(一)均值方差模型MOV
大类资产配置专题(四)均值方差模型(MVO):https://xueqiu.com/9509413026/172746747 MVO的基本思想是:假定投资者都是风险厌恶的,根据各类资产的预期收益和方差 ...
- 大类资产配置策略(一)恒定混合策略(Constant-mix Strategy)
关于恒定混合型配置策略主要介绍等权重投资组合(equally weighted portfolio)和60/40投资组合策略. 等权重投资组合:在有n种可投资的风险资产时,保持每种资产的投资权重为1/ ...
- python量化策略——大类资产配置模型(最小方差模型)
最小方差模型 寻求风险最小的大类资产组合. max=XTΣX\max=X^{T}\Sigma Xmax=XTΣX s.t.ΣX=1,Xi≥0,i=1,2,3...s.t. \quad \Sigma ...
最新文章
- HDU - 2181-哈密顿绕行世界问题
- MySQL从删库到跑路
- Ansible之使用角色一键部署httpd并检查部署结果
- 清除WebLogic8.1缓存
- elasticsearch常见错误解决办法
- 343. Integer Break
- 利用自己构建的网络进行鼾声识别
- VBA合并csv文件
- html5 box布局,使用Flexbox打造响应式网页网格布局
- pyqt自定义信号与槽(Signals and Slots)
- 微信PC版怎么安装旧版本
- 【NVMe2.0b 9】控制器初始化过程
- 决胜5G新战场,联通沃云全新战略重磅发布
- [MATLAB]从键盘输入一个带有字母构成的字符串,要求大写变小写,小写变大写输出。
- Linux 实用指令 -- 网络配置(查看网络IP和网关、 ping 测试主机之间网络连通、Linux网络环境配置(指定固定ip))
- axios下载文件乱码问题 无法解压 文件损坏
- std::vector概述
- VMware ESXi 8.0集成网卡驱动
- html 动画接口,10款 Web 动画插件
- 【烙铁使用规范】——烙铁的使用