ストックドッグ

KatoTakahiro。金融系の会社で働くSEが株やPython、その他諸々について書いています。サービスも運営してます→http://fmbrain.work

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ソースコードで使われているデータを使用しています。

github.com

期待リターンを求める企業だけが日本企業というちぐはぐっぷりですが...

理論と実装方法がメインの記事なので気にしません。


以下から市場リスクプレミアム、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を実装したときのコードを参考にしてください。

www.stockdog.work


ここでは、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