1. 程式人生 > >投資組合分析基礎1

投資組合分析基礎1

多股票策略回測時常常遇到問題。
倉位如何分配?
其實,這個問題,好多好多年前馬科維茨(Markowitz)我喜愛的小馬哥就給出答案——投資組合理論。
根據這個理論,我們可以對多資產的組合配置進行三方面的優化。

1.找到有效前沿。在既定的收益率下使組合的方差最小。

2.找到sharpe最優的組合(收益-風險均衡點)

3.找到風險最小的組合

該理論基於用均值和方差來表述組合的優劣的前提。將選取幾隻股票,用蒙特卡洛模擬初步探究組合的有效前沿。
通過最大Sharpe和最小方差兩種優化來找到最優的資產組合配置權重引數。
最後,刻畫出可能的分佈,兩種最優以及組合的有效前沿。

1)選取A股所有股票2018年的EOD資料(資料事先已經下載好)

import pandas as pd
import numpy as np
data=pd.read_csv(r'C:\Users\yi\Desktop\Study\量化交易\stock2018.csv',sep=',',engine ='python')

檢視DataFrame資訊:
在這裡插入圖片描述
畫一隻股票的圖形看看:

#切出需要的欄位
EOD=data.iloc[:,[0,1,6]].sort_values('trade_date')
#按股票程式碼分組
stock=EOD.groupby(['ts_code'])
#取出'000063.SH'組的資料
zte=stock.get_group(['000063.SH'])
zte.plot('trade_date','close',figsize=(25,15))

在這裡插入圖片描述

stock_means=pd.DataFrame(columns=['ts_code', 'returnmean'])
j=0
for i in stock.nunique().index:
    if j>10:
        break
    #取程式碼為i的股票的close資料
    sclose=stock.get_group(i)['close']
    #計算對數收益
    returns = np.log(sclose / sclose.shift(1))  
     #計算年化對數收益
    returnmean=returns.mean()*252
    #將所有股票的年化對數收益寫入列表
    transit=pd.DataFrame({'ts_code':[0], 'returnmean':[0]})
    transit['ts_code']=i
    transit['returnmean']=returnmean
    stock_means=stock_means.append(transit,ignore_index=True)
    print('code=%s returnmean=%s'%(i,returnmean))
    #returns.hist(bins=50, figsize=(12, 9))
    j+=1

在這裡插入圖片描述
畫出這12只股票的收益直方圖,可以看出大體是正態分佈.
去掉計數器j,對所有股票跑一邊,得到stock_means資料:

stock_means.describe()
Out[69]: 
        returnmean
count  3556.000000
mean     -0.373557
std       1.111227
min     -26.589527
25%      -0.573231
50%      -0.381268
75%      -0.195562
max      24.007412

我去,簡直坑死人,2018年所有股票的平均指數收益率是-0.373557,-0.195562的成績就已經跑贏了75%的股票~就問你坑不坑?
我們看看最坑的和最牛的5個都是誰:

 stock_means.sort_values('returnmean').head(5)
Out[74]: 
        ts_code  returnmean
536   002075.SZ  -26.589527
244   000693.SZ  -12.881314
2184  600086.SH   -8.144002
1195  002739.SZ   -7.548460
608   002147.SZ   -7.318664

stock_means.sort_values('returnmean').tail(5)
Out[75]: 
        ts_code  returnmean
2972  601162.SH   13.214315
2115  300751.SZ   15.765417
3001  601319.SH   23.970533
3226  603220.SH   23.990517
2043  300674.SZ   24.007412

年度最坑獎:沙鋼股份
年度最牛獎:沒有評的意義,基本全是新股,看來市場還是相當不理性的

*注:全部程式碼

import pandas as pd
import numpy as np
data=pd.read_csv(r'D:\Study\stock2018.csv',sep=',',engine ='python')
EOD=data.set_index(['trade_date'],drop=True).drop(['pre_close','change','pct_change','trade_date.1'],axis=1).sort_index()
p_close=EOD['close']
#EOD.pivot_table(index='ts_code',values=['open','high','low','close'],aggfunc=(np.log(p_close/p_close.shift(1)).mean))
EODG=EOD.groupby(['ts_code'])
j=0
lreturn_list=pd.DataFrame()
for i in EODG.groups.keys():
    pclose=EODG.get_group(i)['close']
    stock_code=i
    log_return=np.log(pclose/pclose.shift(1))
    lr=pd.DataFrame({'log_return':log_return})
    log_return_mean=log_return.mean()*len(log_return)
    transit=pd.DataFrame({'ts_code':[i],'log_return_mean':[log_return_mean]})
    if j==0:
        lreturn_mean=transit
    else:
        lreturn_mean=lreturn_mean.append(transit)
    lreturn_list[i]=log_return
    #print ('stock %s :log return is %s'%(i,log_return))
    print ('%s/%s stock %s :mean log return is %s'%(len(EODG.groups.keys()),j+1, i,log_return_mean))
    j=j+1
    #if j>2000:
    #    break
cov_dual_stock=pd.DataFrame()
a=0
for st1 in lreturn_list.columns:
    for st2 in lreturn_list.columns:
        if st1!=st2:
            cov2=lreturn_list.loc[:,[st1,st2]].cov()*len(log_return)
            print(cov2)
            cov_dual_stock=cov_dual_stock.append(cov2)
            a+=1
            if a>10:
                break