投資組合分析基礎1
阿新 • • 發佈:2019-01-02
多股票策略回測時常常遇到問題。
倉位如何分配?
其實,這個問題,好多好多年前馬科維茨(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