一、问题描述
由于最近需要做一个风险平价模型,其中包含一个二次优化(数据为6项资产近5年的数据):
f(V,w)= x
V:几项资产的协方差矩阵;w:几项资产的权重向量;x:一个常数向量(自己预设的风险贡献度,一般为6个1/6)
在使用scipy.optimize时:
1.若用前365天(或第二个365天)的数据求出V,然后进行优化,会进行6次迭代,由w0初始值迭代出优化值w;
2.若用第六(及以上)个365天的数据求出V,然后进行优化,便会不迭代,直接给出初始值w0;
3.若用60天/90天/200天/250天等的数据求出V,然后进行优化,也会不迭代,直接给出初始值w0;
所以不知道是scipy自身有bug,还是我的操作不对?因为毕竟第一种情况是可以正常求出结果的。
我问过周围一些人,代码应该是没问题的(因为本来就是抄的,也经过了测试),但不知道怎么会出现这样的问题,求各位大佬帮帮忙,看看有没有遇到过类似的情况?该怎么解决?
二、代码如下
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import minimize
# 读取文件,并赋值为data(6个资产的价格序列)
data = pd.read_csv('data.csv', encoding = 'utf-8', header = 1, names = None)
data = data.set_index('Date',drop=True)
# 求出收益率序列,赋值为data_r(6个资产的收益率序列)
data_r = pd.DataFrame()
for i in range(len(data)-1):
data_r = data_r.append((data.iloc[i+1,] - data.iloc[i,])/data.iloc[i,], ignore_index = True)
data_r.columns = data_r.columns+'_r'
# 风险预算优化(求二次优化需要用到的一些函数,抄的一位大佬的)
def calculate_portfolio_var(w,V):
#计算组合风险的函数
w = np.matrix(w)
return (w*V*w.T)[0,0]
def calculate_risk_contribution(w,V):
# 计算单个资产对总体风险贡献度的函数
w = np.matrix(w)
sigma = np.sqrt(calculate_portfolio_var(w,V))
# 边际风险贡献
MRC = V*w.T
# 风险贡献
RC = np.multiply(MRC,w.T)/sigma
return RC
def risk_budget_objective(x,pars):
# 计算组合风险
V = pars[0]# 协方差矩阵
x_t = pars[1]# 组合中资产预期风险贡献度的目标向量
sig_p = np.sqrt(calculate_portfolio_var(x,V))# 组合标准差
risk_target = np.asmatrix(np.multiply(sig_p,x_t))
asset_RC = calculate_risk_contribution(x,V)
J = sum(np.square(asset_RC - risk_target.T))[0,0]# 平方误差求和
return J
def total_weight_constraint(x):
return np.sum(x) - 1.0
def long_only_constraint(x):
return x
# 使用数据计算协方差,这里是使用前365天的数据,后面会进行6次迭代
# 若改成60天/90天/200天/900:1265天的数据,不进行迭代,会直接给出w0初始值
covdf_year = pd.DataFrame(np.cov(data_r.iloc[0:365,0:], rowvar=False))
V = np.matrix(covdf_year)
# 根据资产预期目标风险贡献度来计算各资产的权重,这里的w0就是优化中用到的初始值
def calcu_w(x):
w0 = [1/8,1/8,1/8,1/8,1/4,1/4]
x_t = x
cons = ({'type': 'eq', 'fun': total_weight_constraint},{'type': 'ineq', 'fun': long_only_constraint})
res = minimize(risk_budget_objective, w0, args=[V,x_t], method='SLSQP', constraints=cons, options={'disp': True})
w_rb = np.asmatrix(res.x)
return w_rb
# 计算w,参数为预设的风险贡献度,6个1/6代表6个资产拥有相同的风险贡献度
w = calcu_w([1/6,1/6,1/6,1/6,1/6,1/6])
# 之后便会得出结果了,就是上面的几个截图,只有第一种情况是会给出几个不同的结果,其他情况的结果全都是w0初始值[1/8,1/8,1/8,1/8,1/4,1/4]。
三、备注
1.大佬的代码用的是4个资产,我稍作修改,适用于6个资产,不知道算不算抄袭?如果是的话,请告知我,我立马做出补救(第一次发帖子,不太懂这些东西);
2.本人水平很菜,代码还是很简单很初级的东西,希望各位见谅则个。
不知道你这个问题是否已经解决, 如果还没有解决的话: