データ分析系プログラマーのブログ

主にPythonを使ったデータ分析や機械学習をやっています。

Pythonを使ったCAPMの計算

CAPMとは、個別投資案件のリスクと期待リターンの関係を市場ポートフォリオの期待収益やリスクフリー金利、マーケットリスクプレミアムと、市場ポートフォリオのリスクと個別案件のリスクとその相関係数から求められたベータを使って示したフレームワークです。 この記事では、Pythonを使った、ベータの計算、個別投資案件の期待収益の計算を紹介しています。

CAPMの式

CAPMの式は以下のように表します。


r_i = r_f + \beta \times (r_m - r_f)
r_i:個別投資案件の期待収益率
r_m:市場ポートフォリオの期待収益率
r_f:安全資産の利子率(リスクフリー金利)
r_m - r_f:市場リスクプレミアム(マーケットリスクプレミアム)
\beta:市場全体の変動に対する個別投資案件の期待リターンの感度

個別投資案件のベータ

\beta = \frac{\rho_{i,m} \times \sigma_i}{\sigma_m}
\rho_{i,m}:個別投資案件の市場ポートフォリオとの収益率の相関係数
\sigma_i:個別投資案件の収益率のリスク(標準偏差)
\sigma_m:市場ポートフォリオの収益率のリスク(標準偏差)

例えば、マーケット・ポートフォリオの期待収益率が6%、リスク(標準偏差)が30%となっている場合で、、リスクフリー金利が1%とした場合に、資産のリスク(標準偏差)が60%、その資産の収益率のマーケット・ポートフォリオ収益率との相関係数が0.4だとした場合に、この資産のベータと期待収益率は以下のように求めることができます。

\beta = \frac{\rho_{i,m} \times \sigma_i}{\sigma_m} = \frac{0.4 \times0.6}{0.3} = 0.8
r_i = r_f + \beta \times (r_m - r_f) = 0.01 + 0.8 \times (0.06 - 0.01) = 0.05

Pythonでは以下のように書くことができます。

Pythonで個別投資案件のベータを計算する

r_m = 0.06
sigma_m = 0.3
r_f = 0.01
sigma_i = 0.6
rho_im = 0.4
beta = (rho_im * sigma_i) / sigma_m
print(beta)

0.8

PythonCAPMの式から個別投資案件の期待収益率を求める

r_i = r_f + beta*(r_m - r_f)
print(r_i)

0.05

PyPortfolioOptを使った3資産のポートフォリオ最適化の求め方

3資産のポートフォリオリスクの投資比率を求める場合、株価のデータを使った計算をする場合は、PythonのライブラリのPyPortfolioOptを使用する方法もあります。PyPortfolioOptの場合は、Pandasのデータフレームを扱えるので3資産だけでなく複数資産のポートフォリオリスクやリターン、最適な投資比率を求めることができます。この記事は、PyPortfolioOptを使った3資産のポートフォリオ最適化の求め方について紹介しています。

必要なライブラリのインポートと株価データの読み込み

まずは、必要なライブラリをインポートしてきます。今回はpandas、pandas_datareader、pypfoptなどを使用します。次に、pandas_datareaderを使って、stooqから株価のデータを読み込んできます。今回は、docomoKDDIsoftbankの3社の株価を読み込んでいます。

import pandas as pd
import pandas_datareader.data as web
from pypfopt import expected_returns
from pypfopt import risk_models
from pypfopt.efficient_frontier import EfficientFrontier

df_docomo = web.DataReader('9437.JP', 'stooq')
df_kddi = web.DataReader('9433.JP','stooq')
df_softbank = web.DataReader('9434.JP', 'stooq')

df_docomo = df_docomo.sort_index()
df_kddi = df_kddi.sort_index()
df_softbank = df_softbank.sort_index()

分析した期間のみのデータを抽出

stooqから読み込んできた株価のデータは2010年から2020年までのデータになっていますので、分析したい期間のデータを取り出します。

df_docomo = df_docomo["2019-9-01":"2020-09-01"]
df_kddi = df_kddi["2019-9-01":"2020-09-01"]
df_softbank = df_softbank["2019-9-01":"2020-09-01"]

不要な特徴量を削除し、カラム名を変更する

株価のデータは、通常、始値終値、最高値、最安値、取引高という感じになっています。なので、今回は始め値のデータだけを使おうと思うので、それ以外のカラムは削除します。また、このままだと全部のカラム名がopenで同じになってしまうので、カラム名を銘柄名に変更しています。

drop_col = ['High', 'Low', 'Close', 'Volume']

df_docomo = df_docomo.drop(drop_col, axis=1)
df_kddi = df_kddi.drop(drop_col, axis=1)
df_softbank = df_softbank.drop(drop_col, axis=1)
df_docomo = df_docomo.rename(columns={'Open':'docomo'})
df_kddi = df_kddi.rename(columns={'Open':'KDDI'})
df_softbank = df_softbank.rename(columns={'Open':'softbank'})

データをmergeして統合する

次にそれぞれ別々のデータフレームになっているので、mergeを使って、一つのデータフレームにします。ここでは、indexを共通項目にして統合しています。これで分析のための準備が整いました。

df_all = pd.merge(df_docomo, df_kddi, left_index=True, right_index=True)
df_all = pd.merge(df_all, df_softbank, left_index=True, right_index=True)
df_all.head()
docomo KDDI softbank
Date
2019-09-02 2527.20 2656.32 1357.83
2019-09-03 2543.67 2669.51 1362.84
2019-09-04 2546.49 2674.24 1366.49
2019-09-05 2541.31 2692.61 1368.31
2019-09-06 2550.25 2705.33 1375.15

リターンを求める

PyPortfolioOptには、幾つかのリターンを求める方法があります。ここでは、mean_historical_return、ema_historical_returnを使って3資産ごとのリターンを求めています。

expected_returns.mean_historical_return(df_all, frequency=252)

docomo 0.152875
KDDI 0.148389
softbank -0.010779
dtype: float64

expected_returns.ema_historical_return(df_all, frequency=252, span=500)

docomo 0.105531
KDDI 0.105036
softbank -0.005998
Name: 2020-09-01 00:00:00, dtype: float64

リスクを求める

PyPortfolioOptには、リスクの計算方法がいつくか用意されています。ここでは、sample_cov、semicovariance、exp_cov、min_cov_determinant、CovarianceShrinkageの5つのリスク計算を試しています。

risk_models.sample_cov(df_all, frequency=252)
docomo KDDI softbank
docomo 0.051771 0.025393 0.018305
KDDI 0.025393 0.071413 0.018047
softbank 0.018305 0.018047 0.034281
risk_models.semicovariance(df_all, benchmark=0, frequency=252)
docomo KDDI softbank
docomo 0.018448 0.010123 0.005852
KDDI 0.010123 0.028380 0.007973
softbank 0.005852 0.007973 0.012187
risk_models.exp_cov(df_all, span=180, frequency=252)
docomo KDDI softbank
docomo 0.051734 0.026447 0.021012
KDDI 0.026447 0.063434 0.018962
softbank 0.021012 0.018962 0.037984
risk_models.min_cov_determinant(df_all, frequency=252, random_state=None)
docomo KDDI softbank
docomo 0.007597 0.005080 0.001213
KDDI 0.005080 0.009542 0.002058
softbank 0.001213 0.002058 0.005220
cs = risk_models.CovarianceShrinkage(df_all, frequency=252)
cs.ledoit_wolf()
docomo KDDI softbank
docomo 0.051664 0.021464 0.015472
KDDI 0.021464 0.068267 0.015254
softbank 0.015472 0.015254 0.036880

3資産のポートフォリオリスクの最適化

最後に、ポートフォリオリスクの最適化を行っています。ここでは、リターンとして、mean_historical_return、リスクとしてsample_covを使用してポートフォリオリスクの最適化を行っています。この計算では、docomoが約44%、KDDIが約25%、softbnkが約31%の投資比率がもっともリスクが小さくなるという結果となりました。

mu = expected_returns.mean_historical_return(df_all)
S = risk_models.sample_cov(df_all)

ef = EfficientFrontier(mu, S)
ef.efficient_return(target_return=0.1)

OrderedDict([('docomo', 0.4377722843783928),
('KDDI', 0.245876496732417),
('softbank', 0.3163512188893629)])

Pythonを使った3資産のポートフォリオ最適化の求め方

ファンダメンタル分析を行うための企業価値評価の一つとして、複数の資産を組み合わせて投資する方法があります。これは、ハリー・マーコヴィッツというアメリカの経済学者によって提唱されました。このうちある投資比率における3資産のポートフォリオリスクは前回の記事で紹介しました。一方で、このポートフォリオリスクの計算では、どの投資比率であれば、もっともポートフォリオリスクを減らすことができるのか?ということを計算する方法があります。ここでは、前回の3つの資産のリターン、リスク、相関係数の値を使って、最適なポートフォリオの投資比率の求めかたについて紹介しています。

例えば、資産1、資産2、資産3の3つによって、最小分散ポートフォリオ(リスクがもっとも小さいポートフォリオ)となるのは、3つの資産への投資比率をどのような組み合わせが良いのかということは以下のようにPythonで計算することができます。

資産1(リターン2%、リスク20%)
資産2(リターン4%、リスク30%)
資産3(リターン3%、リスク25%)

資産1と資産2との収益率の相関係数:0.3
資産1と資産3との収益率の相関係数:0.4
資産2と資産3との収益率の相関係数:0.4

ライブラリの読み込み

まず最初に必要なライブラリを読み込みます。今回は順列や組み合わせを計算できるitertoolsを使用しています。

import itertools
import pandas as pd
import math
import numpy as np

各資産のリターン、リスク、相関係数

先ほどの要件にあった、各資産のリターン、リスク、相関係数を変数に入れて用意しておきます。

assets1_return = 0.02
assets2_return = 0.04
assets3_return = 0.03

assets1_risk = 0.2
assets2_risk = 0.3
assets3_risk = 0.25

correlation_coefficient12 = 0.3
correlation_coefficient23 = 0.4
correlation_coefficient13 = 0.4

0から1までを100分割したnumpy配列を生成

今回は、投資比率の組み合わせを0から1までを100分割した値の組み合わせから生成し使用します。なので、numpyのlinspaceを使用して、0から1までを100等分した配列データを生成します。

raitio = np.linspace(0, 1, 101)
print(raitio)

[0. 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.1 0.11 0.12 0.13
0.14 0.15 0.16 0.17 0.18 0.19 0.2 0.21 0.22 0.23 0.24 0.25 0.26 0.27
0.28 0.29 0.3 0.31 0.32 0.33 0.34 0.35 0.36 0.37 0.38 0.39 0.4 0.41
0.42 0.43 0.44 0.45 0.46 0.47 0.48 0.49 0.5 0.51 0.52 0.53 0.54 0.55
0.56 0.57 0.58 0.59 0.6 0.61 0.62 0.63 0.64 0.65 0.66 0.67 0.68 0.69
0.7 0.71 0.72 0.73 0.74 0.75 0.76 0.77 0.78 0.79 0.8 0.81 0.82 0.83
0.84 0.85 0.86 0.87 0.88 0.89 0.9 0.91 0.92 0.93 0.94 0.95 0.96 0.97
0.98 0.99 1. ]

順列の生成

ここでは、先ほど生成したnumpy配列とitertoolsのpermutationsを使って三つの組み合わせの順列を生成しています。生成した順列のnumpy配列データは、計算しやすいようにするためにpandasのデータフレームにしておきます。

ratio_list =raitio.tolist()
p_list = list(itertools.permutations(ratio_list, 3))
df = pd.DataFrame(p_list)

合計が1になる組み合わせのみをデータフレームに残す

先ほど生成した、順列は、必ずしも三つの値の合計が1になるとは限らないので、pandasの機能を使って、三つの値が1になるデータだけを残します。すると以下のように、順列で生成した3つのデータのうち、合計が1になる組み合わせのみのデータとなりました。このデータを投資比率のデータとして使用します。

df = df[df.sum(axis=1) == 1]
df.head()
0 1 2
97 0.0 0.01 0.99
195 0.0 0.02 0.98
293 0.0 0.03 0.97
391 0.0 0.04 0.96
489 0.0 0.05 0.95

3資産のリターン計算の関数

以下は、リターンの計算を関数にしたものです。

def return1(x,y,z):
    expected_return = assets1_return * x + assets2_return * y + assets3_return * z
    expected_return = round(expected_return, 3)*100
    
    return expected_return

3資産のポートフォリオリスク計算の関数

以下は、3資産のポートフォリオリスク計算を関数にしたものです。

def sigma(x,y,z):
    result = (((x)**2)*((assets1_risk)**2)
    +((y)**2)*((assets2_risk)**2) 
    + ((z)**2)*((assets3_risk)**2) 
    
    + 2*x*y*correlation_coefficient12*assets1_risk*assets2_risk 
    + 2*y*z*correlation_coefficient23*assets2_risk*assets3_risk 
    + 2*z*x*correlation_coefficient13*assets3_risk*assets1_risk)
    
    result = round(math.sqrt(result), 3)*100
    
    return result

リターンの関数をデータフレームに適応

先ほどのリターンの関数をデータフレームに適応させて、一行づつ計算させると以下のようになります。

df["return"] = df.apply(lambda row: return1(row[0], row[1], row[2]),axis=1)
df.head()
0 1 2 return
97 0.0 0.01 0.99 3.0
195 0.0 0.02 0.98 3.0
293 0.0 0.03 0.97 3.0
391 0.0 0.04 0.96 3.0
489 0.0 0.05 0.95 3.0

ポートフォリオリスクの関数をデータフレームに適応

ポートフォリオリスクの関数も先ほどと同様にデータフレームに適用します。

df["risk"] = df.apply(lambda row: sigma(row[0], row[1], row[2]),axis=1)
df.head()
0 1 2 return risk
97 0.0 0.01 0.99 3.0 24.9
195 0.0 0.02 0.98 3.0 24.7
293 0.0 0.03 0.97 3.0 24.6
391 0.0 0.04 0.96 3.0 24.5
489 0.0 0.05 0.95 3.0 24.4

最小値のリスクを表示

min()を使って、riskの最小値を表示させます。この場合では、17.8がもっともリスクが少なくなっています。

df["risk"].min()

17.8

リスクが最小値となる投資比率の組み合わせを表示

最後に、queryを使って、先ほどの最小値の値となった行を表示してみます。すると、最小値となった投資比率の組み合わせは以下のように幾つかあることがわかります。このようにして、最適な投資比率を求めることができます。

df.query('risk == 17.8')
0 1 2 return risk
575809 0.58 0.16 0.26 2.6 17.8
585512 0.59 0.14 0.27 2.6 17.8
585610 0.59 0.15 0.26 2.6 17.8
585708 0.59 0.16 0.25 2.6 17.8
585806 0.59 0.17 0.24 2.6 17.8
595411 0.60 0.14 0.26 2.5 17.8
595509 0.60 0.15 0.25 2.6 17.8
595607 0.60 0.16 0.24 2.6 17.8
595705 0.60 0.17 0.23 2.6 17.8
605212 0.61 0.13 0.26 2.5 17.8
605310 0.61 0.14 0.25 2.5 17.8
605408 0.61 0.15 0.24 2.5 17.8
605506 0.61 0.16 0.23 2.6 17.8
605604 0.61 0.17 0.22 2.6 17.8
615111 0.62 0.13 0.25 2.5 17.8
615209 0.62 0.14 0.24 2.5 17.8
615307 0.62 0.15 0.23 2.5 17.8
615405 0.62 0.16 0.22 2.5 17.8
625108 0.63 0.14 0.23 2.5 17.8
625206 0.63 0.15 0.22 2.5 17.8

Pythonを使った3資産の期待リターンとポートフォリオリスクの求め方

ファンダメンタル分析を行うための企業価値評価の一つとして、複数の資産を組み合わせて投資する方法があります。これは、ハリー・マーコヴィッツというアメリカの経済学者によって提唱されました。このうち前回は、2資産の期待リターンとポートフォリオリスクを求めましたが、資産の数が増えるとポートフォリオリスクの式も組み合わせの数によって、式が長くなっていきます。この記事では、3資産の期待リターンとポートフォリオリスクの計算方法について紹介しています。

3資産のポートフォリオリスクの式

3資産のポートフォリオのリスク(標準偏差):


\sigma^2 = w_1^2 \times \sigma_1^2 + w_2^2 \times \sigma_2^2 + w_3^2 \times \sigma_3^2\\
+2 \times w_1 \times w_2 \times \rho_{12 }\times \sigma_1 \times \sigma_2\\
+2 \times w_2 \times w_3 \times \rho_{23 }\times \sigma_2 \times \sigma_3\\
+2 \times w_3 \times w_1 \times \rho_{31 }\times \sigma_3 \times \sigma_1$

例えば、資産1(リターン2%、リスク20%)と資産2(リターン4%、リスク30%)、資産3(リターン3%、リスク25%)の3つの資産があり、それぞれの相関係数が、資産1と資産2の収益率との相関係数:0.3、資産2と資産3の収益率との相関係数:0.4、資産1と資産3の収益率との相関係数:0.4で、この時、資産1、資産2、資産3の投資比率を、それぞれ資産比率その1を20%:20%:60%とした場合、資産比率その2を30%:30%:40%とした場合、資産比率その3を80%:10%:10%とした場合の3ケースについて、ポートフォリオの期待リターンとリスク(標準偏差)は以下のように計算することができます。

資産1(リターン2%、リスク20%)
資産2(リターン4%、リスク30%)
資産3(リターン3%、リスク25%)

資産1と資産2の収益率との相関係数:0.3
資産1と資産3の収益率との相関係数:0.4
資産2と資産3の収益率との相関係数:0.4

資産1比率 資産2比率 資産3比率 ポートフォリオのリスク(標準偏差 ポートフォリオの期待リターン
20% 20% 60% 20.3% 3.0%
30% 30% 40% 19.2% 3.0%
80% 10% 10% 18.4% 2.3%

この計算は、Pythonだと以下のように書くことができます。

資産比率その1の場合の期待リターンとポートフォオリスク

import math

assets1_return = 0.02
assets2_return = 0.04
assets3_return = 0.03

assets1_risk = 0.2
assets2_risk = 0.3
assets3_risk = 0.25

correlation_coefficient12 = 0.3
correlation_coefficient23 = 0.4
correlation_coefficient13 = 0.4

assets1_ratio = 0.2
assets2_ratio = 0.2
assets3_ratio = 0.6
expected_return = assets1_return * assets1_ratio + assets2_return * assets2_ratio + assets3_return * assets3_ratio
print("ポートフォリオの期待リターンは、{0}%です。".format(round(expected_return, 3)*100))

ポートフォリオの期待リターンは、3.0%です。

sigma = (
            ((assets1_ratio)**2)*((assets1_risk)**2)
         +((assets2_ratio)**2)*((assets2_risk)**2) 
         + ((assets3_ratio)**2)*((assets3_risk)**2) 
    
         + 2*assets1_ratio*assets2_ratio*correlation_coefficient12*assets1_risk*assets2_risk 
         + 2*assets2_ratio*assets3_ratio*correlation_coefficient23*assets2_risk*assets3_risk 
         + 2*assets3_ratio*assets1_ratio*correlation_coefficient13*assets3_risk*assets1_risk
)
print("ポートフォリオのリスク(標準偏差)は、{0}%です。".format(round(math.sqrt(sigma), 3)*100))

ポートフォリオのリスク(標準偏差)は、20.3%です。

資産比率その2の場合の期待リターンとポートフォオリスク

assets1_ratio = 0.3
assets2_ratio = 0.3
assets3_ratio = 0.4

expected_return = assets1_return * assets1_ratio + assets2_return * assets2_ratio + assets3_return * assets3_ratio
print("ポートフォリオの期待リターンは、{0}%です。".format(round(expected_return, 3)*100))

ポートフォリオの期待リターンは、3.0%です。

sigma = (
            ((assets3_ratio)**2)*((assets3_risk)**2)
         +((assets2_ratio)**2)*((assets2_risk)**2) 
         + ((assets1_ratio)**2)*((assets1_risk)**2) 
    
         + 2*assets1_ratio*assets2_ratio*correlation_coefficient12*assets1_risk*assets2_risk 
         + 2*assets2_ratio*assets3_ratio*correlation_coefficient23*assets2_risk*assets3_risk 
         + 2*assets3_ratio*assets1_ratio*correlation_coefficient13*assets3_risk*assets1_risk
)
print("ポートフォリオのリスク(標準偏差)は、{0}%です。".format(round(math.sqrt(sigma), 3)*100))

ポートフォリオのリスク(標準偏差)は、19.2%です。

資産比率その3の場合の期待リターンとポートフォオリスク

assets1_ratio = 0.8
assets2_ratio = 0.1
assets3_ratio = 0.1

expected_return = assets1_return * assets1_ratio + assets2_return * assets2_ratio + assets3_return * assets3_ratio
print("ポートフォリオの期待リターンは、{0}%です。".format(round(expected_return, 3)*100))

ポートフォリオの期待リターンは、2.3%です。

sigma = (
            ((assets3_ratio)**2)*((assets3_risk)**2)
         +((assets1_ratio)**2)*((assets1_risk)**2) 
         + ((assets2_ratio)**2)*((assets2_risk)**2) 
    
         + 2*assets1_ratio*assets2_ratio*correlation_coefficient12*assets1_risk*assets2_risk 
         + 2*assets2_ratio*assets3_ratio*correlation_coefficient23*assets2_risk*assets3_risk 
         + 2*assets3_ratio*assets1_ratio*correlation_coefficient13*assets3_risk*assets1_risk
)
print("ポートフォリオのリスク(標準偏差)は、{0}%です。".format(round(math.sqrt(sigma), 3)*100))

ポートフォリオのリスク(標準偏差)は、18.4%です。

Pythonを使った複数投資によるポートフォリオの求め方

ファンダメンタル分析を行うための企業価値評価の一つとして、複数の資産を組み合わせて投資する方法があります。この場合に最適な投資比率を計算することで、リスクの少ないポートフォリオを組むことができます。この複数の投資をすることを分散投資と呼び、これは、ハリー・マーコヴィッツというアメリカの経済学者によって提唱されました。この記事では、実際に投資比率を変えながらリスクを計算してそれを散布図にプロットするところまでを紹介しています。

資産1に60%、資産2に40%投資するポートフォリオのリスクとリターン

以下の例は、資産1に60%、資産2に40%の比率で投資した場合のリスクとリターンの計算です。 計算方法は、それぞれの月ごとのリターンに対して資産1には60%、資産2には40%の比率をかけてその合計をその月のリターンとします。次に、その比率で計算した月ごとのリターンのデータを用いて、標準偏差を求めます。これが、このポートフォリオの計算の第一段階です。

図表

資産1 資産2 資産1:資産2 = 60%:40%
前年1月 2% -1% 0.8%
前年2月 5% 11% 7.4%
前年3月 -2% 2% -0.4%
前年4月 0% -3% -1.2%
前年5月 3% 9% 5.4%
前年6月 5% 5% 5.0%
前年7月 0% 12% 4.8%
前年8月 4% 3% 3.6%
前年9月 10% -8% 2.8%
前年10月 -5% 10% 1.0%
前年11月 -4% -5% -4.4%
前年12月 6% 1% 4.0%
12ヶ月平均 2.0% 3.0% 2.4%
標準偏差 4.39% 6.58% 3.33%

資産1と資産2に0%から100%と投資比率を変えることで計算されるポートフォリオのリスクとリターン

例えば、資産1と資産2について、それぞれの投資比率を、0%:100%、10%:90%、20%:80%、30%:70%と10%ずつ変化させていき、最終的に100%:0%となるまでについて、ポートフォリオ(PF)の平均収益率とリスク(標準偏差)をそれぞれ求めて見た場合には以下のように計算することができます。また、これらのデータを、横軸とリスク(標準偏差)、縦軸と平均収益率としてグラフにプロットすると、以下のようになります。

資産1比率 資産2比率 PF平均収益率 PFリスク(標準偏差
0% 100% 3.00% 6.58%
10% 90% 2.90% 5.85%
20% 80% 2.80% 5.16%
30% 70% 2.70% 4.53%
40% 60% 2.60% 3.99%
50% 50% 2.50% 3.57%
60% 40% 2.40% 3.33%
70% 30% 2.30% 3.31%
80% 20% 2.20% 3.50%
90% 10% 2.10% 3.87%
100% 0% 2.00% 4.39%
import matplotlib.pyplot as plt

x = [6.58,5.85,5.16,4.53,3.99,3.57,3.33,3.31,3.50,3.87,4.39]
y = [3.0,2.9,2.8,2.7,2.6,2.5,2.4,2.3,2.2,2.1,2.0]

plt.figure(figsize = (12,8))
plt.scatter(x, y)

plt.title('PFの平均収益率とリスク(標準偏差)')
plt.xlabel('リスク(標準偏差)')
plt.ylabel('平均収益率')

plt.grid(b=True, which='major', color='lightgray', linestyle='-')
plt.savefig('fundamental_portfolio_scatter01.png', bbox_inches='tight')

f:id:hira03:20200927071627p:plain
fundamental_portfolio_scatter01

Pythonで計算すると以下のようになります。

まず最初に、投資1と投資2のデータをnumpyで用意して、それぞれの平均を求めます。次に、0%から100%の比率ごとの平均の合計をリストとして計算します。すると、以下のように、投資比率ごとの平均収益率を計算することができます。

import numpy as np

assets1 = np.array([2,5,-2,0,3,5,0,4,10,-5,-4,6])
assets2 = np.array([-1,11,2,-3,9,5,12,3,-8,10,-5,1])

ratio1 = np.array([0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1])
ratio2 = np.array([1,0.9,0.8,0.7,0.6,0.5,0.4,0.3,0.2,0.1,0])

mean1 = assets1.mean()
mean2 = assets2.mean()

average_profitability = []
assets_ratio = []

for i,j in zip(ratio1, ratio2):
    x = mean1*i
    y = mean2*j
    z = round((x + y),2)
    average_profitability.append(z) 

print(average_profitability)

[3.0, 2.9, 2.8, 2.7, 2.6, 2.5, 2.4, 2.3, 2.2, 2.1, 2.0]

次に、資産1、資産2、それぞれのリターンごとの投資比率をfor文を使って計算しています。この時、資産のデータはnumpyで用意しているので、比率をまとめて計算することができます。計算したデータの合計をリストにします。さらに、その比率ごとに計算された多次元配列となったリストを使って、比率ごとの標準偏差を求めます。これをリストにしておけば、求めるデータが計算できたことになります。

asset_average_all = []
    
for k, l in zip(ratio1,ratio2):
    x = assets1*k
    y = assets2*l
    z = (x + y)
    asset_average_all.append(z)

std_ratio = []

for i in asset_average_all:
    z = i.std(ddof=1)
    std_ratio.append(z)

計算された配列データを見てみると、実際に投資比率ごとに標準偏差が計算されていることがわかります。

print(std_ratio)

[6.578200914591107, 5.849164664524951, 5.160690580990812, 4.5313052504468585, 3.9890759923480115, 3.5738952520642338, 3.333575748760972, 3.3064674915576098, 3.4975315971020584, 3.87462608166611, 4.390071442781686]

最後に、先ほどと同じように散布図にプロットすれば完成です。

plt.figure(figsize = (12,8))
plt.scatter(std_ratio, average_profitability)

plt.title('資産1と資産2におけるPFの平均収益率とリスク(標準偏差)')
plt.xlabel('リスク(標準偏差)')
plt.ylabel('平均収益率')

plt.grid(b=True, which='major', color='lightgray', linestyle='-')
plt.savefig('fundamental_portfolio_scatter02.png', bbox_inches='tight')

f:id:hira03:20200927071710p:plain
fundamental_portfolio_scatter02

ここでは、先ほどの資産2だったデータを資産3に変えて、資産1と資産3を組み合わせたポートフォリオについて計算しています。Pythonでの計算方法も先ほどとほぼ同じです。

import numpy as np

assets1 = np.array([2,5,-2,0,3,5,0,4,10,-5,-4,6])
assets3 = np.array([0,-4,-2,12,6,11,10,1,-6,13,-9,4])

ratio1 = np.array([0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1])
ratio2 = np.array([1,0.9,0.8,0.7,0.6,0.5,0.4,0.3,0.2,0.1,0])

mean1 = assets1.mean()
mean3 = assets3.mean()

average_profitability = []
assets_ratio = []

for i,j in zip(ratio1, ratio2):
    x = mean1*i
    y = mean3*j
    z = round((x + y),2)
    average_profitability.append(z) 

asset_average_all = []

for i, j in zip(assets1, assets3):
    x = i*k
    y = j*l
    z = round((x + y), 2)
    asset_average.append(z) 
    
for k, l in zip(ratio1,ratio2):
    x = assets1*k
    y = assets3*l
    z = (x + y)
    asset_average_all.append(z)

std_ratio = []

for i in asset_average_all:
    z = i.std(ddof=1)
    std_ratio.append(z)

print(std_ratio)

[7.483314773547883, 6.656507410729062, 5.865151319446072, 5.125692857821981, 4.463997393286955, 3.919647479510927, 3.5470858717852014, 3.403207043630784, 3.5161962919661307, 3.8635828873304536, 4.390071442781686]

plt.figure(figsize = (12,8))
plt.scatter(std_ratio, average_profitability)

plt.title('資産1と資産3におけるPFの平均収益率とリスク(標準偏差)')
plt.xlabel('リスク(標準偏差)')
plt.ylabel('平均収益率')

plt.grid(b=True, which='major', color='lightgray', linestyle='-')
plt.savefig('fundamental_portfolio_scatter03.png', bbox_inches='tight')

f:id:hira03:20200927071750p:plain
fundamental_portfolio_scatter03

Pythonを使った期待収益、平均収益率、分散、標準偏差(リスク)の求め方

ファンダメンタル分析を行うための企業価値評価の一つとして、統計学を用いた期待収益や平均収益率、分散、標準偏差を用いることによってリターンとリスクを評価することができます。期待収益は、いわゆる期待値を求めることで計算できます。また、分散や標準偏差とは、企業価値評価においては、リターンにおけるリスク評価として使用します。この記事は、Pythonを使った期待収益、平均収益率、分散、標準偏差の求め方について紹介しています。

期待収益の計算方法

例えば以下のように、1年後に好景気か不況の2つのパターンが起こる確率は同じ(それぞれ50%ずつ)であるとした場合に、資産1〜3の期待収益は以下のように計算することができます。

好景気 不況
資産1 1.5% 1.5%
資産2 3.5% 0%
資産3 6% -1%

資産1:0.5 × 1.5% + 0.5 × 1.5% = 1.5%
資産2:0.5 × 3.5% + 0.5 × 0% = 1.75%
資産3:0.5 × 6% + 0.5 × -1% = 2.5%

この計算は、Pythonだと以下のように書くことができます。

p = 0.5

boom1 = 0.015
boom2 = 0.035
boom3 = 0.06

recession1 = 0.015
recession2 = 0
recession3 = -0.01

assets1 = p*boom1 + p*recession1
assets2 = p*boom2 + p*recession2
assets3 = p*boom3 + p*recession3

print(assets1)
print(assets2)
print(assets3)

0.015
0.0175
0.024999999999999998

平均収益率と分散、標準偏差の計算方法

例えば、以下のような資産2について、12ヶ月の平均収益率と、収益率の分散と標準偏差を求めて、資産1と比較した場合に、リスクとリターンの関係については以下のようなことをいうことができます。

資産1 資産2
前年1月 -1% 0%
前年2月 11% -4%
前年3月 2% -2%
前年4月 -3% 12%
前年5月 9% 6%
前年6月 5% 11%
前年7月 12% 10%
前年8月 3% 1%
前年9月 -8% -6%
前年10月 10% 13%
前年11月 -5% -9%
前年12月 1% 4%
資産2 収益率12ヶ月平均との差 差の2乗
前年1月 0% -3% 0.0009
前年2月 -4% -7% 0.0049
前年3月 -2% -5% 0.0025
前年4月 12% 9% 0.0081
前年5月 6% 3% 0.0009
前年6月 11% 8% 0.0064
前年7月 10% 7% 0.0049
前年8月 1% -2% 0.0004
前年9月 -6% -9% 0.0081
前年10月 13% 10% 0.0100
前年11月 -9% -12% 0.0144
前年12月 4% 1% 0.0001
12ヶ月平均 3.0% 差の2乗の平均=分散 0.00560
標準偏差 7.48%

資産2は、資産1(平均収益:3.0%、標準偏差:6.58%)に比べて、同じ平均収益率(リターン)だけど、標準偏差(リスク)が大きいです。

この計算は、Pythonだと以下のように書くことができます。

import numpy as np

Rate_of_return1 = np.array([-0.01,0.11,0.02,-0.03,0.09,0.05,0.12,0.03,-0.08,0.1,-0.05,0.01]) 
Rate_of_return2 = np.array([0, -0.04, -0.02, 0.12, 0.06, 0.11, 0.10, 0.01, -0.06, 0.13, -0.09, 0.04])

print("資産1の平均収益、分散、標準偏差")
print("平均収益",round(Rate_of_return1.mean(), 2)*100,"%")
print("分散",round(Rate_of_return1.var(ddof=1), 4)*100,"%")
print("標準偏差",round(Rate_of_return1.std(ddof=1), 4)*100,"%")
print()
print("資産2の平均収益、分散、標準偏差")
print("平均収益",round(Rate_of_return2.mean(), 2)*100,"%")
print("分散",round(Rate_of_return2.var(ddof=1), 4)*100,"%")
print("標準偏差",round(Rate_of_return2.std(ddof=1), 4)*100,"%")

資産1の平均収益、分散、標準偏差 平均収益 3.0 % 分散 0.43 % 標準偏差 6.58 %

資産2の平均収益、分散、標準偏差 平均収益 3.0 % 分散 0.5599999999999999 % 標準偏差 7.48 %

Pythonを使った投資収益と投資プロジェクトの現在価値の求め方

ファンダメンタル分析を行うための企業価値評価の一つとして、割引率を求めて現在価値を計算することがあります。この割引率は、資本コスト(cost of capital)、資本の機会費用(opportunity cost of capital)、期待収益率もしくは期待リターン(expected returns)、ハードル・レート(hurdle rate)という呼び方があります。この記事では、Pythonを使った期待収益率(割引率)の求め方について紹介しています。

株式投資の収益率の計算方法

一般的に、投資の収益率と株式投資の収益率は以下のように計算されます。


投資の収益率 = \frac{投資の収益}{投資元本} = \frac{(投資の結果得られた現金) - (投資元本)}{投資元本}

株式投資の収益率 = \frac{投資の収益}{投資元本} = \frac{(株式売却価格) - (株式購入価格) + (売却までに受け取った配当)}{株式購入価格}

1年間の株式投資収益を求める場合

例えば、株式を1株1,000円で購入し、1年後に1,050円で売却するとした場合に、1年後には1株15円の配当が受け取れるとすると、1年間の株式投資収益は以下のように計算することができます。


\frac{(1050 - 1000) + 15}{1000} = 6.5%

この計算は、Pythonだと以下のように書くことができます。

purchase_price = 1000
sale_price = 1050
dividend = 15

stock_investment_income = (sale_price - purchase_price + dividend)/purchase_price
print("株式投資収益は", stock_investment_income*100, "%")

株式投資収益は 6.5 %

期待収益率(割引率)と2年後の投資プロジェクトの現在価値を求める場合

さらに別の例として、1年後に40,000円、2年後に70,000円のキャシュフローが期待されている投資プロジェクトがあるケースを考えてみた場合、このプロジェクトと全く同じリスクを持った証券が市場で取引されていて、この証券を保有すれば、1年後に2,000円、2年後に4,000円のキャッシュフローが発生すると期待されているとした場合に、この証券の市場価格が5,712円だとすると、この投資プロジェクトの割引率は以下のように計算することができます。また、この投資プロジェクトの価値(現在価値)は以下のように計算することができます。

n年後まで、毎年キャッシュフローが発生する場合の現在価値の合計は以下のようになります。


PV = \frac{CF_1}{1 + r} + \frac{CF_2}{(1 + r)^2} + \cdots + \frac{CF_n}{(1 + r)^n}

まず証券のキャッシュフローと市場価値から、期待収益率(年率)を計算します。求める期待収益率(割引率)をx%とすると、xは以下の2次方程式を解くことで求めることができます。


2,000 \times \frac{1}{1 + \frac{x}{100}} + 4,000 \times \frac{1}{(1 + \frac{x}{100})^2} = 5,712

よって、


x = 3.0%

この証券の期待収益率(3%)は、同じリスクを持った投資プロジェクトの機会費用(=割引率、期待収益率)となるので、この投資プロジェクトの価値(現在価値)は、


40,000 \times \frac{1}{1 + \frac{3}{100}} + 70,000 \times \frac{1}{(1 + \frac{3}{100})^2} = 104,820円

となります。

この計算は、Pythonだと以下のように書くことができます。

import sympy
import math
r = sympy.Symbol('r')
print(sympy.solve(2000*(1/(1+r)) + 4000*(1/(1+r)**2) - 5712))

[-589/714 + 5sqrt(14905)/714, -5sqrt(14905)/714 - 589/714]

print(-589/714 + 5*math.sqrt(14905)/714)

0.030014252363098626

 print(-5*math.sqrt(14905)/714 - 589/714)

-1.6798741963406896

r = (-589/714 + 5*math.sqrt(14905)/714)*100
print("期待収益率は", round(r, 2), "%")

期待収益率は 3.0 % よって、

CF1 = 40000
CF2 = 70000
r = 3

PV = CF1*(1/(1+(r/100))) + CF2*(1/(1+(r/100))**2)

print("このプロジェクトの現在価値は約", round(PV,-1), "円")

このプロジェクトの現在価値は約 104820.0 円