Modern Portfolio Theory¶

Portfolio Risk and Return¶

Preparing Data¶

导入必要的库¶

In [1]:
import numpy as np
import pandas as pd
import tushare as ts
import matplotlib 
import joblib

用tushare pro_api下载原始数据¶

In [3]:
# 在tushare主页注册,获取token
pro = ts.pro_api(token='')
In [4]:
df = pro.daily(ts_code='600519.SH,000333.SZ,000001.SZ', start_date='20180101', end_date='20181231')
In [5]:
df
Out[5]:
ts_code trade_date open high low close pre_close change pct_chg vol amount
0 000001.SZ 20181228 9.31 9.46 9.31 9.38 9.28 0.10 1.0776 576604.00 541571.004
1 000333.SZ 20181228 36.75 37.40 36.31 36.86 36.80 0.06 0.1630 211676.03 782455.535
2 600519.SH 20181228 563.30 596.40 560.00 590.01 563.00 27.01 4.7975 63678.37 3705150.490
3 000001.SZ 20181227 9.45 9.49 9.28 9.28 9.30 -0.02 -0.2151 624593.27 586343.755
4 000333.SZ 20181227 37.91 38.06 36.80 36.80 37.13 -0.33 -0.8888 230747.45 864454.239
... ... ... ... ... ... ... ... ... ... ... ...
695 000333.SZ 20180103 56.56 57.25 55.42 55.80 56.38 -0.58 -1.0300 428368.33 2412127.948
696 600519.SH 20180103 701.50 721.40 699.74 715.86 703.85 12.01 1.7100 52019.41 3713523.701
697 000001.SZ 20180102 13.35 13.93 13.32 13.70 13.30 0.40 3.0100 2081592.55 2856543.822
698 000333.SZ 20180102 56.15 57.08 56.02 56.38 55.43 0.95 1.7100 329725.18 1866579.510
699 600519.SH 20180102 700.00 710.16 689.89 703.85 697.49 6.36 0.9100 49612.48 3482407.646

700 rows × 11 columns

提取三只股票的回报率¶

In [6]:
stk1 = df.loc[df.ts_code == '600519.SH',['ts_code','trade_date','pct_chg']]
stk2 = df.loc[df.ts_code == '000333.SZ',['ts_code','trade_date','pct_chg']]
stk3 = df.loc[df.ts_code == '000001.SZ',['ts_code','trade_date','pct_chg']]
In [7]:
stk3
Out[7]:
ts_code trade_date pct_chg
0 000001.SZ 20181228 1.0776
3 000001.SZ 20181227 -0.2151
6 000001.SZ 20181226 -0.4283
9 000001.SZ 20181225 -0.8493
12 000001.SZ 20181224 -0.3175
... ... ... ...
685 000001.SZ 20180108 -2.5600
688 000001.SZ 20180105 0.3800
691 000001.SZ 20180104 -0.6000
694 000001.SZ 20180103 -2.7000
697 000001.SZ 20180102 3.0100

243 rows × 3 columns

合并回报率¶

In [8]:
stk = pd.merge(stk1,stk2,on = 'trade_date')
stk = pd.merge(stk,stk3,on = 'trade_date')
In [9]:
stk
Out[9]:
ts_code_x trade_date pct_chg_x ts_code_y pct_chg_y ts_code pct_chg
0 600519.SH 20181228 4.7975 000333.SZ 0.1630 000001.SZ 1.0776
1 600519.SH 20181227 0.5214 000333.SZ -0.8888 000001.SZ -0.2151
2 600519.SH 20181226 -1.0092 000333.SZ -0.6688 000001.SZ -0.4283
3 600519.SH 20181225 -0.3891 000333.SZ -0.9539 000001.SZ -0.8493
4 600519.SH 20181224 0.1040 000333.SZ -0.4747 000001.SZ -0.3175
... ... ... ... ... ... ... ...
209 600519.SH 20180108 1.8600 000333.SZ -0.5200 000001.SZ -2.5600
210 600519.SH 20180105 0.1800 000333.SZ 1.1700 000001.SZ 0.3800
211 600519.SH 20180104 2.9600 000333.SZ 2.6700 000001.SZ -0.6000
212 600519.SH 20180103 1.7100 000333.SZ -1.0300 000001.SZ -2.7000
213 600519.SH 20180102 0.9100 000333.SZ 1.7100 000001.SZ 3.0100

214 rows × 7 columns

计算期望回报率¶

In [10]:
stk_return = []
stk_return.append(stk.pct_chg_x.mean())
stk_return.append(stk.pct_chg_y.mean())
stk_return.append(stk.pct_chg.mean())
In [11]:
stk_return
Out[11]:
[-0.018102336448598117, -0.1510565420560747, -0.18671261682243007]

