投资组合的有效边界及基于目标函数的组合优化

##导入数据
data2=pd.read_csv('data2.csv', encoding='gbk', index_col='Dates')
data2.index=[dt.datetime.strptime(x,'%Y/%m/%d') for x in data2.index]

#计算股票收益率
log_returns=np.log(data2.pct_change()+1)

##计算不同权重状态下的股票组合预期收益率和波动率,用于出不同权重状态下股票组合的收益波动分布图
number = 10000 #10000组权重
stock_num=len(log_returns.columns)#股票数量
weights=np.random.rand(number, stock_num)
weights/=np.sum(weights, axis = 1).reshape(number,1) #注意这里一定要加reshape,使得除数的size属性完备
pret=np.dot(weights, log_returns.mean())*252#股票组合的预期年化收益率
pvol=np.diag(np.sqrt(np.dot(weights,np.dot(log_returns.cov()*252,weights.T))))#股票组合的预期年化波动率

plt.figure(figsize=(10,6))
plt.scatter(pvol,pret,c=pret/pvol,marker='o')
plt.xlabel('预期波动率')
plt.ylabel('预期收益率')
plt.grid(True)
plt.colorbar(label='夏普比率')

##优化计算
import scipy.optimize as sco
##编写目标变量的计算函数(3个) 用于之后求解夏普率最大化,风险最小化,收益最大化的目标组合
def statistics(weights):
    weights=np.array(weights)
    pret=np.dot(weights, log_returns.mean())*252#股票组合的预期年化收益率
    pvol=np.sqrt(np.dot(weights.T,np.dot(log_returns.cov()*252,weights)))#股票组合的预期年化波动率
    return np.array([pret, pvol, pret/pvol])

 ###求解夏普率最大的组合权重
 ###定义最大化SharpRatio的目标函数
def min_neg_sharp(weights):
    return -1*statistics(weights)[2]

#编写优化的约束条件,minimize函数的约定表达如下
cons=({'type':'eq','fun': lambda x: np.sum(x)-1})#约束是所有参数(权重)的总和为1。
bnd=tuple((0,1) for i in range(stock_num))##我们还将参数值(权重)限制在0和1之间。这些值以多个元组组成的一个元组形式提供给最小化函数

#调用minimize函数进行最优化求解
opts_maxSharpRatio = sco.minimize(min_neg_sharp, stock_num*[1/stock_num], method='SLSQP', bounds=bnd, constraints=cons)#  N*[1/N]表示复制N个一维list #'SLSQP'表示Sequential Least SQuares Programming序贯最小二乘规划
print(opts_maxSharpRatio['x'].round(3))#求得优化后组合的权重
print(statistics(opts_maxSharpRatio['x'])) #优化后组合的预期收益率,预期波动率,及SharpRatio

##求解波动率最小化的组合权重
#定义目标函数
def min_vol(weights):
    return statistics(weights)[1]

opts_minVolatility = sco.minimize(min_vol, stock_num*[1/stock_num], method='SLSQP',bounds=bnd, constraints=cons)
print(opts_minVolatility['x'].round(3))
print(statistics(opts_minVolatility['x']))


##求解最大预期收益的组合权重
def min_neg_pret(weights):
    return -statistics(weights)[0]
opts_maxReturn=sco.minimize(min_neg_pret, stock_num*[1/stock_num], method='SLSQP', bounds=bnd, constraints=cons)
print(opts_maxReturn['x'].round(3))
print(statistics(opts_maxReturn['x']))

##构建有效边界组合
trets=np.linspace(0.04,0.15,50)
tvols=[]

for trets_i in trets:
    cons1=({'type':'eq','fun': lambda x: np.sum(x)-1},{'type':'eq','fun': lambda x: statistics(x)[0]-trets_i})#约束是所有参数(权重)的总和为1,且预期收益等于目标收益
    res=sco.minimize(min_vol,stock_num*[1/stock_num], method='SLSQP', bounds=bnd, constraints=cons1)
    tvols.append(res['fun'])
tvols=np.array(tvols)

##作图
plt.figure(figsize=(10,6))
plt.scatter(pvol, pret, marker='o', c=pret/pvol)
plt.scatter(tvols, trets,marker='x',c=trets/tvols, label='有效边界')
plt.plot(statistics(opts_maxSharpRatio['x'])[1],statistics(opts_maxSharpRatio['x'])[0],marker='*',markersize=15,label='最大夏普率组合')
plt.plot(statistics(opts_minVolatility['x'])[1],statistics(opts_minVolatility['x'])[0],marker='*',markersize=15,label='最小方差组合')
plt.plot(statistics(opts_maxReturn['x'])[1],statistics(opts_maxReturn['x'])[0],marker='*',markersize=15,label='最大收益组合')
plt.grid(True)
plt.colorbar(label='夏普率')
plt.xlabel('预期波动率')
plt.ylabel('预期收益率')
plt.legend()

投资组合的有效边界及基于目标函数的组合优化_第1张图片

基于《Python与量化投资 从基础到实战》内容的练习

你可能感兴趣的:(投资组合的有效边界及基于目标函数的组合优化)