使用Cplex求解均值方差模型

   在进行多目标进化算法求解投资组合问题时,由于多目标进化算法求得的是一组近似最优解,对于最大化收益和最小化风险的两目标M-V模型,需要找到一个基准,方便作为参考。这里利用Cplex工具求解均值-方差模型。

1、模型构建

   马科维茨的均值-方差模型,实质上是一个非线性的双目标的最优化问题,为的是达到最大化收益和最小化风险双目标的均衡状态。模型的数学描述如式所示:
在这里插入图片描述

   其中,其中V为投资组合的风险,希望其尽可能小。R为投资组合的收益,希望其尽可能大。X为投资到各个证券上的资产比例组成的权重向量。
双目标问题聚合为单目标问题:
   下面我们将该双目标问题转化为单目标优化问题,它是假设在投资组合收益率相同的情况下,把风险降为最小的模型。即仅保留最小化风险这个目标,将收益转化为约束。
在这里插入图片描述

2、数据准备

   数据准备对模型构建至关重要,原始数据集为100只股票的周盘价,通过统计计算,我们得到98只股票的期望收益率以及收益率的协方差矩阵。

3、Cplex求解

(1)首先导入所需函数库

import cplex
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

(2)数据准备

cov_matrix =pd.read_csv(r'data\股票收盘价集合\股票收益率矩阵.csv')
expect_return = pd.read_csv(r'data\股票收盘价集合\股票期望收益率.csv')
cov_matrix = cov_matrix.to_numpy()
expect_return = expect_return['0'].tolist()
return_max = max(expect_return)
return_min = min(expect_return)
StockNames = range(0,98)

(3)构建Cplex模型

def setproblemdata(p):
    p.objective.set_sense(p.objective.sense.minimize)    
    names = ['w' + str(i) for i in range(98)]    
    p.variables.add(obj=[0] * 98, ub=[1] * 98, lb=[0] * 98, names=names)
    my_senses = 'EG'
    my_rhs = [1, 0.005]
    rows = [[names, [1] * 98],[names, list(expect_return[:98])]]
    p.linear_constraints.add(lin_expr=rows, senses=my_senses, rhs=my_rhs )
    qmat = []
    for j in range(98):
        qmat.append([[i for i in range(98)], [2 * cov_matrix[j, m] for m in range(98)]])
    p.objective.set_quadratic(qmat)

(4)模型运行求解

p = cplex.Cplex()
setproblemdata(p)
p.solve()

print(sum(p.solution.get_values()))#是否满足预算约束
print(p.solution.get_objective_value())#最低风险值
print(np.array(p.solution.get_values()).round(3))#对应的投资组合

portfolio_names = []
portfolio_weights = []
for i in range(98):
    proportion = np.round(p.solution.get_values()[i], 3)  # keep results with 3 decimals and keep weights larger than 0
    if proportion != 0:
        portfolio_names.append(StockNames[i])
        portfolio_weights.append(proportion)
df = pd.DataFrame(columns = portfolio_names)
df.loc['Weight'] = portfolio_weights
print('Selected stocks and their weights:')
print(df)

运行结果
在这里插入图片描述
(5)敏感性分析

def sensitivity(exp_return):
    p = cplex.Cplex()
    p.objective.set_sense(p.objective.sense.minimize)
    names = ['w' + str(i) for i in range(98)]
    p.variables.add(obj=[0] * 98, ub=[1] * 98, lb=[0] * 98, names=names)
    my_senses = 'EG'
    my_rhs = [1, exp_return]
    rows = [[names, [1] * 98], [names, list(expect_return[:98])]]
    p.linear_constraints.add(lin_expr=rows, senses=my_senses, rhs=my_rhs)
    qmat = []
    for j in range(98):
        qmat.append([[i for i in range(98)], [2 * cov_matrix[j, m] for m in range(98)]])
    p.objective.set_quadratic(qmat)
    p.solve()
    return (p.solution.get_objective_value(), np.array(p.solution.get_values()).round(3))

return_values = np.arange(0.0000635, 0.0095, 0.00009436)
risks = []
for i in return_values:
    risks.append(sensitivity(i)[0])
print(return_values)
print(risks)
plt.figure(figsize=(15,8))
plt.plot(risks, return_values, '.--')
plt.xlabel('Portfolio Risk', fontsize = 18)
plt.ylabel('Portfolio Return', fontsize = 18)
plt.title('Efficient Frontier for our stocks pool\n', fontsize = 25)
plt.grid()
plt.show()
print(np.sum(sensitivity(0.005)[1]))

最优边界图片
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值