weixin_43713627
魏。
2021-01-16 13:51

使用scipy.optimize做二次优化时,为什么有时候不进行迭代?

  • python

一、问题描述

       由于最近需要做一个风险平价模型,其中包含一个二次优化(数据为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.本人水平很菜,代码还是很简单很初级的东西,希望各位见谅则个。

  • 点赞
  • 回答
  • 收藏
  • 复制链接分享

0条回答

为你推荐

换一换