文章目录

  • 1. 引言
    • 1.1 前文回顾与问题提出
    • 1.2 数据收集与标的资产选取
    • 1.3 基本假设
  • 2. 风险平价策略简介
    • 2.1 模型的建立
    • 2.2 模型求解
  • 3. 风险平价策略实现伪代码
  • 4. 基于python的模型实现
    • 4.1 python代码
    • 4.2 实证结果
  • 5. 结论
    • 5.1 策略表现
    • 5.2 可能存在的问题及潜在处理方法
  • 免责声明
  • 写在最后

1. 引言

1.1 前文回顾与问题提出

在之前的文章中,我们介绍了马科维茨模型在中国市场资产配置中的应用。(详情请见【基金量化研究系列】大类资产配置研究(四)——基于马科维茨模型的资产配置研究)。但是,由于马科维茨模型中存在的诸多问题,资产配置的效果却不尽如人意。

我们之前的实证研究已经提到过:波动率与未来的收益率呈现出显著的负相关关系,因此我们可以以某类资产的波动率作为先行指标:当资产波动率不断上升时,资产收益的下行风险显著增加,在这种情况下我们应该对该类资产进行减仓。我们很自然地想到一种配置思路:如果让所有的风险资产对投资组合的总风险的贡献均有相同的比例(即风险平价),那这样一种策略会不会既稳健又有较高的收益率呢?

在这篇文章中,就让我们来验证一下这样的观点吧!

1.2 数据收集与标的资产选取

本文以开源的Choice数据库作为本文的数据来源。关于Choice数据库的使用方法及说明请参考:Choice数据量化接口产品手册。

对于标的资产的选择,我们仍以“易方达沪深300ETF(510310)”与“国泰上证5年国债ETF(511010)”作为股票市场与债券市场的基准可投标的,并以“华安黄金易ETF(518880)”和“七日深圳国债逆回购R-007(131801)”作为商品和无风险资产的基准可投资标的。这些标的均可以在券商账户中进行交易。

1.3 基本假设

本文仍延续前文的基本假设,规定:
(1)市场中不允许融资做多与融券做空;
(2)建仓调仓过程中不允许借款、参与国债回购;
(3)每日仅在收盘时间以收盘价格进行交易;
(4)未特别规定,忽略调、建仓手续费。


2. 风险平价策略简介

2.1 模型的建立

所谓 风险平价(Risk Parity) ,即将 投资组合的总风险平均分散入各资产,使得每一类资产贡献的风险相等。因此,首先要解决的问题,就是如何去衡量各类资产所贡献的风险大小。

首先,组合资产的波动率满足:

σp=(ωTΣω)12\sigma_p = (\omega^T \Sigma \omega )^{ \frac{1}{2}} σp​=(ωTΣω)21​

其中:
· σp 表示组合资产的标准差;
· Σ 表示风险资产的协方差矩阵;
· ω 表示风险资产的权重列向量。

定义第 i 类资产的风险贡献率(Risk Contribution)RCi
RCi=1σpωi∂σp∂ωi,i=1,2,...,N\text{RC}_i = \frac{1}{\sigma_p} \omega_i \frac{\partial\sigma_p}{\partial\omega_i}, \ i = 1, 2, ..., N RCi​=σp​1​ωi​∂ωi​∂σp​​, i=1,2,...,N
其中:
∂σp∂ωi=∂(ωTΣω)12∂ωi=(ωTΣ)iωTΣω,i=1,2,...,N\frac{\partial\sigma_p}{\partial\omega_i} = \frac{\partial(\omega^T \Sigma \omega )^{ \frac{1}{2}}}{\partial\omega_i} = \frac{(\omega^T\Sigma)_i }{\sqrt{\omega^T \Sigma \omega}} , \ i = 1, 2, ..., N ∂ωi​∂σp​​=∂ωi​∂(ωTΣω)21​​=ωTΣω​(ωTΣ)i​​, i=1,2,...,N
因此, RCi 可以变型为:
RCi=ωi(ωTΣ)iωTΣω,i=1,2,...,N\text{RC}_i = \frac{\omega_i(\omega^T\Sigma)_i }{\omega^T \Sigma \omega}, \ i = 1, 2, ..., N RCi​=ωTΣωωi​(ωTΣ)i​​, i=1,2,...,N
上式的分子项表示由第 i 类资产贡献的方差,分母则表示组合资产的总方差。

若想让每一类风险资产对组合的风险贡献率相等,对于任意的 i,RCi 应满足:
RCi=ωi(ωTΣ)iωTΣω=1N,i=1,2,...,N\text{RC}_i = \frac{\omega_i(\omega^T\Sigma)_i }{\omega^T \Sigma \omega}= \frac{1}{N}, \ i = 1, 2, ..., N RCi​=ωTΣωωi​(ωTΣ)i​​=N1​, i=1,2,...,N
或者可以等价转换为一个 N 元非线性函数的零点问题:
f(ω)=∑i=1N(RCi−1N)2=∑i=1N(ωi−ωTΣωN(ωTΣ)i)2=0f(\omega) = \sum_{i=1}^{N}(\text{RC}_i - \frac{1}{N})^2 \\ = \sum_{i = 1}^{N} ( \omega_i - \frac{\omega^T \Sigma \omega}{N(\omega^T\Sigma)_i } )^2 = 0 f(ω)=i=1∑N​(RCi​−N1​)2=i=1∑N​(ωi​−N(ωTΣ)i​ωTΣω​)2=0
然而,除了风险平价的限制以外,我们还对各资产的权重有限制:我们要求各权重必须非负(不可做空),且权重的和必须为1(全部投资),而这些额外的限制条件很可能导致上述函数无实数解。一种退而求其次的方法则是将上述方程转化为下列约束优化问题:
min f(ω)=∑i=1N(ωi−ωTΣωN(ωTΣ)i)2\text{min} \ f(\omega) = \sum_{i = 1}^{N} ( \omega_i - \frac{\omega^T \Sigma \omega}{N(\omega^T\Sigma)_i } )^2 min f(ω)=i=1∑N​(ωi​−N(ωTΣ)i​ωTΣω​)2
s.t.

ωT1−1=0ωi≥0,i=1,...,N\omega^T\bold{1} - 1 = 0 \\ \omega_i ≥ 0,i= 1, ..., N ωT1−1=0ωi​≥0,i=1,...,N

也可以将上述优化问题的目标函数改写成矩阵形式:
f(ω)=[ω−ωTΣωNv]T[ω−ωTΣωNv]f(\omega) = [ \omega - \frac{\omega^T \Sigma \omega}{N}v ]^T [ \omega - \frac{\omega^T \Sigma \omega}{N}v ] f(ω)=[ω−NωTΣω​v]T[ω−NωTΣω​v]
其中,vN 阶列向量:
v=(vi)N×1=[1(ωTΣ)i]N×1v = (v_i)_{N\times1}= [\frac{1}{(\omega^T\Sigma)_i }] _{N\times1} v=(vi​)N×1​=[(ωTΣ)i​1​]N×1​

因此,对于风险平价策略,投资于各风险资产的权重修向量 ω 即为下列约束优化问题的解:
minf(ω)=[ω−ωTΣωNv]T[ω−ωTΣωNv]\text{min} f(\omega) = [ \omega - \frac{\omega^T \Sigma \omega}{N}v ]^T [ \omega - \frac{\omega^T \Sigma \omega}{N}v ] minf(ω)=[ω−NωTΣω​v]T[ω−NωTΣω​v]

s.t.
ωT1−1=0ω≥0\omega^T\bold{1} - 1 = 0 \\ \omega ≥ \bold0 \\ ωT1−1=0ω≥0

2.2 模型求解

由于上述问题仍然是有线性限制条件的优化问题,我们仍可延续马科维茨模型中的求解方法,使用Python的Scipy包中的minimize函数进行上述优化问题的求解。同样地,对于R语言使用者,可以使用alabama包中的constrOptim.nl函数进行求解。


3. 风险平价策略实现伪代码

