Python で資本資産価格モデルを実装します。
個別資産として バークシャーハサウェイ(BRK-A)、マーケット全体として S&P500 index ( ^GSPC )を使います。
無リスク資産の収益率は 2% で固定し簡略化します。
import datetime import matplotlib.pyplot as plt import numpy as np import pandas as pd import scipy.optimize from pandas_datareader import data as pdr import yfinance as yf import requests_cache # override pandas_datareader yf.pdr_override() # casche for downloaded data expire_after = datetime.timedelta(days=3) session = requests_cache.CachedSession(cache_name='cache', backend='sqlite', expire_after=expire_after) # '^GSPC' is S&P 500 index ticker STOCKS = ['BRK-A', '^GSPC'] START = pd.to_datetime('2010-01-01') END = pd.to_datetime('2020-01-01') RISK_FREE_RATE = 0.02
情報の取得と月次リターン
情報の取得
yahoo finance から日次の調整終値を取得します。
以下と同じです。
import datetime import matplotlib.pyplot as plt import numpy as np import pandas as pd import scipy.optimize from pandas_datareader import data as pdr import yfinance as yf import requests_cache # override pandas_datareader yf.pdr_override() # casche for downloaded data expire_after = datetime.timedelta(days=3) session = requests_cache.CachedSession(cache_name='cache', backend='sqlite', expire_after=expire_after) # '^GSPC' is S&P 500 index ticker STOCKS = ['BRK-A', '^GSPC'] START = pd.to_datetime('2010-01-01') END = pd.to_datetime('2020-01-01') RISK_FREE_RATE = 0.02 def download_data_adjclose(stocks): data = pdr.get_data_yahoo(stocks, start=START, end=END)['Adj Close'] return data if __name__ == '__main__': data = download_data_adjclose(STOCKS) print(data.head()) print(data.tail())
月次リターンの計算
日次の調整終値から月次リターンを計算します。
まずは、pandas
の resample
を使い、日次調整終値から月次の平均調整終値を計算します。
pandasで時系列データをリサンプリングするresample, asfreq
その後、対数収益率を計算します。
import datetime import matplotlib.pyplot as plt import numpy as np import pandas as pd import scipy.optimize from pandas_datareader import data as pdr import yfinance as yf import requests_cache # override pandas_datareader yf.pdr_override() # casche for downloaded data expire_after = datetime.timedelta(days=3) session = requests_cache.CachedSession(cache_name='cache', backend='sqlite', expire_after=expire_after) # '^GSPC' is S&P 500 index ticker STOCKS = ['BRK-A', '^GSPC'] START = pd.to_datetime('2010-01-01') END = pd.to_datetime('2020-01-01') RISK_FREE_RATE = 0.02 def download_data_adjclose(stocks): data = pdr.get_data_yahoo(stocks, start=START, end=END)['Adj Close'] return data def calc_monthly_returns(data): data = data.resample('M').mean() returns = np.log(data/data.shift(1)) # drop NAN for np.polyfit returns.dropna(inplace=True) return returns if __name__ == '__main__': data = download_data_adjclose(STOCKS) # print(data.head()) # print(data.tail()) returns = calc_monthly_returns(data) print(returns.head()) print(returns.tail()) returns.plot() plt.show() returns.hist(bins=100) plt.show()
CAPMの公式による\(\beta\)の計算
以下の公式に従い\(\beta\)を計算します。
$$ {\beta}_i = \frac{Cov(R_i, R_m)}{Var(R_m)} $$
import datetime import matplotlib.pyplot as plt import numpy as np import pandas as pd import scipy.optimize from pandas_datareader import data as pdr import yfinance as yf import requests_cache # override pandas_datareader yf.pdr_override() # casche for downloaded data expire_after = datetime.timedelta(days=3) session = requests_cache.CachedSession(cache_name='cache', backend='sqlite', expire_after=expire_after) # '^GSPC' is S&P 500 index ticker STOCKS = ['BRK-A', '^GSPC'] START = pd.to_datetime('2010-01-01') END = pd.to_datetime('2020-01-01') RISK_FREE_RATE = 0.02 def download_data_adjclose(stocks): data = pdr.get_data_yahoo(stocks, start=START, end=END)['Adj Close'] return data def calc_monthly_returns(data): data = data.resample('M').mean() returns = np.log(data/data.shift(1)) # drop NAN for np.polyfit returns.dropna(inplace=True) return returns def calc_beta(returns): cov_matrix = np.array(returns.cov()) print(cov_matrix) beta = cov_matrix[0, 1] / cov_matrix[1, 1] return beta if __name__ == '__main__': data = download_data_adjclose(STOCKS) # print(data.head()) # print(data.tail()) returns = calc_monthly_returns(data) # print(returns.head()) # print(returns.tail()) # returns.plot() # plt.show() # returns.hist(bins=100) # plt.show() beta = calc_beta(returns) print('Beta', beta)
[[0.00107756 0.00054425] [0.00054425 0.00076873]] Beta 0.7079843244326955
回帰による\(\beta\)と\(\alpha\)の計算
回帰分析で\(\beta\)と\(\alpha\)を求めます。
回帰分析には、numpy
の polyfit
を使います。
import datetime import matplotlib.pyplot as plt import numpy as np import pandas as pd import scipy.optimize from pandas_datareader import data as pdr import yfinance as yf import requests_cache # override pandas_datareader yf.pdr_override() # casche for downloaded data expire_after = datetime.timedelta(days=3) session = requests_cache.CachedSession(cache_name='cache', backend='sqlite', expire_after=expire_after) # '^GSPC' is S&P 500 index ticker STOCKS = ['BRK-A', '^GSPC'] START = pd.to_datetime('2010-01-01') END = pd.to_datetime('2020-01-01') RISK_FREE_RATE = 0.02 def download_data_adjclose(stocks): data = pdr.get_data_yahoo(stocks, start=START, end=END)['Adj Close'] return data def calc_monthly_returns(data): data = data.resample('M').mean() returns = np.log(data/data.shift(1)) # drop NAN for np.polyfit returns.dropna(inplace=True) return returns def calc_beta(returns): cov_matrix = np.array(returns.cov()) # print(cov_matrix) beta = cov_matrix[0, 1] / cov_matrix[1, 1] return beta def regression_beta_alpha(returns): beta, alpha = np.polyfit((np.array(returns.iloc[:, 1])-RISK_FREE_RATE), (np.array(returns.iloc[:, 0])-RISK_FREE_RATE) , deg=1) return beta, alpha if __name__ == '__main__': data = download_data_adjclose(STOCKS) # print(data.head()) # print(data.tail()) returns = calc_monthly_returns(data) # print(returns.head()) # print(returns.tail()) # returns.plot() # plt.show() # returns.hist(bins=100) # plt.show() beta = calc_beta(returns) print('Beta', beta) beta_reg, alpha_reg = regression_beta_alpha(returns) print('Beta from Reg:',beta_reg, 'Alpha:', alpha_reg)
Beta 0.7079843244326955 Beta from Reg: 0.7079843244326959 Alpha: -0.0018562495855438549
\(\beta\)は、公式に従う場合、回帰分析で求めた場合、当然ですが、ともにほぼ同じ値となっています。
また、 \(\alpha\) が負になっており、無リスク資産の収益率が2%であると仮定した場合、バークシャーハサウェイは CAPM では割高になっていると考えられます。
期待収益率の計算と図示
CAPMの下での期待収益率を計算し、またモデルを図示します。
import datetime import matplotlib.pyplot as plt import numpy as np import pandas as pd import scipy.optimize from pandas_datareader import data as pdr import yfinance as yf import requests_cache # override pandas_datareader yf.pdr_override() # casche for downloaded data expire_after = datetime.timedelta(days=3) session = requests_cache.CachedSession(cache_name='cache', backend='sqlite', expire_after=expire_after) # '^GSPC' is S&P 500 index ticker STOCKS = ['BRK-A', '^GSPC'] START = pd.to_datetime('2010-01-01') END = pd.to_datetime('2020-01-01') RISK_FREE_RATE = 0.02 def download_data_adjclose(stocks): data = pdr.get_data_yahoo(stocks, start=START, end=END)['Adj Close'] return data def calc_monthly_returns(data): data = data.resample('M').mean() returns = np.log(data/data.shift(1)) # drop NAN for np.polyfit returns.dropna(inplace=True) return returns def calc_beta(returns): cov_matrix = np.array(returns.cov()) # print(cov_matrix) beta = cov_matrix[0, 1] / cov_matrix[1, 1] return beta def regression_beta_alpha(returns): beta, alpha = np.polyfit((np.array(returns.iloc[:, 1])-RISK_FREE_RATE), (np.array(returns.iloc[:, 0])-RISK_FREE_RATE) , deg=1) return beta, alpha if __name__ == '__main__': data = download_data_adjclose(STOCKS) # print(data.head()) # print(data.tail()) returns = calc_monthly_returns(data) # print(returns.head()) # print(returns.tail()) # returns.plot() # plt.show() # returns.hist(bins=100) # plt.show() beta = calc_beta(returns) print('Beta', beta) beta_reg, alpha_reg = regression_beta_alpha(returns) print('Beta from Reg:',beta_reg, 'Alpha:', alpha_reg) expected_return = RISK_FREE_RATE + \ beta*(returns.iloc[:, 1].mean()*12-RISK_FREE_RATE) print('Expected Return', expected_return) # plot results fig, axis = plt.subplots(1) axis.scatter(returns.iloc[:, 1]-RISK_FREE_RATE, returns.iloc[:, 0]-RISK_FREE_RATE, label='Data') axis.plot(returns.iloc[:, 1]-RISK_FREE_RATE, beta_reg*(returns.iloc[:, 1]-RISK_FREE_RATE)+alpha_reg, color='red', label='CAPM REG line') plt.legend() plt.grid(True) plt.xlabel('MarketReturn - RiskFreeRate') plt.ylabel('StockReturn - RiskFreeRate') plt.text(-0.025, 0.03, r'$E(R_i) – R_f = {\beta}_i (E(R_m)−R_f) + {\alpha}_i $') plt.show()
Beta 0.7079843244326955 Beta from Reg: 0.7079843244326959 Alpha: -0.0018562495855438549 Expected Return 0.07996021496399774