用 Python 實(shí)現(xiàn)資本資產(chǎn)定價(jià)模型
Python中文社區(qū)(ID:python-china)
在本文中,我們將學(xué)習(xí)如何計(jì)算資本資產(chǎn)定價(jià)模型 (CAPM) 并獲得貝塔系數(shù)。資本資產(chǎn)定價(jià)模型(Capital Asset Pricing Model 簡(jiǎn)稱CAPM)是由美國(guó)學(xué)者于1964年在資產(chǎn)組合理論和資本市場(chǎng)理論的基礎(chǔ)上發(fā)展起來的,主要研究證券市場(chǎng)中資產(chǎn)的預(yù)期收益率與風(fēng)險(xiǎn)資產(chǎn)之間的關(guān)系,以及均衡價(jià)格是如何形成的,是現(xiàn)代金融市場(chǎng)價(jià)格理論的支柱,廣泛應(yīng)用于投資決策和公司理財(cái)領(lǐng)域。CAPM 被認(rèn)為是一個(gè)單因子模型,在其之上可以建立更復(fù)雜的因子模型。(掃描本文最下方二維碼獲取全部完整源碼和Jupyter Notebook 文件打包下載。)
CAPM 由以下等式表示:
這里,E(ri) 表示資產(chǎn) i 的預(yù)期收益,rf是無風(fēng)險(xiǎn)利率(例如政府債券),E(rm) 是市場(chǎng)的預(yù)期收益,β 是貝塔系數(shù)。β 可以解釋為資產(chǎn)收益的敏感度水平,相對(duì)于一般市場(chǎng)水平。β 的一些情況包括:
- β <= -1:資產(chǎn)向與市場(chǎng)基準(zhǔn)相反的方向移動(dòng),并且大于基準(zhǔn)的負(fù)值。
- -1 < β < 0:資產(chǎn)向與市場(chǎng)基準(zhǔn)相反的方向移動(dòng)
- β = 0:資產(chǎn)的價(jià)格變動(dòng)與市場(chǎng)基準(zhǔn)一致。
- 0 < β < 1:資產(chǎn)與市場(chǎng)同向運(yùn)動(dòng),但金額較小。一個(gè)例子是一家公司的股票價(jià)格容易受到日常市場(chǎng)波動(dòng)的影響。
- β = 1:資產(chǎn)和市場(chǎng)正朝著同一方向移動(dòng)相同數(shù)量。
- β > 1:資產(chǎn)與市場(chǎng)同向運(yùn)動(dòng),但金額更大。一個(gè)例子是一家公司的股票非常容易受到每日市場(chǎng)新聞的影響。
CAPM 也可以表示為:
這里,等式的左邊可以解釋為風(fēng)險(xiǎn)溢價(jià),而右側(cè)包含市場(chǎng)溢價(jià)。相同的等式可以改寫為:
其中:
在這個(gè)例子中,我們以亞馬遜股票為例并假設(shè)標(biāo)普 500 指數(shù)代表市場(chǎng)。我們使用 5 年(2014-2018 年)的月度數(shù)據(jù)來估計(jì) β。在當(dāng)前,無風(fēng)險(xiǎn)利率如此之低,為了簡(jiǎn)單起見,我們假設(shè)它等于零。
執(zhí)行以下步驟以在 Python 中實(shí)現(xiàn) CAPM:
1、導(dǎo)入第三方庫(kù):
- import pandas as pd
- import yfinance as yf
- import statsmodels.api as sm
2、指定風(fēng)險(xiǎn)資產(chǎn)和時(shí)間范圍:
- RISKY_ASSET = 'AMZN'
- MARKET_BENCHMARK = '^GSPC'
- START_DATE = '2014-01-01'
- END_DATE = '2018-12-31'
3、從雅虎財(cái)經(jīng)下載必要的數(shù)據(jù):
- df = yf.download([RISKY_ASSET, MARKET_BENCHMARK],
- start=START_DATE,
- end=END_DATE,
- adjusted=True,
- progress=False)
4、重新采樣到每月數(shù)據(jù)并計(jì)算簡(jiǎn)單的回報(bào):
- X = df['Adj Close'].rename(columns={RISKY_ASSET: 'asset',
- MARKET_BENCHMARK: 'market'}) \
- .resample('M') \
- .last() \
- .pct_change() \
- .dropna()
5、使用協(xié)方差方法計(jì)算 β 值:
- covariance = X.cov().iloc[0,1]
- benchmark_variance = X.market.var()
- beta = covariance / benchmark_variance
代碼的結(jié)果是 β = 1.6709。
6、準(zhǔn)備輸入并將 CAPM 估計(jì)為線性回歸:
- y = X.pop('asset')
- X = sm.add_constant(X)
- capm_model = sm.OLS(y, X).fit()
- print(capm_model.summary())
下圖顯示了估計(jì) CAPM 模型的結(jié)果:
這些結(jié)果表明貝塔系數(shù)(此處表示為market)等于 1.67,這意味著亞馬遜股票的回報(bào)比市場(chǎng)波動(dòng)性高 67%(由標(biāo)準(zhǔn)普爾 500 指數(shù)表示市場(chǎng)走勢(shì))。截距的值比較小,在 5% 的顯著性水平上統(tǒng)計(jì)不顯著。
首先,我們指定了我們想要使用的資產(chǎn)(亞馬遜和標(biāo)普 500 指數(shù))和時(shí)間范圍。在第 3 步中,我們從雅虎財(cái)經(jīng)下載了數(shù)據(jù)。然后,我們只保留了最后一個(gè) 每月可用價(jià)格并計(jì)算每月回報(bào)的百分比變化。
在第 5 步中,我們將 β 計(jì)算為風(fēng)險(xiǎn)資產(chǎn)與基準(zhǔn)方差之間的協(xié)方差之比。
在第 6 步中,我們將目標(biāo)(亞馬遜的股票收益)和特征(標(biāo)準(zhǔn)普爾 500 收益)使用 pandas DataFrame 的 pop 方法。之后,我們添加了常量,使用add_constant函數(shù)添加到特征(有效地添加一列)。這將截距添加到此回歸背后的想法是調(diào)查在估計(jì)模型——截距(在 CAPM 的情況下,也稱為 Jensen's alpha) 是否為零。如果它是積極的和顯著的,這意味著——假設(shè) CAPM 模型是真——資產(chǎn)或投資組合會(huì)產(chǎn)生異常高的風(fēng)險(xiǎn)調(diào)整回報(bào)。那么有兩個(gè)可能的影響——要么市場(chǎng)效率低下,要么還有其他一些未被發(fā)現(xiàn)的模型中應(yīng)包含的風(fēng)險(xiǎn)因素。這個(gè)問題被稱為聯(lián)合假設(shè)問題。
最后,我們運(yùn)行 OLS 回歸并打印摘要。在這里,我們可以看到market 變量的系數(shù)(即 CAPM beta)等于計(jì)算步驟 5 中資產(chǎn)與市場(chǎng)之間的協(xié)方差。
在主要示例中,我們假設(shè)沒有無風(fēng)險(xiǎn)利率,這是一個(gè)合理的假設(shè)。但是,在某些情況下,我們可能希望考慮非零無風(fēng)險(xiǎn)利率。在本節(jié)中,我們將介紹三種可能的方法:
- 使用 Kenneth French 教授網(wǎng)站的數(shù)據(jù):市場(chǎng)溢價(jià) (rm-rf) 和 無風(fēng)險(xiǎn)利率(近似于 1 個(gè)月的國(guó)庫(kù)券)可以從 Kenneth French 教授的網(wǎng)站下載。該指數(shù)不同于標(biāo)準(zhǔn)普爾 500 指數(shù)——他的網(wǎng)站上有詳細(xì)說明。
- 第二種選擇是近似無風(fēng)險(xiǎn)利率,例如,13 周(3個(gè)月)國(guó)庫(kù)券(雅虎金融股票代碼:^IRX)。
請(qǐng)按照以下步驟了解如何下載數(shù)據(jù)并將其轉(zhuǎn)換為適當(dāng)?shù)臒o風(fēng)險(xiǎn)利率。
1、以天為單位定義期間的長(zhǎng)度:
- N_DAYS = 90
2、從雅虎財(cái)經(jīng)下載數(shù)據(jù):
- df_rf = yf.download('^IRX', start=START_DATE, end=END_DATE)
3、將數(shù)據(jù)重新采樣為每月頻率(通過為每個(gè)月取最后一個(gè)值):
- rf = df_rf.resample('M').last().Close / 100
4、計(jì)算無風(fēng)險(xiǎn)收益(表示為每日值)并將值轉(zhuǎn)換為月收益:
- rf = ( 1 / (1 - rf * N_DAYS / 360) )**(1 / N_DAYS)
- rf = (rf ** 30) - 1
5、繪制計(jì)算出的無風(fēng)險(xiǎn)利率:
- rf.plot(title='Risk-free rate (13 Week Treasury Bill)')
下圖顯示了無風(fēng)險(xiǎn)利率隨時(shí)間的可視化:
- 最后一種方法是使用 3 個(gè)月期國(guó)庫(kù)券來估算無風(fēng)險(xiǎn)利率,可以從美聯(lián)儲(chǔ)經(jīng)濟(jì)數(shù)據(jù) (FRED) 數(shù)據(jù)庫(kù)下載。請(qǐng)按照以下步驟學(xué)習(xí)如何下載數(shù)據(jù)并將其轉(zhuǎn)換為每月無風(fēng)險(xiǎn)利率:
1、導(dǎo)入第三方庫(kù):
- import pandas_datareader.data as web
2、從 FRED 數(shù)據(jù)庫(kù)下載數(shù)據(jù):
- rf = web.DataReader('TB3MS', 'fred', start=START_DATE,
- end=END_DATE)
3、將獲得的無風(fēng)險(xiǎn)利率轉(zhuǎn)換為月值:
- rf = (1 + (rf / 100)) ** (1 / 12) - 1
4、繪制計(jì)算出的無風(fēng)險(xiǎn)利率:
- rf.plot(title='Risk-free rate (3-Month Treasury Bill)')
我們可以通過比較兩個(gè)方法的圖來比較兩種方法的無風(fēng)險(xiǎn)利率:
我們可以看出來這些圖都非常相似。