风险平价策略得的伪代码如下:
Step 0:始化参数。规定调仓频率(本文以 T = 30 即30个交易日作为调仓周期进行说明)。规定 t = 0,进入Step 1;
Step 1:根据前一周期的日收盘价格,计算该周期内除无风险资产以外的各类资产日收益率 ri,t 与日波动率 σi,t,计算各类资产的风险平价权重 wi,t
Step 2:以当日收盘价格将各类资产比例调整至目标权重;
Step 3: 令 t = t + 1,重复 Step 1 直至回测结束。


4. 基于python的模型实现

4.1 python代码

由于风险平价策略在权重的优化求解方法上和形式上与马科维茨模型如出一辙,因此本文在马科维茨模块基础上进行了改进,只需要对模块函数内的目标函数进行修改即可。(请参考【基金量化研究系列】大类资产配置研究(四)——基于马科维茨模型的资产配置研究的4.1部分)。在运行时,可将下列代码块保存为python文件“Mean_Variance.py”。

# -*- coding: utf-8 -*-
# author: Mikey_Sun time: 5/19/2020
# all copyright belongs to the author. NO COPY ALLOWED.import math
from scipy.optimize import minimize
import numpy as np
import pandas as pd########################
## Module 1 MV框架模块 ##
########################
def M_V(R, rf, Sigma, output_type = 'Dict', print_out = False):''':param R: list格式,输入各收益序列:param rf: num格式或list格式,输入无风险利率:param Sigma: two-d list格式,输入各收益序列协方差矩阵:param output_type: Bool类型,True为打印结果,Flase为不打印结果:param : num格式或list格式:return: dataframe'''# Step 1: 初始化收入变量格式N = len(R) # 获取资产类别数R = np.array(R).reshape(N) # 格式化收益率序列rf = np.array(rf) # 格式化无风险利率Sigma = np.array(Sigma).reshape(N, N) # 格式化协方差矩阵# Step 2: 将无风险利率嵌入到收益率序列与协方差矩阵中(增广阵)R = np.r_[R, rf] # 增广收益率序列Sigma = np.c_[Sigma, np.zeros(N).reshape(N, 1)] # 增广协方差矩阵列Sigma = np.r_[Sigma, np.zeros(N+1).reshape(1, N+1)] # 增广协方差矩阵行# Step 3: 利用minimize函数进行模型求解:eps = 1e-10  # 找到一个非常接近0的值作为误差限w0 = np.ones(N+1) / (N+1)  # 各类别资产权重参数初始化#fun = lambda w: 0.5 * math.log(np.dot(np.dot(w, Sigma), np.transpose(w))) - math.log(#    np.dot(w, R - rf))  # 约束函数:最大化对数sharpe-ratiofun = lambda w:  - np.dot(w, R - rf) / np.dot(np.dot(w, Sigma), np.transpose(w))**0.5 # 约束函数:最大化对数sharpe-ratiocons = ({'type': 'eq', 'fun': lambda w: np.sum(w) - 1},  # 限制条件一:全部投资{'type': 'ineq', 'fun': lambda w: w - eps},  # 限制条件二:不可做空)res = minimize(fun, w0, method='SLSQP', constraints=cons)# Step 4: 计算各指标w_op = res.x # 获取权重数据r_op = np.dot(res.x, R) # 计算收益率sigma_op = np.dot(np.dot(w_op, Sigma), np.transpose(w_op)) # 计算组合波动率SR = (r_op - rf) / sigma_op # 计算夏普比率# Step 5: 是否打印测试if print_out:print('''最优权重配比:{0:}最优收益率:{1:.2f}最优风险:{2:.2f}最优夏普比率:{3:.2f}  '''.format(w_op, r_op, sigma_op, SR))# Step 6: 打印模块if str(output_type).upper() == 'DATAFRAME':return pd.DataFrame({'Weights':[w_op], 'Return':r_op, 'Sigma':sigma_op, 'SR':SR})elif str(output_type).upper() == 'DICT':return {'Weights':w_op, 'Return':r_op, 'Sigma':sigma_op, 'SR':SR}elif str(output_type).upper() == 'LIST':return [w_op, r_op, sigma_op, SR]else:return {'Weights':w_op, 'Return':r_op, 'Sigma':sigma_op, 'SR':SR}########################
## Module 2 风险平价框架模块 ##
########################def R_P(R, rf, Sigma, output_type = 'Dict', print_out = False):''':param R: list格式,输入各收益序列:param rf: num格式或list格式,输入无风险利率:param Sigma: two-d list格式,输入各收益序列协方差矩阵:param output_type: Bool类型,True为打印结果,Flase为不打印结果:param : num格式或list格式:return: dataframe'''# Step 1: 初始化收入变量格式N = len(R) # 获取资产类别数R = np.array(R).reshape(N) # 格式化收益率序列rf = np.array(rf) # 格式化无风险利率Sigma = np.array(Sigma).reshape(N, N) # 格式化协方差矩阵# Step 2: 利用minimize函数进行模型求解:eps = 1e-10  # 找到一个非常接近0的值作为误差限w0 = np.ones(N) / N  # 各类别资产权重参数初始化fun = lambda w: np.dot(w - np.dot(np.dot(w, Sigma), np.transpose(w))/N / np.dot(w, Sigma),np.transpose(w - np.dot(np.dot(w, Sigma), np.transpose(w))/N / np.dot(w, Sigma) ))cons = ({'type': 'eq', 'fun': lambda w: np.sum(w) - 1},  # 限制条件一:全部投资{'type': 'ineq', 'fun': lambda w: w - eps},  # 限制条件二:不可做空)res = minimize(fun, w0, method='SLSQP', constraints=cons)# Step 4: 计算各指标w_op = res.x # 获取权重数据r_op = np.dot(res.x, R) # 计算收益率sigma_op = np.dot(np.dot(w_op, Sigma), np.transpose(w_op)) # 计算组合波动率SR = (r_op - rf) / sigma_op # 计算夏普比率# Step 5: 是否打印测试if print_out:print('''最优权重配比:{0:}最优收益率:{1:.2f}最优风险:{2:.2f}最优夏普比率:{3:.2f}  '''.format(w_op, r_op, sigma_op, SR))# Step 6: 打印模块if str(output_type).upper() == 'DATAFRAME':return pd.DataFrame({'Weights':[w_op], 'Return':r_op, 'Sigma':sigma_op, 'SR':SR})elif str(output_type).upper() == 'DICT':return {'Weights':w_op, 'Return':r_op, 'Sigma':sigma_op, 'SR':SR}elif str(output_type).upper() == 'LIST':return [w_op, r_op, sigma_op, SR]else:return {'Weights':w_op, 'Return':r_op, 'Sigma':sigma_op, 'SR':SR}