计算波动率¶

In [12]:
stk_risk = []
stk_risk.append(stk.pct_chg_x.var())
stk_risk.append(stk.pct_chg_y.var())
stk_risk.append(stk.pct_chg.var())
stk_risk=list(np.sqrt(stk_risk))
In [13]:
stk_risk
Out[13]:
[2.152815303401083, 2.4165597834086348, 2.014982759273316]

保存数据¶

In [14]:
joblib.dump(df,'stock_raw.pkl')
joblib.dump(stk_return,'stk_return.pkl')
joblib.dump(stk_risk,'stk_risk.pkl')
Out[14]:
['stk_risk.pkl']

Two Risky Assets¶

生成数据¶

In [15]:
rho=.4
w1=[0.01*n for n in range(101)]
portfolio_return=[w*stk_return[0]+(1-w)*stk_return[1] for w in w1]
portfolio_risk=[np.sqrt(w**2*stk_risk[0]**2+2*rho*w*(1-w)*stk_risk[0]*stk_risk[1]+(1-w)**2*stk_risk[1]**2)
                for w in w1]

设置绘图环境¶

In [16]:
%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')
In [17]:
fig = plt.figure()
ax = plt.axes()
ax.scatter(portfolio_risk, portfolio_return)
Out[17]:
<matplotlib.collections.PathCollection at 0x1e60d1baee0>

Three Risky Assets¶

生成权向量¶

In [18]:
w1=[0.001*n for n in range(1001)]
w=[[w, .001*n, 1-w-.001*n] for n in range(1001) for w in w1 if w+.001*n<=1]

生成收益率向量与方差协方差矩阵¶

In [19]:
ret=stk.loc[:,['pct_chg_x','pct_chg_y','pct_chg']].mean().to_numpy()
cov=stk.loc[:,['pct_chg_x','pct_chg_y','pct_chg']].cov().to_numpy()

计算组合收益与波动率¶

In [20]:
portfolio_return=[]
portfolio_risk=[]
for weight in w:
    #w=np.array([w1[n],w2[n],w3[n]])
    ww=np.array(weight)
    portfolio_return.append(ww.dot(ret.T))
    portfolio_risk.append(np.sqrt(ww.dot(cov).dot(ww.T)))

设置绘图环境¶

In [21]:
%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')
In [22]:
fig = plt.figure()
ax = plt.axes()
ax.scatter(portfolio_risk, portfolio_return)
Out[22]:
<matplotlib.collections.PathCollection at 0x1e60d91cb50>

Diversification¶

导入必要的库¶

In [23]:
import random

导入数据¶

In [24]:
df=pd.read_csv('data/TRD_Dalyr.csv',sep='\t')
df[-5:]
Out[24]:
Stkcd Trddt Opnprc Hiprc Loprc Clsprc Dretwd
839588 900957 2018-12-24 0.623 0.633 0.622 0.628 0.008026
839589 900957 2018-12-25 0.610 0.626 0.607 0.621 -0.011146
839590 900957 2018-12-26 0.630 0.630 0.617 0.620 -0.001610
839591 900957 2018-12-27 0.631 0.635 0.613 0.617 -0.004839
839592 900957 2018-12-28 0.612 0.623 0.612 0.616 -0.001621

提取股票代码¶

In [25]:
tic_vec=df.Stkcd.unique()
tic_vec=pd.DataFrame(tic_vec,columns=['tic'])
tic_vec.shape
Out[25]:
(3669, 1)

设定实验参数¶

In [26]:
n=50
sample_size=1000
x=np.linspace(1,n,n)
y=[]

生成数据¶

In [27]:
y=[]
for i in x:
    z=[]
    #smpl=pd.DataFrame({'Trddt':[],'Dretwd':[]})
    j=0
    while j < sample_size:
        # j-th sampling
        smpl_tic=tic_vec.sample(int(i),replace=True)
        smpl=pd.DataFrame({'Trddt':[],'Dretwd':[]})
        k=0
        while k<i:
            smpl=smpl.merge(df[['Trddt','Dretwd']][df.Stkcd==smpl_tic.tic.iloc[k]],how='outer',on='Trddt')
            k+=1
        smpl.fillna(0)
        z.append(np.std(smpl.mean(axis=1,numeric_only=True)))
        j+=1
        #smpl.pivot_table()
    y.append(np.mean(z))

导入必要的库,绘图¶

In [28]:
%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')
In [29]:
fig = plt.figure()
ax = plt.axes()
ax.plot(x, y);