Scipy库求解最优资产投资组合

问题导入:已知无风险利率为3%,下表包括六家公司的年度回报(文件),使用Python编制程序,求解最优投资组合。

Year BMW ORACLE YOIGO SACYR BALAY APPLE
2011 1.4866 0.0562 0.9641 -1.2367 0.0512 0.5075
2012 0.2902 0.4356 0.2111 4.0332 0.2491 0.4014
2013 0.1911 0.8831 0.3746 0.3813 0.1815 -1.6639
2014 0.1288 0.3643 -0.2525 0.0666 0.2566 0.1564
2015 -0.0850 0.1460 0.4236 0.4114 0.4718 0.2199
2016 0.1068 0.0836 0.1333 -0.9241 0.3121 -0.0216
2017 -0.0040 -0.6284 -0.3053 3.4962 -0.0368 -0.0636
2018 0.0726 0.4273 -0.2470 0.4870 0.1204 -0.2773
2019 -0.2030 -0.2196 0.1404 0.0862 -0.3052 -0.2985
2020 -0.0437 0.0681 -0.0756 -1.1594 -0.1501 3.0549

首先我们导入相关库。

import pandas as pd
import numpy as np
import scipy.optimize as sco

一、读取excel文件,获取收益率数据

excel文件链接:链接:https://pan.baidu.com/s/1nhhfS688IMxpW_xFtrMUVw 提取码:8rwb

Scipy库求解最优资产投资组合

代码如下:

data = pd.read_excel(r'C:UsersmiDesktop收益率.xlsx',index_col=0)
>>>data
          BMW  ORACLE   YOIGO   SACYR   BALAY   APPLE
Year                                                
2011   1.4866  0.0562  0.9641 -1.2367  0.0512  0.5075
2012   0.2902  0.4356  0.2111  4.0332  0.2491  0.4014
2013   0.1911  0.8831  0.3746  0.3813  0.1815 -1.6639
2014   0.1288  0.3643 -0.2525  0.0666  0.2566  0.1564
2015  -0.0850  0.1460  0.4236  0.4114  0.4718  0.2199
2016   0.1068  0.0836  0.1333 -0.9241  0.3121 -0.0216
2017  -0.0040 -0.6284 -0.3053  3.4962 -0.0368 -0.0636
2018   0.0726  0.4273 -0.2470  0.4870  0.1204 -0.2773
2019  -0.2030 -0.2196  0.1404  0.0862 -0.3052 -0.2985
2020  -0.0437  0.0681 -0.0756 -1.1594 -0.1501  3.0549

二、给定权重,求组合收益率、标准差、夏普比率

