定量分析のはじめかた4
今回は「資本資産価格モデル」、CAPMについて解説をいたします。理論的な背景は大事にしつつ、Pythonによるコード事例を紹介した解説を行っています。
資本資産価格モデル(CAPM)とは?
資産の期待リターンと市場のシステマティックリスクの関係を説明するものです。この式から、資産が市場全体に対してどれだけリスクを持つのか、そしてそのリスクに対してどれだけのリターンが期待できるのかを計算することができますね。
CAPMの公式
数学的には、CAPMの公式を以下のように定義することができます。
ri = 資産iの期待収益率 (算出結果=期待リターン)
rf = リスクフリーレート(無リスク利子率)
rm = 市場の期待収益率
βi = 資産iのβ(ベータ)係数
なるほど、よくわからんとなるので、いくつか前提となる用語をまとめておきました。
rf = リスクフリーレート(無リスク利子率)
リスクが最小でリスク・フリーに近い金融商品から得られる利回りのことで、「 rf 」と表記されます。
例えば、T-Notes(米国債)の利回り、預貯金による利息などがあります。CAPMはリスクフリーレート=rf が存在すると仮定して計算を行います。
# リスクフリーレート(サンプルで0.01 = 1%としています。)
risk_free_rate = 0.01
rm = マーケットリターン(市場リターン)
マーケットリターン(市場リターン)は特定の市場における全体的なリターンを示す指標で「rm」と表記されます。代表的なポートフォリオで利用されるケースとして、米国市場であればS&P500というインデックスが該当します。
※S&P500は、米国上場500社の時価総額を加重した指数ですね。
マーケットリターンを取得する関数
def get_index_data(symbol: str, start: str, end: str) -> pd.DataFrame:
""" SP500 の時系列データ取得 """
start = datetime.strptime(start, '%Y,%m,%d')
end = datetime.strptime(end, '%Y,%m,%d')
df = web.DataReader(symbol, 'stooq', start, end)
df.sort_index(inplace=True)
return df
def get_index_return(symbol: str, start: str, end: str) -> pd.Series:
""" SP500 のリターンの取得 """
index_data = get_index_data(symbol, start, end)['Close'].pct_change()
index_data.name = 'Return' # シリーズの名前を'Return'に設定
return index_data
# SP500のリターンを取得(2020年7月31日~2023年7月31日)
symbol = "^SPX" # シンボルは文字列で指定
market_return = get_index_return(symbol, "2020,7,31", "2023,7,31")
β = ベータ
ベータは資産のリターンが市場全体(S&P500など)と、どの程度の連動性があるかを測定します。例えば、市場リターンが1%増加した場合、資産のリターンがどれぐらい増加するかを、ベータ(β)という尺度ではかります。
CAPMにおいて、システマティック・リスク(市場リスク)と資産の期待リターンとの関係を表すために使用されます。
市場全体のベータは1.0であり、個別銘柄は市場に対するボラティリティの高さでランク付けされ、リスク分析としてリスクの度合いを評価したり、ポートフォリオ戦略として、特定のセクターやリスクプロファイルに合わせてポートフォリオを構築したい場合、ベータ値を用いて銘柄の選定やウェイト調整を行うことが一般的です。
ベータを取得する関数
# 個別銘柄のβを取得
def calculate_beta(stock_return: pd.Series, market_returns: pd.Series) -> float:
covariance = np.cov(stock_return, market_return)[0][1]
variance = np.var(market_returns)
beta = covariance / variance
return beta
βが1.0の場合、その価格は市場と正相関、つまり市場と同等の連動性であることを意味します。
ベータ<1.0の場合、「ディフェンシブ」と呼ばれ、理論的にはその証券が市場よりも変動が小さいことを示します=値動き(リスク)が低い
ベータ>1.0の場合、「アグレッシブ」と呼ばれ、その資産価格が市場よりも変動が大きいことを示します=値動き(リスク)が高いとみなします。
複数銘柄の株価リターンを取得
予め株価リターンを計算し、株価リターン(AAPL)を用いて、ベータの算出、CAPMの計算から期待リターンを算出します。
以下のソースコードでは、指定した銘柄リストを作成し、複数の株価リターンを取得できるようにしています。
対象の株価リターンを操作する場合、stocks_returns["AAPL"]のようにして、個別銘柄を指定することができます。
def get_stock_data(symbol: str, start: str, end: str) -> pd.DataFrame:
start = datetime.strptime(start, '%Y,%m,%d')
end = datetime.strptime(end, '%Y,%m,%d')
df = web.DataReader(f"{symbol}.US", 'stooq', start, end)
df.sort_index(inplace=True)
return df
def get_stocks_close(symbols: Union[str, list], start: str, end: str) -> pd.DataFrame:
if isinstance(symbols, str):
symbols = [symbols]
stocks = {}
for symbol in symbols:
stocks[symbol] = get_stock_data(symbol, start, end)['Close']
return pd.DataFrame(stocks)
def get_stocks_returns(symbols: list, start: str, end: str) -> pd.DataFrame:
stocks = {}
# get_stocks_close を呼び出す時にsymbolsリストを渡す
closes = get_stocks_close(symbols, start, end)
for symbol in symbols:
# 各銘柄のClose価格の取得
close = closes[symbol]
# リターンの計算
stocks[symbol] = close.pct_change() * 100
return pd.concat(stocks, axis=1)
stocks = ["AAPL", "GOOGL", "AMZN", "MSFT"]
stocks_returns = get_stocks_returns(stocks, "2021,7,31", "2023,7,31")
stocks_returns.tail(10)
個別銘柄のベータ
上記の株価リターン(stocks_returns)からデータを取得することができました。続いて、stocks_returns["AAPL"]のリターンデータを用いて、個別銘柄ベータを算出してみましょう。
以下の関数を用いて、AAPLのベータを取得します。
def calculate_beta(asset_returns: pd.Series, market_returns: pd.Series) -> float:
""" betaの計算 """
covariance = np.cov(asset_returns, market_returns)[0][1]
variance = np.var(market_returns)
beta = covariance / variance
return beta
stock_return = stocks_returns['AAPL'].dropna()
market_return = market_return.dropna()
beta_aapl = calculate_beta(stock_return, market_return)
print(beta_appl)
>>> 1.33303...
AAPLのβは 1.33303 という計算結果でした。
つまり、市場(SP500)に対して1.33%の変動性があり、市場が1%上昇すればAAPLはおおよそ1.33%上昇することが期待されます。
個別銘柄のCAPM
続いて、AAPLをベースにCAPMフレームワークを用いて、期待収益率を計算してみましょう。先にCAPMを計算する関数を実装しておきます。
この関数は前述した、数式をベースに定義しています。
# CAPMの計算 (リスクフリーレートと市場リターンはサンプルとして設定)
def get_capm(beta: float, market_return: float, risk_free_rate: float) -> float: """ CAPMを求める """
return risk_free_rate + beta * (market_return - risk_free_rate)
※CAPMを算出するために、市場(銘柄)の期待収益率の平均とベータ係数を算出する必要があります。
# リスクフリーレート(サンプルで0.01 = 1%)
risk_free_rate = 0.01
# マーケットリターンの平均を算出
average_market_return = market_return.mean()
# CAPMから期待リターンを算出
expected_return = get_capm(beta, average_market_return, risk_free_rate)
print(expcted_return)
>>> 0.06318...
期待収益率(expceted_return)は 0.06318 (=6.3%)という結果になりました。単純すぎる内容のため、この銘柄の期待収益率が市場全体やベンチマークと比較してどうか?期待収益率ではなく、その銘柄もつリスク(ボラティリティやβ)も考慮する必要があります。
CAPMはポートフォリオ型のフレームワークの為、複数の銘柄での期待収益率を見てみましょう。
ポートフォリオ型のβ/CAPMの算出
# 各銘柄のウェイト(ここでは25%に等分)
weights = np.array([0.25, 0.25, 0.25, 0.25])
portfolio_return = (stock_return * weights).sum(axis=1)
covariance_portfolio_market = np.cov(portfolio_return, market_return)[0][1]
variance_market = np.var(market_return)
portfolio_beta = covariance_portfolio_market / variance_market
portfolio_expected_return = risk_free_rate + portfolio_beta * (expected_market_return - risk_free_rate)
print("ポートフォリオのベータ値:", portfolio_beta)
print("ポートフォリオのCAPMに基づく期待リターン:", portfolio_expected_return)
ポートフォリオのベータ値: 1.359995…(およそ35.9%)
ポートフォリオのCAPMに基づく期待リターン: 0.105199…(およそ10%)
の期待収益率を算出できました。
理論の提唱者であるハリー・M・マーコウィッツは、この理論を開発する過程で、投資ポートフォリオを効率的に構築する方法を提供しました。個別資産の期待収益率が、無リスク利率と市場ポートフォリオの超過収益に対する感応度(ベータ係数)に基づいて決定されることを前提にしています。
投資家は自分のリスク許容度に応じて、最適なリスクとリターンのバランスを達成したポートフォリオを作成するという、合理的な行動に基づいており、未来の株価を予測するものではありません。
しかし、より高度なアプローチとして、リスクファクターモデルの構築や、投資の選定基準を明確にする最小分散アプローチ、効率的フロンティアの算出など応用的な定量アプローチを目指すことができますね(ひいらぎ)
【C102 東ピ18ab】Starsand Plane 新刊告知
さて、もう明後日になりますが、8/13(日)にコミックマーケット102に参加することになり、最終の準備を行っています。
同人誌の中身は以下の詳細ページにサンプルがありますが、私のパートでは、全体的にプログラミングを主体とした金融のアプローチを中心に執筆しています。
ボリュームが多くなりましたが、上記のように解説とプログラミングをメインにしており、わかりやすい内容を意識しました(あまり小難しい書き方を意識して、例えば話を盛り込んだりして平易な文章にしています)
■詳細ページ
https://www.pixiv.net/artworks/110495832
日時:23年8月13日(日) 東5ホール 東ピ 18ab
サークル名:Starsand Planet
SP本②
A Deep Dive into Financial Landscape.
著者 黒猫アイランド・松崎美子・ひいらぎ
売り子:逢坂みぁさん(https://twitter.com/mia_xqx)
と当日もう一人予定しており、お待ちしております。
台風の動向が気になりますが、天気予報をみてるとだいぶ停滞している模様。。開催中の交通機関等も大丈夫だと思いますが、翌日の新幹線や飛行機など、帰りに影響を受ける方もいらっしゃると思います。天候が変わりやすいので、こまめなチェックをお願いいたします。
また、当日は大変蒸し暑くなっていると思いますので、こまめな水分補給と睡眠など熱中症対策はお願いします。皆さま、どうかお気をつけてお越しください(ひいらぎ@夏バテ)
この記事が気に入ったらサポートをしてみませんか?