3ファクターモデルをPythonで実装して期待リターンを求める
3ファクターモデルとは
CAPMを発展させた理論です。
CAPMは、市場のリスクプレミアムのみで期待リターンを求めています。
#CAPM 個別株の期待リターン = β * (市場リスクプレミアム - 無リスク金利) + 無リスク金利
CAPMはとてもシンプルで金融市場の値動きの本質を表しているのですが、シンプルゆえときに値動きを説明できないタイミングあります。
そのため、もう少し変数を加えて細かく金融市場の値動きを説明してみよう、というのが3ファクターモデルです。
名前の通り、ファクター(変数)が3つです。
- 市場リスクプレミアム
- 小型株ファクター(SMB)
- サイズファクター(HML)
それぞれのファクターのβを計算し、個別株の期待リターンを求めます。
3ファクターモデルの計算式
個別株の期待リターン = β * 市場リスクプレミアム + SMB'β * SMB + HML'β * HML + 無リスク金利
CAPMにでてこないファクターであるSMBとHMLについて説明します。
SMBとは
SMB : Small minus Big
小型株のパフォーマンスと大型株のパフォーマンスの差を表しています。
多くの分析から、小型株は大型株よりも高いリターンを出すことがわかっています。
小型株を保有したときの、期待リターンをSMBという指標によって考慮します。
SMBは時価総額によって、企業を2つに分類します。
企業規模(Small size,Big size)
HMLとは
HML : High minus Low
簿価時価比率が高い銘柄と低い銘柄のパフォーマンスの差です。
簿価時価比率 = 簿価 / 時価
簿価時価比率が高ければ、簿価が評価されておらず、時価がついてきていないということになります。
そのため、会社の価値はあるが市場が高い値をつけていないバリュー株ということになります。
簿価時価比率は、PBRの逆数で求めることができます。
PBR = 時価 / 一株当たり純資産
これの逆数なので...
簿価時価比率 = 一株当たり純資産 / 時価
一株当たり純資産は、帳簿上の解散価値です。つまり、1株あたりのの帳簿上の価値を表しています。
そのため、簿価として一株当たり純資産を使うってことですね。(たぶん)
簿価時価比率によって企業を3つに分類します。
簿価時価比率(Low BM,Medium BM,High BM)
SMBとHMLを計算式
企業規模(Small size,Big size)と簿価時価比率(Low BM,Medium BM,High BM)の組み合わせで,次の6つのポートフォリオに分割します。
簿価時価比率(低) | 簿価時価比率(中) | 簿価時価比率(大) | |
時価総額(小) | (1).Small size-Low BM(S/LB) | (2).Small size-Medium BM(S/MB) | (3).Small size-High BM(S/HB) |
時価総額(大) | (4).Big size-Low BM(B/LB) | (5).Big size-Medium BM(B/MB) | (6).Big size-High BM(B/HB) |
SMB =( (1) + (2) + (3) )/3 - ( (4) + (5) + (6) )/3 HML =( (3) + (6) )/2-( (1) + (4) )/2,
このSMBとHMLは市場全ての企業を対象に計算します。
日本市場であれば、市場全ての企業 = 東証1部 が適切かな、と思います。
これで3ファクターモデルの式に出てくる変数が全て出揃いました。
個別株の期待リターン = β * 市場リスクプレミアム + SMB'β * SMB + HML'β * HML + 無リスク金利
実際は、以下の線形回帰式を最小二乗法でそれぞれのファクターのベータを求めます。
y = ax + a2x2 + a3x3 + b
Pythonで実装
注意!!ここから適当なところあります
3ファクターモデルを計算するには、過去の株価だけではなく、時価総額と時価簿価比率のデータが必要です。
集めてくるのがとっても面倒です。
なので、アメリカの市場のリスクプレミアムとSMLとHMLのデータがあるので、それを使うことにしました...笑
以下のgithubのソースコードで使われているデータを使用しています。
期待リターンを求める企業だけが日本企業というちぐはぐっぷりですが...
理論と実装方法がメインの記事なので気にしません。
以下から市場リスクプレミアム、HML、SMLのデータを取得します。
http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/F-F_Research_Data_Factors_CSV.zip
データを扱いやすい形に整形します。
データは2000年以降のものにフィルタリングします。
import pandas as pd import numpy as np import datetime import os, sys corrent_dir = os.getcwd() os.chdir("../") sys.path.append(os.getcwd()) import scraping_stock os.chdir(corrent_dir) FFdata = pd.read_csv("F-F_Research_Data_Factors.CSV", header = 0, names = ["Date","MKT-RF","SMB","HML","RF"], skiprows=3) FFdata = FFdata[:1074] for i in range(len(FFdata)): d = FFdata["Date"].iloc[i] FFdata["Date"].iloc[i] = datetime.datetime(int(d[0:4]), int(d[4:6]), 1, 0, 0, 0, 0)# print(FFdata.head(10)) # print(FFdata.tail(10)) FFdata = FFdata.loc[FFdata["Date"] >= datetime.datetime(2000, 1, 1, 0, 0, 0, 0)] FFdata = FFdata.sort_values("Date", ascending=True)
上記のデータが2000年01月から2015年12月までなので、同じ期間のNTTデータ(9613)の株価を取得します。
株価取得のコードはMPTを実装したときのコードを参考にしてください。
ここでは、2000年01月から2015年12月の期間のデータが既にあるとして、データの整形にはいります。
stock = 9613 # scraping_stock.scraping(stock, days=5475 , term="m") df = pd.read_csv("../data/code_{0}.csv".format(stock)) df = df.dropna(how="any") # Datetime形式に変換 date_format = "%Y年%m月" for i in range(len(df)): df["Date"].iloc[i] = datetime.datetime.strptime(df["Date"].iloc[i], date_format) df = df.sort_values("Date", ascending=True) # 必要なデータを切り出し tmp_df = df.loc[:, ["Date", "Adj Close"]] # リターンを計算する # tmp_df["Return"] = np.log(tmp_df["Adj Close"]) - np.log(tmp_df["Adj Close"].shift(1)) tmp_df["Return"] = tmp_df["Adj Close"].pct_change()
2つのデータを1つのDataFrameにまとめます。
data = pd.merge(FFdata, tmp_df, on="Date") data.index = data["Date"].values data = data.drop("Date", axis=1) data = data.astype(float) data = data.dropna(how="any") print(data.head()) # リターンから無リスク金利をひきます data["XReturn"] = data["Return"] * 100 - data["RF"].astype(float)
3ファクターモデルに基づいて、期待リターンを計算していきます。
それぞれのファクターのβは、60ヶ月分のデータから求めます。
個別株の期待リターン(60ヶ月分) = β * 市場リスクプレミアム(60ヶ月分) + SMB'β * SMB(60ヶ月分) + HML'β * HML(60ヶ月分) + 無リスク金利
求めたβを使って、個別株の期待リターンを求めます。
市場のリスクプレミアムとSMBとHMLは、持ちうるデータの最大期間を使って個別株の期待リターンを求めます。
個別株の期待リターン = β * 市場リスクプレミアム(最大期間) + SMB'β * SMB(最大期間) + HML'β * HML(最大期間) + 無リスク金利
import statsmodels.api as sm # 60ヶ月 t = 60 tf_list = [] # 2000 ~ 2015年まで計算 for i in range(11, len(data)-t, 12): # 最大期間を取得 MKT_RF = data.iloc[0:i+t, [0]].mean().values[0]#"MKT-RF" SMB = data.iloc[0:i+t, [1]].mean().values[0]#"SMB" HML = data.iloc[0:i+t, [2]].mean().values[0]#"HML" RF = data.iloc[i+t, [3]].values[0] print("MKT-RF : ", MKT_RF, "SMB : ", SMB, "HML : ", HML) # 60ヶ月分 tmp_data = data.ix[i:i+t] print(tmp_data) # 3ファクターモデルを計算 y = tmp_data["XReturn"] X = tmp_data.loc[:, ["MKT-RF", "SMB", "HML"]] X = sm.add_constant(X) model = sm.OLS(y, X) results = model.fit() # print(results.summary()) alpha, beta, smb_beta, hml_beta = results.params print(alpha, beta, smb_beta, hml_beta) # 求めたβで期待リターンを計算 expected_return = (beta * MKT_RF) + (smb_beta * SMB) + (hml_beta * HML) + alpha + RF # 求めた期待リターンは、月間でもデータなので年率に変換 print(expected_return * 12)
いちおう結果
2006 ~ 2015年の期間でNTTデータの期待リターンを3ファクターモデルで求め、実際のリターンを比較しました。
3ファクターモデルで求めた期待リターン
年 | 期待リターン |
---|---|
2006 | 3.380415% |
2007 | 15.638408% |
2008 | 19.402995% |
2009 | 3.269230% |
2010 | 3.621298% |
2011 | -10.057815% |
2012 | -9.765555% |
2013 | -6.118449% |
2014 | 5.041712% |
2015 | 11.430143% |
実際のNTTデータの期待リターン
年 | 期待リターン |
---|---|
2006 | 3.189316966221089% |
2007 | -15.716405993233739% |
2008 | -27.606051376861046% |
2009 | -14.094971477913244% |
2010 | 0.8188833324962229% |
2011 | -10.280445385445681% |
2012 | 13.43885732894585% |
2013 | 39.04595333427926% |
2014 | 17.567901291557355% |
2015 | 27.7547208081126% |
ちなみにアメリカの市場のリスクプレミアム、SMB、HMLを使っているで本当に結果に意味はありません。
考察するに値しないので、結果としてはこういった形で出る、というくらいです。
参考
計算式はこの論文を参考にしています。
http://www2.itc.kansai-u.ac.jp/~koji_ota/Paper/PublishedPaper/Ota_2012_Shogakuronshu.pdf
データはこのgithubのコードに使われているものを参考にしています。
https://github.com/nakulnayyar/FF3Factor/blob/master/FamaFrench3Factor.ipynb