# 定义无风险收益率
rf = 0.03
# 获取股票平均收益率
returns = data.mean() 
# 获取股票收益率的方差协方差矩阵
cov = data.cov(bias=True
# 定义资产数量
number_assets = 6

# 给定权重,求组合收益率、标准差、夏普比率
def statistics(weights):        
    weights = np.array(weights)
    pret = np.dot(weights, returns) #获取组合收益率
    pvol = np.sqrt(np.dot(weights.T, np.dot(cov, weights))) #获取组合标准差
    psharpe = (pret - rf) / pvol #获取组合夏普比率
    return np.array([pret, pvol, psharpe])

三、规划求解

规划求解需要用到scipy.optimize的minimize函数。函数用法如下所示。

scipy.optimize.minimize(fun, x0, args=(), method=None, jac=None, hess=None, hessp=None, bounds=None, constraints=(), tol=None, callback=None, options=None)

主要参数如下表所示:

参数 说明
fun 目标函数
x0 初始迭代值
args 要输入到目标函数中的参数
method 求解的算法,目前可选的有Nelder-Mead,Powell,CG,BFGS,Newton-CG,L-BFGS-B,TNC,COBYLA,SLSQP,dogleg,trust-ncg等。一般求极值多用 ‘SLSQP’算法
bounds 可选项,变量的边界(仅适用于L-BFGS-B,TNC和SLSQP)。以(min,max)对的形式定义 x 中每个元素的边界。如果某个参数在 min 或者 max 的一个方向上没有边界,则用 None 标识。如(None, max)
constraints 约束条件(只对 COBYLA 和 SLSQP)。dict 类型。type : str, ‘eq’表示等于0,’ineq’表示不小于0 ;fun : 定义约束的目标函数。

(一)求解夏普比率最高的投资组合,并且单个资产权重均不超过20%

目标函数fun:夏普比率最大化

约束条件constraints:权重之和=1

变量边界bounds:单个权重不超过0.2

代码如下:

# 设置目标:夏普比率最大
def minus_sharpe(x):
    return -statistics(x)[2]

# 约束条件分为eq和ineq
# eq表示函数结果等于0 ;ineq 表示 表达式大于等于0  
# 约束条件:权重之和=1
def constraint1(x):
    return np.sum(x) -1

con1 = {'type''eq''fun': constraint1} 

# 定义边界约束(优化变量的上下限)
bnds = tuple((None0.2for x in range(number_assets)) #每个资产权重取值范围为0-0.2

# 设置初始权重
x0 = number_assets * [1 / number_assets]

# 规划求解
solution = sco.minimize(minus_sharpe,x0,method='SLSQP', bounds=bnds, constraints=con1)

# 求解出权重、组合收益率、标准差、夏普比率
final_weights = solution.x #权重
finanl_ratio = statistics(final_weights) #组合收益率、标准差、夏普比率

print(f'{final_weights[0]:.1%}投资于{data.columns[0]}{final_weights[1]:.1%}投资于{data.columns[1]},'
     f'{final_weights[2]:.1%}投资于{data.columns[2]}{final_weights[3]:.1%}投资于{data.columns[3]},'
     f'{final_weights[4]:.1%}投资于{data.columns[4]}{final_weights[5]:.1%}投资于{data.columns[5]},'
     f'组合收益率:{finanl_ratio[0]:.1%},组合标准差:{finanl_ratio[1]:.1%},组合夏普比率:{finanl_ratio[2]:.1%}')

结果如下:

18.5%投资于BMW,20.0%投资于ORACLE,20.0%投资于YOIGO,9.7%投资于SACYR,20.0%投资于BALAY,11.7%投资于APPLE,组合收益率:19.7%,组合标准差:22.3%,组合夏普比率:75.0%

(二)求解方差最小的投资组合

目标函数fun:方差最小化,即标准差最小化

约束条件constraints:权重之和=1

变量边界bounds:无

代码如下:

# 设置目标:方差最小
def min_std(x):
    return statistics(x)[1]

# 约束条件:权重之和=1
def constraint1(x):
    return np.sum(x) -1

con1 = {'type''eq''fun': constraint1} 

# 设置初始权重
x0 = number_assets * [1 / number_assets]

# 规划求解
solution = sco.minimize(min_std,x0,method='SLSQP',constraints=con1)

# 求解出权重、组合收益率、标准差、夏普比率
final_weights = solution.x #权重
finanl_ratio = statistics(final_weights) #组合收益率、标准差、夏普比率

print(f'{final_weights[0]:.1%}投资于{data.columns[0]}{final_weights[1]:.1%}投资于{data.columns[1]},'
     f'{final_weights[2]:.1%}投资于{data.columns[2]}{final_weights[3]:.1%}投资于{data.columns[3]},'
     f'{final_weights[4]:.1%}投资于{data.columns[4]}{final_weights[5]:.1%}投资于{data.columns[5]},'
     f'组合收益率:{finanl_ratio[0]:.1%},组合标准差:{finanl_ratio[1]:.1%},组合夏普比率:{finanl_ratio[2]:.1%}')

结果如下:

3.6%投资于BMW,10.1%投资于ORACLE,18.5%投资于YOIGO,3.4%投资于SACYR,56.0%投资于BALAY,8.4%投资于APPLE,组合收益率:14.9%,组合标准差:18.1%,组合夏普比率:65.9%

(三)求解方差最小的投资组合,组合收益率为30%

目标函数fun:方差最小化,即标准差最小化

约束条件constraints:1、权重之和=1;2、组合收益率=0.3

代码如下:

#设置目标:方差最小
def min_std(x):
    return statistics(x)[1]

# 约束条件1:权重之和=1
def constraint1(x):
    return np.sum(x) -1
# 约束条件2:组合收益=0.3
def constraint2(x):
    return statistics(x)[0]-0.3

con1 = {'type''eq''fun': constraint1} 
con2 = {'type''eq''fun': constraint2} 
cons = (con1,con2)

# 设置初始权重
x0 = number_assets * [1 / number_assets]

# 规划求解
solution = sco.minimize(min_std,x0,method='SLSQP',constraints=cons)

# 求解出权重、组合收益率、标准差、夏普比率
final_weights = solution.x #权重
finanl_ratio = statistics(final_weights) #组合收益率、标准差、夏普比率

print(f'{final_weights[0]:.1%}投资于{data.columns[0]}{final_weights[1]:.1%}投资于{data.columns[1]},'
     f'{final_weights[2]:.1%}投资于{data.columns[2]}{final_weights[3]:.1%}投资于{data.columns[3]},'
     f'{final_weights[4]:.1%}投资于{data.columns[4]}{final_weights[5]:.1%}投资于{data.columns[5]},'
     f'组合收益率:{finanl_ratio[0]:.1%},组合标准差:{finanl_ratio[1]:.1%},组合夏普比率:{finanl_ratio[2]:.1%}')

结果如下:

47.1%投资于BMW,66.5%投资于ORACLE,2.8%投资于YOIGO,22.3%投资于SACYR,-57.0%投资于BALAY,18.3%投资于APPLE,组合收益率:30.0%,组合标准差:42.9%,组合夏普比率:63.0%

(四)求解收益率最高的投资组合,组合标准差为40%

目标函数fun:组合收益率最大化

约束条件constraints:1、权重之和=1;2、组合标准差=0.4

代码如下:

# 设置目标:收益率最大化
def minus_return(x):
    return -statistics(x)[0]

# 约束条件1:权重之和=1
def constraint1(x):
    return np.sum(x) -1
# 约束条件2:组合标准差=0.4
def constraint2(x):
    return statistics(x)[1]-0.4

con1 = {'type''eq''fun': constraint1} 
con2 = {'type''eq''fun': constraint2} 
cons = (con1,con2)

# 设置初始权重
x0 = number_assets * [1 / number_assets]

# 规划求解
solution = sco.minimize(minus_return,x0,method='SLSQP',constraints=cons)

# 求解出权重、组合收益率、标准差、夏普比率
final_weights = solution.x #权重
finanl_ratio = statistics(final_weights) #组合收益率、标准差、夏普比率

print(f'{final_weights[0]:.1%}投资于{data.columns[0]}{final_weights[1]:.1%}投资于{data.columns[1]},'
     f'{final_weights[2]:.1%}投资于{data.columns[2]}{final_weights[3]:.1%}投资于{data.columns[3]},'
     f'{final_weights[4]:.1%}投资于{data.columns[4]}{final_weights[5]:.1%}投资于{data.columns[5]},'
     f'组合收益率:{finanl_ratio[0]:.1%},组合标准差:{finanl_ratio[1]:.1%},组合夏普比率:{finanl_ratio[2]:.1%}')

结果如下:

43.5%投资于BMW,61.8%投资于ORACLE,4.1%投资于YOIGO,20.8%投资于SACYR,-47.7%投资于BALAY,17.5%投资于APPLE,组合收益率:28.8%,组合标准差:40.0%,组合夏普比率:64.4%


原文始发于微信公众号(Python for Finance):Scipy库求解最优资产投资组合

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/45698.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!