下面是主函数模块代码块。其中引用的“Risk_Factor_Calculation”模块来自于本人自己开发的量化策略回测框架中的一部分,请参考:【基于python的量化策略回测框架搭建】策略表现衡量指标模块。

# -*- coding: utf-8 -*-
# author: Mikey_Sun time: 5/26/2020
# all copyright belongs to the author. NO COPY ALLOWED.import Risk_Factor_Calculation as RF
import Mean_Variance as MV
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,518880.SH,131801.SZ"  # 所需数据的代码。510310为沪深300ETF,511010为五年国债ETFindicators = "open,high,low,close"  # 需要下载的数据指标startdate = "20130729"  # 回测起始时间,可自行修改enddate = "20200515"  # 回测结束时间,可自行修改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) #设置数据索引为交易日
tickers = ["510310.SH","511010.SH","518880.SH",'131801.SZ']HS300ETF = pd.DataFrame(data[data["CODES"] == '510310.SH']["CLOSE"].astype(float)) #沪深300ETF专属数据结构。仅保留收盘价格
GZ5yETF = pd.DataFrame(data[data["CODES"] == '511010.SH']["CLOSE"].astype(float)) #国债ETF专属数据结构。仅保留收盘价格
GoldETF = pd.DataFrame(data[data["CODES"] == '518880.SH']["CLOSE"].astype(float)) #黄金ETF专属数据结构。仅保留收盘价格
R_001 = pd.DataFrame(data[data["CODES"] == '131801.SZ']["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 #创建收益率序列
GoldETF['RETURN'] = 0 #创建收益率序列
R_001['RETURN'] = 0
HS300ETF['RETURN'].astype(float)#设定格式为浮点
GZ5yETF['RETURN'].astype(float)#设定格式为浮点
GoldETF['RETURN'].astype(float)#设定格式为浮点
R_001['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日收益率
GoldETF["RETURN"][td_dates[1:]] = np.array(GoldETF["CLOSE"][td_dates[1:]]) / np.array(GoldETF["CLOSE"][td_dates[:-1]]) - 1 #计算GZ5yETF日收益率
R_001["RETURN"][td_dates[1:]] = np.array(R_001["CLOSE"][td_dates[1:]])/100/365# 将收益率序列单独存储至returns
returns = pd.DataFrame({'510310.SH':HS300ETF["RETURN"], '511010.SH':GZ5yETF["RETURN"], '518880.SH':GoldETF["RETURN"], '131801.SZ':R_001["RETURN"]},index= td_dates)#################################
## Module 3: 计算策略权重    ######
#################################
def weights_calculate_RP(T):weights_strategy_RP = []for t in range(T, n, T):R = []for i in range(3):R.append(np.mean(returns[tickers[i]][td_dates[t - T:t]]) * T)rf = np.mean(returns['131801.SZ'][td_dates[t - T:t]]) * TSigma = np.cov(returns[tickers[0:3]][t - T:t] * T, rowvar=False)outcome = MV.R_P(R=R, rf=rf, Sigma=Sigma)for i in range(T):weights_strategy_RP.append(outcome['Weights'])return weights_strategy_RPdef weights_calculate_MV(T):weights_strategy_MV = []for t in range(T, n, T):R = []for i in range(3):R.append(np.mean(returns[tickers[i]][td_dates[t - T:t]]) * T)rf = np.mean(returns['131801.SZ'][td_dates[t - T:t]]) * TSigma = np.cov(returns[tickers[0:3]][t - T:t] * T, rowvar=False)outcome = MV.M_V(R=R, rf=rf, Sigma=Sigma)for i in range(T):weights_strategy_MV.append(outcome['Weights'])return weights_strategy_MV#################################
## Module 4: 各策略净值与收益率计算 ##
#################################
nv_HS300ETF = [1]  #记录全仓股票策略净值
nv_GZ5yETF = [1]  #记录全仓债券策略净值
nv_GoldETF = [1]
nv_Cash = [1]
r_HS300ETF = []
r_GZ5yETF = []
r_GoldETF = []
r_Cash = []nv_strategy_MV = [1]
r_strategy_MV = []
nv_strategy_RP = [1]
r_strategy_RP = []T = 30 # 设置调参周期长度
weights_strategy_RP = weights_calculate_RP(T) # 计算风险平价策略权重序列
weights_strategy_MV = weights_calculate_MV(T) # 计算马科维茨模型策略权重序列for i in range(T, n):nv_HS300ETF.append( nv_HS300ETF[i-T] *(1 + returns['510310.SH'][td_dates[i]]))nv_GZ5yETF.append( nv_GZ5yETF[i-T] *(1 + returns['511010.SH'][td_dates[i]]))nv_GoldETF.append( nv_GoldETF[i-T] *(1 + returns['518880.SH'][td_dates[i]]))nv_Cash.append( nv_Cash[i-T] *(1 + returns['131801.SZ'][td_dates[i]]))r_HS300ETF.append(returns['510310.SH'][td_dates[i]])r_GZ5yETF.append(returns['511010.SH'][td_dates[i]])r_GoldETF.append(returns['518880.SH'][td_dates[i]])r_Cash.append(returns['131801.SZ'][td_dates[i]])r_strategy_MV.append(weights_strategy_MV[i - T][0] * returns[tickers[0]][td_dates[i]] +weights_strategy_MV[i - T][1] * returns[tickers[1]][td_dates[i]] +weights_strategy_MV[i - T][2] * returns[tickers[2]][td_dates[i]] +weights_strategy_MV[i - T][3] * returns[tickers[3]][td_dates[i]])r_strategy_RP.append(weights_strategy_RP[i - T][0] * returns[tickers[0]][td_dates[i]] +weights_strategy_RP[i - T][1] * returns[tickers[1]][td_dates[i]] +weights_strategy_RP[i - T][2] * returns[tickers[2]][td_dates[i]])nv_strategy_MV.append(nv_strategy_MV[i-T] * (1 + r_strategy_MV[i-T]))nv_strategy_RP.append(nv_strategy_RP[i-T] * (1 + r_strategy_RP[i-T]))#################################################
## Module 5: 汇总各策略净值信息,并计算其风险及收益情况 ##
#################################################
r_series = [r_HS300ETF, r_GZ5yETF, r_GoldETF, r_Cash, r_strategy_MV , r_strategy_RP]
nv_series = [nv_HS300ETF, nv_GZ5yETF, nv_GoldETF, nv_Cash, nv_strategy_MV ,nv_strategy_RP]Period = 'D'
Indicators = 'ALL'
alpha = 0.05
output_type = 'pd.DataFrame'
strategy_names = ['沪深300', '债券ETF', '黄金ETF', '国债逆回购', '均值方差策略', '风险平价策略']# 进入风险值计算回测系统框架(该框架为自主创建,需要读取该文件)
Risks = RF.Risk_Indicators(r_series, nv_series, Period = Period, Indicators= Indicators, alpha=alpha, output_type=output_type)
Risks = pd.DataFrame(Risks.values.tolist(), index = strategy_names, columns = Risks.columns)#打印风险值情况
print(Risks[Risks.columns[:4]])
print(Risks[Risks.columns[4:]])################################
## Module 6: 绘制各策略净值走势图 ##
################################
plt.plot(nv_HS300ETF, label = "nv_HS300ETF", color = "black")
plt.plot(nv_GZ5yETF, label = "nv_GZ5yETF", color = "red")
plt.plot(nv_GoldETF, label = "nv_GoldETF", color = "blue")
plt.plot(nv_Cash, label="nv_Cash", color="purple")
plt.plot(nv_strategy_MV, label="nv_strategy_MV", color="green")
plt.plot(nv_strategy_RP, label="nv_strategy_RP", color="grey")
plt.show()

:为节约时间,本文代码直接在马科维茨代码的基础上打了补丁,代码内容冗长,有待进一步优化,在此仅做实例展示。

4.2 实证结果

调仓周期为30个交易日时(设置 T = 30),策略的运行结果如下:

      Return     Sigma        R/S       MDD
沪深300   0.121751  0.245480   0.495972  1.046858
债券ETF   0.037404  0.028362   1.318794  0.056963
黄金ETF   0.058866  0.126968   0.463625  0.216147
国债逆回购   0.018584  0.000557  33.345747  0.000000
均值方差策略  0.061792  0.106153   0.582107  0.338244
风险平价策略  0.066728  0.060375   1.105237  0.102871MDD_R  MDD_P       VaR      CVaR
沪深300   0.456784  155.0  0.099732  0.099732
债券ETF   0.049023   39.0  0.016768  0.016768
黄金ETF   0.213716  461.0  0.046573  0.046573
国债逆回购   0.000000    0.0  0.000000  0.000000
均值方差策略  0.258140   17.0  0.065919  0.065919
风险平价策略  0.084008   47.0  0.051322  0.051322Process finished with exit code 0


*数据来源:Choice数据库
图1 2013/09/09 - 2020/05/15 期间各策略净值走势图(以2013年9月8日为基日,定义净值为1。黑线为全股策略,红线为全债策略,蓝线为纯黄金策略,紫线为纯现金策略,绿线为马科维茨模型策略,灰线为风险平价策略)

调仓周期调整为60个交易日时(设置 T = 60),策略的运行结果如下:

     Return     Sigma        R/S       MDD
沪深300   0.122891  0.246382   0.498783  1.041314
债券ETF   0.038749  0.028488   1.360169  0.057206
黄金ETF   0.064613  0.126399   0.511182  0.210307
国债逆回购   0.018449  0.000546  33.792535  0.000000
均值方差策略  0.051419  0.064649   0.795346  0.111822
风险平价策略  0.107824  0.064947   1.660180  0.090008MDD_R  MDD_P       VaR      CVaR
沪深300   0.456784  155.0  0.099732  0.099732
债券ETF   0.049023   39.0  0.016768  0.016768
黄金ETF   0.203894  339.0  0.046573  0.046573
国债逆回购   0.000000    0.0  0.000000  0.000000
均值方差策略  0.088425   12.0  0.034050  0.034050
风险平价策略  0.068778   53.0  0.023362  0.023362Process finished with exit code 0


*数据来源:Choice数据库
图2 2013/10/30 - 2020/5/15 期间各策略净值走势图(以2013年10月29日为基日,定义净值为1。黑线为全股策略,红线为全债策略,蓝线为纯黄金策略,紫线为纯现金策略,绿线为马科维茨模型策略,灰线为风险平价策略)


5. 结论

5.1 策略表现

策略表现上来看,调仓频率不论是每30个交易日一次还是每60个交易日一次,风险平价策略都相比于马科维茨策略拥有较低的风险水平较高的夏普比率。从尾部风险角度来看,风险平价策略 在相同置信度下的在险价值较低,而最大回撤比率也显著低于马科维茨策略。不过值得注意的是,风险平价策略的最大回撤周期远大于马科维茨策略,这意味着该策略将空间上的部分损失转化为时间上的损失,这可能要求组合管理人对连续的小阴跌要有较高的承受度。

还有一点值得注意的是,当调仓周期从30个交易日变更为60个交易日的时候,后者的收益率和夏普比率均明显高于前者,这可能意味着策略的表现对调仓周期较为敏感。在本文进一步的实证过程中,发现策略的表现随调仓频率的增加而呈现出明显的倒U型,这说明选择合适的调仓周期也是影响风险平价策略表现的重要因素

5.2 可能存在的问题及潜在处理方法

同时,我们也应该看到,调仓周期也是影响策略表现的一个重要因素。根据实证结果,调仓周期过短或过长,策略的表现均不理想。出现这一问题的原因可能有:
(1)估计量的有偏性。模型需要对各收益序列协方差矩阵进行估计,而样本长度会影响估计量的准确性。
(2)调仓信号的滞后性。当波动率在短期内发生重大变化时,调仓频率的滞后性会导致在短时间内仓位发生重大偏离。

对于第一种可能存在的问题,我们已经在马科维茨模型中给出了几种可能的解决方法,在此不做赘述。对于第二个问题,一种处理方法就是对调仓方式从周期性静态调仓变更为动态再平衡(Dynamic Rebalance)。例如,每日或每周监控各风险资产的风险贡献率,若某资产风险贡献率超越某一阈值(例如超越基准比率的10%)后则立即进行再平衡调仓。当然,也可以借鉴机器学习的办法,将调仓周期 T 作为策略的 调整参数(Tuning Parameter),通过设置目标函数(如夏普比率)以寻找最优的调仓周期。

此外,本文规定调仓周期与模型参数估计的样本窗口期长度相等(即以过去 T 个交易日的历史数据来计算未来 T 个交易日各资产所占的比例)。这一规定是经验性的,有兴趣的读者也可以在这一点上做进一步的研究。


免责声明

免责声明:本文内容及观点仅供参考,不构成任何投资建议,投资者据此操作,风险自担。一切有关本文涉及的数据均来自于第三方数据机构,使用时请查阅第三方数据平台的使用说明,本文不负有数据准确性的直接负责。本文所述策略表现均基于历史数据,不代表对未来的预期。投资有风险,入市需谨慎。


写在最后

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

欢迎感兴趣的小伙伴来跟作者一起挑刺儿~ 包括但不限于语言上的、排版上的和内容上的不足和疏漏~ 一起进步呀!
有任何问题,欢迎在本文下方留言,或者将问题发送至勘误邮箱: mikeysun_bugfix@163.com

谢谢大家!

【基金量化研究系列】大类资产配置研究(六)——多资产风险平价策略相关推荐

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

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

  2. 【基金量化研究系列】大类资产配置研究(一)——股债二八配置策略与股债风险平价策略

    文章目录 1. 引言 1.1 资产配置简介 1.2 可投标的说明 1.3 市场基本情况与数据库使用的说明 1.4 本文策略基本假设 2. 资产配置策略一--股债二八策略 2.1 策略简介 2.2 基于 ...

  3. AI大类资产配置:从风险平价开始

    原创文章第84篇,专注"个人成长与财富自由.世界运作的逻辑, AI量化投资". 昨天听刘润讲了一个故事:话说韩寒约九球天后潘晓婷打台球.韩寒觉得自己水平就算离潘有差距,但一战之力还 ...

  4. 用ETF做大类资产配置,夏普比1.84,附源码

    原创文章第78篇,专注"个人成长与财富自由.世界运作的逻辑, AI量化投资". 财富自由与价值.专家有深刻的关联.成为专家,做生产者. 专家与专注,深度思考,长期主义关联. 成为对 ...

  5. 【投资策略】2022 年大类资产配置展望:稳中求进-中金公司

    猜你喜欢 0.如果你想参与进元宇宙,究竟应该采取怎样的策略?1.未来10年,普通人的赚钱机会在哪里?2.华为2021数字化转型:从战略到执行.pdf3.2021抖音私域运营白皮书.pdf4.营销拓客思 ...

  6. 第三届大湾区杯B题思路及代码-基于宏观经济周期的大类资产配置策略构建

    B 题 基于宏观经济周期的大类资产配置策略构建 赛题背景介绍: 赛题数据描述: 问题1. 寻找出高频有效的宏观经济指标,将 2001 年-2021 年国内的宏观经济运行状况划 分成不同的经济状态:(比 ...

  7. 大类资产配置(一)均值方差模型MOV

    大类资产配置专题(四)均值方差模型(MVO):https://xueqiu.com/9509413026/172746747 MVO的基本思想是:假定投资者都是风险厌恶的,根据各类资产的预期收益和方差 ...

  8. 大类资产配置策略(一)恒定混合策略(Constant-mix Strategy)

    关于恒定混合型配置策略主要介绍等权重投资组合(equally weighted portfolio)和60/40投资组合策略. 等权重投资组合:在有n种可投资的风险资产时,保持每种资产的投资权重为1/ ...

  9. 【Python量化】风险平价策略

    文章目录 一.风险平价策略 二.风险平价组合的构建步骤 第一步,选择底仓. 第二步,计算资产对组合的风险贡献. 第三步,优化组合风险贡献,计算资产权重. 三.风险平价组合的Python实现 3.1 数 ...

  10. 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 ...

最新文章

  1. 国防科技大学教授:殷建平——计算机科学理论的过去、现在与未来
  2. 正则表达式验证代码(字母、数字、Email、网址、电话号码、汉字、身份证号码)
  3. 给你总结了这些对付幂等性的套路
  4. 返岗上班应该注意什么?五个细节必须牢记
  5. zzlinux运维自动化shell脚本小工具
  6. 402. 移掉K位数字(单调栈)
  7. html的换行问题(未解决)
  8. 【bayes】贝叶斯likelihood和model
  9. 不入oracle数据库,Oracle数据库之操作符及函数
  10. 疯传社群源码v7.8.0 测试可用 修复绿色版
  11. Promise 源码:静态方法
  12. 浅谈Cisco ASA的基础
  13. 使用iMazing精准地导出Safari浏览器数据
  14. codejock Toolkit Pro for Visual C++ MFC 零售版
  15. EDA365_skill2.5百度网盘资源
  16. oracle 定时任务
  17. Teamviewer远程工具使用
  18. 怎样用c语言预测股票价格,如何根据时间和价格的波动来预测股票走势
  19. gprs模块与服务器通信协议,gprs模块与服务器通信原理分析
  20. 05——去哪儿(旅游网站首页开发)

热门文章

  1. 大学学python用记笔记吗_Python 应该怎么学?
  2. 固态硬盘是什么接口_固态硬盘都有哪些接口,是否通用吗?
  3. 学习日记 | 云计算 - 服务模型 - 三层架构(深度学习)
  4. 想下载B站视频却不知如何下手?一文教你爬B站!
  5. 微信小程序云函数发天气预报
  6. 【ML】从特征分解,奇异值分解到主成分分析
  7. Excel数据批量导入导出(基础版)
  8. python编程软件开发_Python编程-绑定方法、软件开发
  9. php家族族谱代码,家族族谱系统设计.doc
  10. 【测试】兼容性测试云真机测试平台