有效性前沿
在无数风险资产投资组合中,只要给出既定风险水平,我们总是可以找到收益最高的一个组合。当投资者可承受的风险水平变化时,与该风险水平相对应的最优投资组合A点也一直存在,并且随着风险水平变化不断的移动。这条由不同风险水平下最优投资组合A点构成的曲线,我们称之为有效曲线,又叫有效前沿。
有效性前沿python计算
输入项:
1、资产收益率irr
2、资产相关性矩阵(协方差):cov
3、随机种子:seed。随机生成的配置比例数量,随机种子越大计算越精确
4、目标收益:r_return。投资者期望获得的收益率。
5、无风险利率:rf。指的是10年期国债收益率或者同业拆借利率。
计算步骤:
1、首先随机生成配置比例,个数为随机种子(seed)。
对应的代码为def random_weight
2、依据随机生成的配置比例,计算目标收益(r_return)下的最优配置比例
对应的代码为def cal_random_weight
3、依据随机生成的配置比例,求有效性前沿最左侧的点,即为有效性前沿的起点。
对应的代码为 self.cal_left_point
4、依据所有的最优点,绘制有效性前沿
对应的代码为 self.cal_ff
5、计算市场组合的预期收益率,预期波动率
对应的代码为 self.cal_market_weight
6、依据无风险利率,及市场组合两点连线,求出资本市场线
python代码:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import scipy.optimize as sco
plt.rcParams['font.sans-serif']=['SimHei']# 中文显示问题
plt.rcParams['axes.unicode_minus']=False# 负数显示问题classEffectiveForefront(object):"""
有效性前沿类
"""def__init__(self, irr, cov, seed, r_return, rf):"""
有效性前沿初始化
:param irr: 收益率
:param cov: 协方差
:param seed: 随机种子数
:param r_return: 目标收益率
:param rf: 无风险利率
"""
self.irr = irr
self.rf = rf
self.cov = cov
self.seed = seed
self.r_return = r_return
self.plt =None
self.cons =({'type':'eq','fun':lambda x: np.sum(x)-1},{'type':'eq','fun':lambda x: self.opt_return_vol(x)[0]- r_return})# 输入最优解条件
self.bnds =tuple((0,1)for x inrange(len(irr)))# 输入边界条件
self.frist_weight =len(irr)*[1/len(irr)]# 生成初始权重defeff_handler(self):"""
有效性前沿计算流程
:return: self.plt 有效性前沿及资本市场线
:return: opt_w 目标收益率下资产配置比例
"""
self.plt = self.random_weight()
opt_w = self.cal_random_weight()
left_point_return, left_point_vol = self.cal_left_point()
self.plt.plot(left_point_vol, left_point_return,'y*', markersize=14)
self.cal_ff(left_point_return)
rm, vm, slope = self.cal_market_weight()
rp_cml, vp_cml = self.cal_cml(slope)
self.plt.plot(vp_cml, rp_cml,'b--')
self.plt.plot(vm, rm,'g*', markersize=14)
self.plt.show()return self.plt, opt_w
defcal_cml(self, slope):"""
计算资本市场线
:param slope: 计算资本市场线斜率
:return:
"""
rp_cml = np.linspace(0.02,0.25)
vp_cml =(rp_cml - self.rf)/ slope
return rp_cml, vp_cml
defcal_market_weight(self):"""
市场组合的预期收益率,预期波动率
:return:
"""# 仅设定权重之和为1的约束条件
cons_sr =({'type':'eq','fun':lambda x: np.sum(x)-1})# 求解最优权重
result_sr = sco.minimize(self.srmin_f, self.frist_weight, method='SLSQP', bounds=self.bnds, constraints=cons_sr)
slope =-result_sr['fun']# 即资本市场线斜率# 市场组合的预期收益率
rm = np.sum(irr * result_sr['x'])# 市场组合的收益率# 市场组合的波动率
vm =(rm - self.rf)/ slope # 市场组合的波动率return rm, vm, slope
defcal_ff(self, left_point_return):"""
求解有效前沿
:param left_point_return: 最左侧点收益率
:param left_point_vol: 最左侧点波动率
:return:
"""
rp_target = np.linspace(left_point_return,0.25,100)# 设定波动率列表
vp_target =[]for r in rp_target:
cons_new =({'type':'eq','fun':lambda x: np.sum(x)-1},{'type':'eq','fun':lambda x: self.opt_return_vol(x)[0]- r})
result_new = sco.minimize(self.vmin_f, self.frist_weight, method='SLSQP',
bounds=self.bnds, constraints=cons_new)
vp_target.append(result_new['fun'])
self.plt.plot(vp_target, rp_target,'r-')defcal_random_weight(self):"""
计算最有结果权重
:return:
"""# 求最值
result = sco.minimize(self.vmin_f, self.frist_weight, method='SLSQP', bounds=self.bnds, constraints=self.cons)# 获取最优化结果的权重
result['x'].round(4)
w_df = pd.DataFrame()
w_df['asset']=list(self.cov)
w_df['weight']= result['x']return w_df
defrandom_weight(self):"""
随机生成配置比例
:return:
"""
rp_list =[]
vp_list =[]# 设定投资组合各产品的均值for i in np.arange(self.seed):
x = np.random.random(5)
weights = x /sum(x)
rp_list.append(np.sum(weights * self.irr))
vp_list.append(np.sqrt(np.dot(weights, np.dot(self.cov, weights.T))))
plt.figure(figsize=(8,6))
plt.scatter(vp_list, rp_list)
plt.xlim(0.12,0.28)
plt.ylim(-0.1,0.2)
plt.xlabel('波动率')
plt.ylabel('预期收益率')
plt.grid('True')return plt
defopt_return_vol(self, w):"""
计算最优组合的预期收益率、收益波动率
:param w: 资产配置权重
:return:
"""
w = np.array(w)
rp_opt = np.sum(w * self.irr)# 计算最优投资组合的预期收益率
vp_opt = np.sqrt(np.dot(w, np.dot(self.cov, w.T)))# 计算最优投资组合的收益波动率return np.array([rp_opt, vp_opt])defvmin_f(self, w):return self.opt_return_vol(w)[1]defcal_left_point(self):"""
求解有效前沿最左侧的点
:return:
"""
cons_vmin =({'type':'eq','fun':lambda x: np.sum(x)-1})
result_vmin = sco.minimize(self.vmin_f, self.frist_weight, method='SLSQP',
bounds=self.bnds, constraints=cons_vmin)# 求解投资组合的最左侧点的收益率
rp_vmin = np.sum(irr * result_vmin['x'])# 求解投资组合的最左侧点的波动率
vp_vmin = result_vmin['fun']return rp_vmin, vp_vmin
defsrmin_f(self, w):"""
最优投资组合夏普比率
:param w:
:return:
"""
w = np.array(w)
rp_opt = np.sum(w * irr)
vp_opt = np.sqrt(np.dot(w, np.dot(cov, w.T)))
SR =(rp_opt - self.rf)/ vp_opt
return-np.array([rp_opt, vp_opt, SR])[2]# 求解最大的夏普比率就是求解负的最小值if __name__ =='__main__':
irr = np.array([0.20,0.08,-0.17,0.06,-0.04])
cov = pd.DataFrame({'A':[0.09,0.02,0.02,0.01,0.02],'B':[0.02,0.12,0.04,0.02,0.03],'C':[0.02,0.04,0.07,0.02,0.03],'D':[0.01,0.02,0.02,0.04,0.02],'E':[0.02,0.03,0.03,0.02,0.04]})
seed =10000
r_return =0.1
rf =0.02
ef = EffectiveForefront(irr, cov, seed, r_return, rf)
plt, opt_w = ef.eff_handler()print('目标收益率下的配置比例为')print(opt_w)
plt.show()
该算法的优点:
1、无需用到复杂的tensorflow模型,比较好调试参数
2、资产数较少的时候,计算非常准确。
缺点:
1、资产数较大的时候,要满足相同的精度,需要的随机种子数会指数级增加。在本案例中,五个资产用了一万随机种子。如果资产数增加为六,随机种子数要达到十万个。如果50个资产,随机种子数要达到10^50。不适合资产配置较多的投资组合。
2、大量随机生成的配置点离最优点非常远,浪费掉了。
附上python结果:
目标收益率下的配置比例为:
asset weight
0 A 0.310922
1 B 0.085937
2 C 0.000000
3 D 0.550663
4 E 0.052478
版权归原作者 GOGOTYY 所有, 如有侵权,请联系我们删除。