最优投资组合构建问题,Python实现

本文介绍了在已知预期收益率和协方差矩阵的情况下,如何利用Python进行投资组合优化,目标是最大化夏普比率。通过scipy.optimize库的SLSQP方法解决约束优化问题,找到权重分配以最小化波动率或最大化收益风险比。
摘要由CSDN通过智能技术生成

本文记录在可投资集已知预期收益率和预期协方差矩阵的条件下,使用程序工具求解最优投资组合的方法。

问题描述

构建最优投资组合是一个带约束的优化问题,优化目标是最大化投资组合的夏普比率,而约束是资产权重相加等于1。

Python实现

# construct optimized portfolio
import numpy as np
import pandas as pd
import scipy.optimize as sco

fcst_style_sharpe = pd.read_csv('fcst_style_sharpe.csv')
style_cov = pd.read_csv('style_cov.csv')

selected_col = ['mkt','smb','hml','vmg','rmw','gms','pmo','mom']
noa = len(selected_col)

style_ret = fcst_style_sharpe['fcst_ret'#* 100

weights = np.random.random(noa)
weights /= np.sum(weights)


def port_ret(weights):
    return np.sum(style_ret * weights) * 252

def port_vol(weights):
    return np.sqrt(np.dot(weights.T, np.dot(style_cov * 252, weights)))

def min_func_sharpe(weights):
    return -port_ret(weights) / port_vol(weights)
    
# maximize sharpe ratio
eweights = np.array(noa * [1. / noa,])
#bnds = tuple((0, 1) for x in range(noa))
bnds = tuple((-22for x in range(noa))
cons = ({'type''eq''fun'lambda x:  np.sum(x) - 1})

opts = sco.minimize(min_func_sharpe, eweights,
                    method='SLSQP', bounds=bnds,
                    constraints=cons)

opt_weight = opts['x']
opt_weight.round(4)

opts_sharpe = port_ret(opt_weight) / port_vol(opt_weight)
opts_sharpe

# plot the optimized portfolio
from lets_plot import *
LetsPlot.setup_html()

fzoo = pd.read_csv('data/fzoo.csv')

opt_style = fzoo[['trading_date','mkt']].copy()
opt_style.columns = ['trading_date','style']
opt_style['style'] = np.dot(fzoo[selected_col],opt_weight)
opt_style['style_cum'] = np.log1p(opt_style['style']/100).cumsum()

x = pd.to_datetime(opt_style['trading_date'])[-1000:]
y = opt_style['style_cum'][-1000:]/opt_style['style_cum'].iloc[-1000]
ggplot({'date': x, 'port': y}, aes(x='date', y='port')) + geom_line()

# minimize volatility
optv = sco.minimize(port_vol, eweights,
                    method='SLSQP', bounds=bnds,
                    constraints=cons)

bnds = tuple((01for x in weights)

cons = ({'type''eq''fun'lambda x:  port_ret(x) - tret},
        {'type''eq''fun'lambda x:  np.sum(x) - 1})

%time
trets = np.linspace(0.050.5100)
tvols = []
for tret in trets:
    res = sco.minimize(port_vol, eweights, method='SLSQP',
                       bounds=bnds, constraints=cons)
    tvols.append(res['fun'])
tvols = np.array(tvols)

# plot the front
from pylab import mpl, plt
plt.style.use('seaborn-v0_8-whitegrid')
mpl.rcParams['font.family'] = 'serif'
%matplotlib inline

prets = []
pvols = []
for p in range (5000):
    weights = np.random.random(noa)
    weights /= np.sum(weights)
    prets.append(port_ret(weights))
    pvols.append(port_vol(weights))
prets = np.array(prets)
pvols = np.array(pvols)


plt.figure(figsize=(106))
plt.scatter(pvols, prets, c=prets / pvols,
            marker='o', cmap='coolwarm')
plt.xlabel('expected volatility')
plt.ylabel('expected return')
plt.colorbar(label='Sharpe ratio');

tvols = np.array(tvols)

plt.figure(figsize=(106))
plt.scatter(pvols, prets, c=prets / pvols,
            marker='.', alpha=0.8, cmap='coolwarm')
plt.plot(tvols, trets, 'b', lw=4.0)
plt.plot(port_vol(opts['x']), port_ret(opts['x']),
         'y*', markersize=15.0)
plt.plot(port_vol(optv['x']), port_ret(optv['x']),
         'r*', markersize=15.0)
plt.xlabel('expected volatility')
plt.ylabel('expected return')
plt.colorbar(label='Sharpe ratio')


本文由 mdnice 多平台发布

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值