個別株と市場のボラティリティの関係性を示すβをPythonで計算する
βとは
βは、CAPMというポートフォリオ理論に出てくる概念であり、個別株と市場のボラティリティの関係性を示します。
日本経済新聞のサイトでは、銘柄のβランキングが公表されています。
個別株とは、TOYOTAであったりNTTデータであったり、ひとつひとつの会社のことです。
市場とは、株式市場全体のことです。日本では、TOPIX = 市場 として扱われることが多いと思います。
βは高ければ、高いほど市場より高いボラティリティがあり、低ければ低いほど市場より低いボラティリティということになります。
ボラティリティ = リスク であるため、言い換えるとβが高い株は、リスクの高い株、ということにもなります。
β = 1.0 : 株式が市場と同じボラティリティ β = 2.0 : 株式が市場より高いボラティリティ β = 0.5 : 株式が市場より低いボラティリティ
TOYOTAとさくらネットの株価の日々のリターンをビジュアル化してみます。
それぞれのβは以下になります。
銘柄名 | β |
---|---|
さくらネット(3778) | 1.54 |
TOYOTA(7203) | 1.02 |
βがさくらネットのほうが高く、ボラティリティが高いことがわかると思います。
言うても、0.5ほどしか差がないので、微妙な差ですが....
βの求め方
β = 個別株と市場ポートフォリオの相関 × 個別株の標準偏差 / 市場ポートフォリオの標準偏差
この式が何をしているかと言うと...
個別株の値動きのうち、市場と連動している部分のみをβとしています。
個別株の値動きは、大きく2つにわけることができます。
1つは、市場の動き。もう1つは、個別株特有の動きです。
TOPIXが上昇すれば、個別株もそれに応じて上昇します。
これが市場の動きです。
逆に個別株特有の動きとは、決算の結果が良かったや、粉飾決算がバレた、などです。
これらのイベントによって個別株は、特有の値動きをするので、この値動きは市場の動きとは別です。
市場の動きと個別株特有の動きが合わさって、個別株の値動きになります。
個別株の値動きの中から個別株特有の動きを控除したものを、個別株のβとしているのです。
どうやって個別株特有の動きを控除するかと言うと、個別株と市場の相関係数を使います。
個別株と市場ポートフォリオの相関 × 個別株の標準偏差
個別株と市場の値動きの相関係数が0.7だった場合は、0.7は市場の動き、残りの0.3は個別株特有の動きであると。
そういった解釈になります。
Pythonで実装する
株価を取得するプログラミングは、現代ポートフォリオ理論をPythonで実装したときと同じものを利用しるので割愛します。
βの計算対象は、さくらネット(3778)にします。
市場は、TOPIX(998405)にしています。
とりあえず、pandasのDataFrameでさくらネットとTOPIXを統合したものを作成します。
Close_998405 Close_3778 1800.44 850 1783.49 852 1778.87 843 1744.01 811 1761.71 816 1763.76 817 1759.65 823 1771.13 831 1777.08 839 1780.56 820 1776.73 831 1772.07 816 1786.15 820 1792.08 833 1792.66 854
上記のデータが master_df に入っています。
returns_daily = master_df.pct_change() # β = 証券iと市場ポートフォリオの相関 × 証券i の標準偏差 / 市場ポートフォリオの標準偏差 tmp_df = returns_daily.loc[:, ["Close_998405", "Close_3778"]] # 相関係数を計算 corr = tmp_df.corr().iloc[0, 1] # それぞれの標準偏差を計算 std_i = returns_daily["Close_3778"].std() std_m = returns_daily["Close_998405"].std() # βの計算 beta = std_i * corr / std_m # print("beta : ", beta)
プログラミング全体は、gitlabにおいています。
上のコードでは、愚直にpandasで式を再現しています。
scipyの単回帰でもβを求めることができますし、こっちのほうがコードが短くてスマートです。
tmp_df = returns_daily.loc[:, ["Close_998405", "Close_3774"]] x = [i[0] for i in tmp_df.iloc[:, [0]].values] y = [i[0] for i in tmp_df.iloc[:, [1]].values] slope, intercept, r_value, p_value, std_err = stats.linregress(x[1:len(x)], y[1:len(y)]) print("β : ", slope)
計算の結果は、どちらも以下になります。
β : 1.54465802366
計算期間は、2017/11/04 ~ 2018/07/12にしています。
まとめ
特になし!
以上おわり!