はじめに
TOPIX500構成銘柄を対象に,最適なポートフォリオを構築することを考えてみます.
TOPIX500は東証市場第一部銘柄の中から時価総額及び流動性の高い500銘柄で構成される指数であり,東証市場第一部時価総額の約90パーセント弱をカバーしています.そのため,日本のほとんどの大手企業が含まれていると言えます.
株式投資は債券などに比べ値動きが激しいのが特徴です.複数の銘柄をうまく組み合わせてポートフォリオつくり資産運用することで,リスクを抑えながらリターンを得ることができます.
今回はTOPIX500構成銘柄の2銘柄に投資する場合,
どの銘柄にどんな比率で投資すればリスクを抑えながら収益が得られるかを検証してみました.
1銘柄投資の収益とリスク
まず,TOPIX500を構成する全銘柄について,収益率の期待値(平均値)と分散を計算すると,以下の結果が得られます.収益率は1日ごとに計算しています.
各点は各銘柄の収益率の期待値と分散を示しています.したがって,500個の赤点があります.
赤色の濃さはシャープ・レシオ(期待値÷標準偏差)の値を表します.この値はリスクの大きさに比べてどれだけ収益率を得られるか,投資効率の高さを示します.ここで,リスクは値動きの大きさのことを指し,分散や標準偏差をリスクと呼んでいます.
今回の検証では2019年1月~2021年2月における株価の時系列データを使用しています.
TOPIX500構成銘柄のうち,最もシャープ・レシオが高い銘柄を表にまとめました.
順位 | 証券コード | 銘柄名 | シャープレシオ | 収益率の期待値 | 分散 |
---|---|---|---|---|---|
1 | 6920 | レーザーテック | 0.158 | 0.503 | 10.172 |
2 | 2413 | エムスリー | 0.148 | 0.381 | 6.621 |
3 | 3635 | コーエーテクモホールディングス | 0.125 | 0.265 | 4.488 |
4 | 8035 | 東京エレクトロン | 0.115 | 0.270 | 5.532 |
5 | 3038 | 神戸物産 | 0.113 | 0.279 | 6.088 |
6 | 9697 | カプコン | 0.107 | 0.262 | 5.940 |
7 | 6976 | 太陽誘電 | 0.107 | 0.316 | 8.710 |
8 | 4519 | 中外製薬 | 0.106 | 0.198 | 3.433 |
9 | 4686 | ジャストシステム | 0.106 | 0.291 | 7.474 |
10 | 4062 | イビデン | 0.105 | 0.277 | 7.024 |
2銘柄分散投資の効果
次に,2銘柄分散投資の効果を東京エレクトロンと神戸物産を例に説明します.
東京エレクトロンに$x$,神戸物産$y$の比率で,$x+y=1$となるように投資するとします.$x$と$y$の銘柄の組み合わせごとに,収益率の期待値と分散を計算すると,以下の結果が得られます.
この結果から,2銘柄に投資することで,リスク(分散)を下げることができるとわかります.東京エレクトロンに0.48,神戸物産に0.52の比率で投資したとき,リスクが最小になります.
以下の表に,東京エレクトロンのみへ投資,神戸物産のみへ投資,東京エレクトロンに0.48,神戸物産に0.52の比率で投資した場合の収益率の期待値と分散,シャープ・レシオをまとめました.
投資比率 | 収益率の期待値 | 収益率の分散 | シャープ・レシオ |
---|---|---|---|
東京エレク(1) 神戸物産(0) |
0.27 | 5.53 | 0.11 |
東京エレク(0) 神戸物産(1) |
0.28 | 6.09 | 0.11 |
東京エレク(0.48) 神戸物産(0.52) |
0.274 | 3.398 | 0.149 |
このように,2銘柄に投資することで,各銘柄に単独投資するときよりもリスクを下げることができます.このとき,2銘柄に分散投資しても期待値はほぼ同じなので,投資の効率の高さを示すシャープレシオは高くなっています.また,東京エレクトロンと神戸物産はどちらもほぼ同じ収益率の期待値なので,2銘柄に分散投資しても収益率の期待値は変わりません.
したがって,収益率の期待値はほぼ一定で,リスクを下げることができたので,シャープレシオは高くなります.このように,投資先を選ぶときは、投資したい銘柄が1つ決まってもすぐに投資するのではなく、その銘柄と同時に投資することでリスクを抑えられる銘柄をさがすことも重要です.
TOPIX500構成銘柄ではどの2銘柄を選ぶのが最適か?
今度はTOPIX500構成銘柄中で,どの2銘柄を選び,どんな比率で投資するのが最適かを探していきます.
東京エレクトロンと神戸物産の例と同様な方法で,500銘柄すべての組み合わせについて,収益率の期待値と分散について計算すると,以下の結果が得られます.
各投資の組み合わせのうち,最もシャープ・レシオが高い銘柄を表にまとめました.
順位 | 投資先(投資比率) | シャープレシオ | 収益率の平均 | 分散 |
---|---|---|---|---|
1 |
レーザーテック(0.475) エムスリー(0.53) |
0.188 | 0.439 | 5.437 |
2 | レーザーテック(0.495) コーエーテクモホールディングス(0.505) |
0.181 | 0.383 | 4.480 |
3 | レーザーテック(0.576) 神戸物産(0.424) |
0.176 | 0.343 | 4.449 |
4 | レーザーテック(0.515) 中外製薬(0.485) |
0.176 | 0.408 | 5.395 |
5 | レーザーテック(0.495) カプコン(0.505) |
0.175 | 0.355 | 4.142 |
... | ... | ... | ... | ... |
20 | エムスリー(0.657) 太陽誘電(0.343) |
0.166 | 0.358 | 4.678 |
... | ... | ... | ... | ... |
24 | エムスリー(0.596) 東京エレクトロン(0.404) |
0.165 | 0.336 | 4.160 |
... | ... | ... | ... | ... |
31 | エムスリー(0.556) コーエーテクモホールディングス(0.444) |
0.163 | 0.329 | 4.064 |
... | ... | ... | ... | ... |
258 | 東京エレクトロン(0.434) コーエーテクモホールディングス(0.566) |
0.150 | 0.267 | 3.184 |
... | ... | ... | ... | ... |
この結果から,レーザーテックに0.475,エムスリーに0.53の比率で投資するときが最も効率の良い投資が実現できそうだと言えます.このときのシャープレシオの大きさは0.188であり,単独投資では実現できないような値の大きさとなっています.
ランキング上位にはレーザーテックやエムスリーが投資先として含まれているので,様々な結果を載せるために表では一部結果を省略しています.
おわりに
今回はTOPIX500構成銘柄の2銘柄に投資するとき,どの銘柄にどんな比率で投資すればリスクを抑えながら収益が得られるかを検証してみました.
その結果,レーザーテックに0.475,エムスリーに0.53の比率で投資したときがリスクに対して最も収益が得られることがわかりました.このときの投資効率の高さ(シャープレシオ)は1銘柄投資では実現できなかった値の高さとなりました.
今回はシャープレシオの値を見て最適な投資先と投資比率を決定しました.リスクに対する収益率のみを重視する投資家にはこの結果がそのまま生かせるでしょう.しかし,投資家によって,許容できるリスクが異なります.リスク許容度が低い投資家にとっては,いくらシャープレシオが高くてもリスクが高ければ適切な投資先と言えません.よって,許容できるリスクの範囲を設定した上で同様な検証を行うことが必要でしょう.このことは以前書いた記事(日経225全銘柄の投資効率を検証)に詳しく書いてありますので,気になる方はご覧いただけると幸いです.また2銘柄分散投資の収益率の期待値や分散の詳しい計算方法は,以前書いた記事(分散投資でリスク回避の仕方【2銘柄編】)が参考になると思います.
最後に,1銘柄投資,2銘柄投資に続き,3銘柄投資を考える場合には投資商品を分散しリスクを最小化する【3銘柄編】で紹介した3銘柄分散投資の収益率の期待値や分散の計算方法を使って今回と同様な検証が可能です.もしかすると,2銘柄では得られなかった最適な投資先と投資比率がみつかるかもしれません.気になる方は是非検証してみてはいかがでしょうか.
<過去記事> ・[投資タイミングを判断するときに必ず見てほしい指標RSIをデータ分析](https://qiita.com/MandT500/items/37c2d357e89ca6354d13) ・[日経平均株価が上がった次の日に上がる銘柄を見つけたい](https://qiita.com/MandT500/items/55c73b9d46aa39083d1c) ・[どの暗号資産が効率よく稼げるか](https://qiita.com/MandT500/items/53c2ff8f48592429effc) ・[1株1千円以下の価格変動が大きい銘柄に投資してパフォーマンスをあげる](https://qiita.com/MandT500/items/280cd7dc9ca50108cd8d) ・[コロナ・ショック後から株価上昇し続けている15銘柄](https://qiita.com/MandT500/items/ede92d7c322d0bbf32dd)付録(分析プログラム)
自作の関数や株価データの取得は後日,別の記事にまとめる予定です.今回の記事ではデータの取得方法は省略します.
2銘柄分散投資の効果
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
stock1='8035.T'
stock2='3038.T'
csv_file1 = './trade_package/data/price/' + stock1 + '.csv'
csv_file2 = './trade_package/data/price/' + stock2 + '.csv'
# 全銘柄の株価データを読み込み
start_time = '2019-01-01'
df1 = pd.read_csv(csv_file1, index_col=0)['Close'][start_time:]
df2 = pd.read_csv(csv_file2, index_col=0)['Close'][start_time:]
df = pd.concat([df1, df2], axis=1)
df.columns= [stock1, stock2]
#print(df)
# 収益率の計算
df_returns = (df-df.shift(1))/df.shift(1)*100
# 収益率の分散,平均,共分散
ave = df_returns.mean()
var = df_returns.var()
print('Average:'); print(ave)
print('Variance:'); print(var)
print('Covariance:\n', df_returns.cov().loc[stock1,stock2])
# データを生成
E = [x*ave[stock1]+(1-x)*ave[stock2] for x in np.linspace(0, 1, 100)]
V = [x**2*var[stock1]+2*x*(1-x)*df_returns.cov().loc[stock1,stock2]+(1-x)**2*var[stock2] for x in np.linspace(0, 1, 100)]
fig = plt.figure(figsize=(8,4))
plt.rcParams["font.size"] = 18
# 放物線描画
plt.plot(V,E)
# 点追加
plt.ylim(0, 0.5)
plt.xlim(0,13)
plt.plot([V[V.index(min(V))]], [E[V.index(min(V))]], 'o', c='orange')
plt.plot([V[0]], [E[0]], 'o', c='r')
plt.plot([V[-1]], [E[-1]], 'o', c='g')
# タイトル設定
plt.title('東京エレクトロンと神戸物産へ分散投資', fontname="MS Gothic")
# 軸ラベル設定
plt.ylabel('期待値(E)', fontname="MS Gothic")
plt.xlabel('分散(V)', fontname="MS Gothic")
# テキスト追加
plt.text(V[V.index(min(V))]-2.5, E[V.index(min(V))]+0.025,
' 東エレク:神戸物産\n$=${}:{}'.format(round(1-V.index(min(V))/100,3),V.index(min(V))/100),
fontname="MS Gothic",c='orange')
plt.text(V[0], E[0]+0.02,'東エレク:神戸物産$=$0:1',fontname="MS Gothic",c='r')
plt.text(V[-1], E[-1]-0.05,'東エレク:神戸物産$=$1:0',fontname="MS Gothic",c='g')
## TOPIX500構成銘柄への2銘柄分散投資
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import trade_package.get as get
import matplotlib.cm as cm
import itertools
# 時系列データの期間を設定
start_time = '2019-01-01'
# TOPIX500銘柄リスト
list_stock_name = get.topix500()
print('Calculation Return...')
# 株価時系列データフレームと収益率の計算
df = pd.DataFrame()
for stock in list_stock_name.code:
csv_file = './trade_package/data/price/' + stock + '.csv'
df_new = pd.read_csv(csv_file, index_col=0)['Close'][start_time:]
df_new.name = stock
df = pd.concat([df, df_new], axis=1)
df_returns = (df-df.shift(1))/df.shift(1)*100
# 収益率の分散,平均,共分散
ave = df_returns.mean()
var = df_returns.var()
cov = df_returns.cov()
# 2銘柄投資のポートフォリオの収益率の期待値と分散を計算
print('Calculation E-V...')
data_E = []; data_V = []
split = 30
for stock1, stock2 in itertools.combinations(list_stock_name.code, 2):
data_E += [x*ave[stock1] +(1-x)*ave[stock2] for x in np.linspace(0, 1, split)]
data_V += [x**2*var[stock1] + (1-x)**2*var[stock2] + 2*x*(1-x)*cov.loc[stock1, stock2] \
for x in np.linspace(0, 1, split)]
# ポートフォリオのシャープレシオを計算
plot_sharpR = [data_E[i] / np.sqrt(data_V[i]) for i in range(len(data_V))]
# E-V図を作成
print('Plot EV...')
fig = plt.figure(figsize=(8,8))
plt.rcParams["font.size"] = 18
sc = plt.scatter(data_V, data_E, vmin=0.2, vmax=-0.15, c=plot_sharpR, cmap=cm.Reds, s=2)
plt.colorbar(sc)
# 図の設定
plt.title('ポートフォリオのリターンとリスク', fontname="MS Gothic")
plt.ylabel('期待値(E)', fontname="MS Gothic")
plt.xlabel('分散(V)', fontname="MS Gothic")
plt.ylim(-0.15, 0.55)
plt.xlim(0,)
import pandas as pd
import numpy as np
import trade_package.get as get
import itertools
# 時系列データの期間を設定
start_time = '2019-01-01'
# TOPIX500銘柄リスト
list_stock_name = get.topix500()
# 株価時系列データフレームと収益率の計算
df = pd.DataFrame()
for stock in list_stock_name.code:
csv_file = './trade_package/data/price/' + stock + '.csv'
df_new = pd.read_csv(csv_file, index_col=0)['Close'][start_time:]
df_new.name = stock
df = pd.concat([df, df_new], axis=1)
df_returns = (df-df.shift(1))/df.shift(1)*100
# 収益率の分散,平均,共分散
ave = df_returns.mean()
var = df_returns.var()
cov = df_returns.cov()
# 2銘柄投資のポートフォリオの収益率の期待値と分散を計算
split = 100
x_list = np.linspace(0, 1, split)
df_EVS = pd.DataFrame()
i=0
imax=len(list(itertools.combinations(list_stock_name.code, 2)))
for stock1, stock2 in itertools.combinations(list_stock_name.code, 2):
i+=1
print(f'{round(i/imax*100,2)} %')
data_E = [x*ave[stock1] +(1-x)*ave[stock2] for x in x_list]
data_V = [x**2*var[stock1] + (1-x)**2*var[stock2] + 2*x*(1-x)*cov.loc[stock1, stock2] for x in x_list]
sharp_R = [data_E[i]/np.sqrt(data_V[i]) for i in range(len(data_E))]
sharp_Rmax = max(sharp_R)
sharp_Rmax_i = sharp_R.index(sharp_Rmax)
data_list = [stock1,stock2,x_list[sharp_Rmax_i],1-x_list[sharp_Rmax_i],data_E[sharp_Rmax_i],data_V[sharp_Rmax_i],sharp_Rmax]
df_EVS = pd.concat([df_EVS, pd.DataFrame(data_list).T])
df_EVS.columns = ['stock1','stock2','x','1-x','E','V','sharpR']
df_EVS.sort_values('sharpR', ascending=False).to_csv('result.csv',index=None)
,stock1,stock2,x,1-x,E,V,sharpR
2413.T,6920.T,0.5252525252525253,0.4747474747474747,0.4386425418606011,5.436930262315414,0.18811952275504365
3635.T,6920.T,0.5050505050505051,0.4949494949494949,0.38280233520826157,4.479558675075106,0.18086601239448313
3038.T,6920.T,0.42424242424242425,0.5757575757575757,0.40785474339729155,5.394535099809534,0.17560161507746488
4519.T,6920.T,0.48484848484848486,0.5151515151515151,0.35519703647873563,4.141744177781606,0.1745330581678534
6920.T,9697.T,0.5858585858585859,0.41414141414141414,0.4030451414132443,5.398403333691024,0.1734686607962055
4612.T,6920.T,0.38383838383838387,0.6161616161616161,0.3931402905080809,5.286885113088228,0.17098090746230274
...