import pandas as pd
import numpy as np
from pylab import mpl
mpl.rcParams['font.sans-serif']=['Microsoft YaHei']
# 导入tushare
import tushare as ts
# 初始化pro接口
pro = ts.pro_api('f947555218dc693f775eb197f88714e1a8758b46f5ea63d138c4ec6a')
# 拉取数据
df = pro.daily(**{
"ts_code": "002761.SZ , 000736.SZ , 600502.SH, 002062.SZ",
"trade_date": "",
"start_date": 20220101,
"end_date": 20220511,
"offset": "",
"limit": ""
}, fields=[
"ts_code",
"trade_date",
"open",
"high",
"low",
"close",
"pre_close",
"change",
"pct_chg",
"vol",
"amount"
])
print(df)
df.set_index('ts_code',inplace = True)
df1 = df[['close','trade_date']].reset_index() #让索引重置
data= df1.pivot(index = 'trade_date',
columns = 'ts_code',
values= 'close')
(data / data.iloc[0] * 100).plot(figsize=(10, 5))
R=np.log(data/data.shift(1)) #按照对数收益率的计算公式得到股票收益率
R=R.dropna() #删除缺省的数据
R.describe()
R.hist(bins=40,figsize=(10,10)) #将股票收益率按照直方图方式展示
#%%
#计算各类数据
R_mean=R.mean()*252 #计算股票的年化平均收益率
print(R_mean)
R_cov=R.cov()*252 #计算股票的协方差矩阵并且年化处理
print(R_cov)
R_corr=R.corr() #计算股票的相关系数矩阵
print(R_corr)
R_vol=R.std()*np.sqrt(252) #计算股票收益率的年化波动率
print(R_vol)
#随机生成权重
weights = np.array([0.25,0.25,0.25,0.25])
R_port=np.sum(weights*R_mean) #计算投资组合的预期收益率
print('投资组合的预期收益率:',round(R_port,4))
vol_port=np.sqrt(np.dot(weights,np.dot(R_cov,weights.T))) #计算投资组合收益波动率
print('投资组合收益波动率',round(vol_port,4))
#%%
rp=[]#收益率
vp=[]#波动率
for i in np.arange(2000):#随机生成2000组配置比例数据
x=np.random.random(4)
weights=x/sum(x) #每支股票的权重计算
rp.append(np.sum(weights*R_mean)) #计算组合的收益率
vp.append(np.sqrt(np.dot(weights,np.dot(R_cov,weights.T))))#计算组合的波动率
from matplotlib import pyplot as plt
plt.figure(figsize=(10,8))
plt.scatter(vp,rp)
plt.title(u'投资组合收益率与波动率关系',fontsize=12)
plt.xlabel(u'波动率')
plt.ylabel(u'组合收益率',rotation=90)
plt.grid('True')
plt.show()
#%%
import scipy.optimize as sco
#定义一个求配置比例的函数
def pzbl(w):
w=np.array(w)
rp=np.sum(w*R_mean)
vp=np.sqrt(np.dot(w,np.dot(R_cov,w.T)))
return np.array([rp,vp])
#定义一个得到最小波动率的函数
def vpmin(w):
return pzbl(w)[1]
m=len(R_mean)*[1.0/len(R_mean),] #生成权重相等的数组
cons=({'type':'eq','fun':lambda x:np.sum(x)-1},{'type':'eq','fun':lambda x:pzbl(x)[0]-0.15})#两个约束条件
bnds=tuple((0,1) for x in range(len(R_mean)))#权重的边界
result=sco.minimize(vpmin,m,method='SLSQP',bounds=bnds,constraints=cons)
result
cons_min={'type':'eq','fun':lambda x:np.sum(x)-1}
result1=sco.minimize(vpmin,m,method='SLSQP',bounds=bnds,constraints=cons_min)
rp_min=np.sum(R_mean*result1['x'])
vp_min=result1['fun']
print('波动率在可行集是全局最小值时的投资组合预期收益率',round(rp_min,4))
print('在可行集是全局最小的波动率',round(vp_min,4))
t=np.linspace(rp_min,0.3,100) #收益率从最低到30%,生成100个收益率
v=[]
for i in t:
cons=({'type':'eq','fun':lambda x:np.sum(x)-1},{'type':'eq','fun':lambda x:pzbl(x)[0]-i})
result=sco.minimize(vpmin,m,method='SLSQP',bounds=bnds,constraints=cons)
v.append(result['fun'])
plt.figure(figsize=(10,8))
plt.scatter(vp,rp)
plt.plot(v,t,'r-',label=u'有效前沿',lw=2)
plt.plot(vp_min,rp_min,'y*',label=u'全局最小波动率',markersize=14)
plt.xlabel(u'波动率',fontsize=12)
plt.ylabel(u'收益率',fontsize=12,rotation=90)
plt.title(u'投资组合的有效前沿',fontsize=14)
plt.legend(fontsize=12)
plt.grid('True')
plt.show()
为什么有效上沿的图是这样的