用 Python 分析資產收益的典型化事實
Python中文社區(ID:python-china)
典型化事實(Stylized Facts)是在實際數據中發現的一些現象。“典型化事實”在經濟學中非常重要,無論是宏觀經濟學還是貿易、金融還是產業經濟學,在理論的發展中都扮演著非常重要的角色,因而如果能發現一些“典型化事實”,對經濟學的理論研究和之后的實證研究是非常重要的。掃描本文最下方二維碼獲取全部完整源碼和Jupyter Notebook 文件打包下載。
典型化事實(Stylized Facts)是出現在許多資產回報(跨時間和市場)中的統計屬性。了解它們很重要,因為當我們構建代表資產價格動態的模型時,模型必須能夠捕獲這些屬性。
下面我們使用從 1985 年到 2018 年標普 500 指數的每日回報收益來分析五個典型化事實。
我們從雅虎財經下載標準普爾 500 指數價格并計算收益。使用以下代碼導入所有需要的庫:
- import pandas as pd
- import numpy as np
- import yfinance as yf
- import seaborn as sns
- import scipy.stats as scs
- import statsmodels.api as sm
- import statsmodels.tsa.api as smt
在本節中,我們將用 Python去發現標準普爾 500 指數系列中的五個典型化事實。
- df = yf.download('^GSPC',
- start='1985-01-01',
- end='2018-12-31',
- progress=False)
- dfdf = df[['Adj Close']].rename(columns={'Adj Close': 'adj_close'})
- df['log_rtn'] = np.log(df.adj_close/df.adj_close.shift(1))
- dfdf = df[['adj_close', 'log_rtn']].dropna(how = 'any')
一、資產收益的非高斯分布
運行以下步驟,通過繪制收益直方圖和 Q-Q 圖來發現第一個事實的存在。
1、使用觀察到的收益的均值和標準差計算正態概率密度函數 (PDF):
- r_range = np.linspace(min(df.log_rtn), max(df.log_rtn), num=1000)
- mu = df.log_rtn.mean()
- sigma = df.log_rtn.std()
- norm_pdf = scs.norm.pdf(r_range, loc=mu, scale=sigma)
2、繪制直方圖和 Q-Q 圖:
- fig, ax = plt.subplots(1, 2, figsize=(16, 8))
- # histogram
- sns.distplot(df.log_rtn, kde=False, norm_hist=True, axax=ax[0])
- ax[0].set_title('Distribution of S&P 500 returns', fontsize=16)
- ax[0].plot(r_range, norm_pdf, 'g', lw=2,
- label=f'N({mu:.2f}, {sigma**2:.4f})')
- ax[0].legend(loc='upper left');
- # Q-Q plot
- qq = sm.qqplot(df.log_rtn.values, line='s', axax=ax[1])
- ax[1].set_title('Q-Q plot', fontsize = 16)
- # plt.tight_layout()
- # plt.savefig('images/ch1_im10.png')
- plt.show()
執行上面的代碼會產生下圖:
我們可以使用直方圖(顯示分布的形狀)和 Q-Q 圖來評估收益的正態性。此外,我們可以打印匯總統計信息:
通過查看均值、標準差、偏度和峰度等指標,我們可以推斷它們偏離我們在正態下的預期。此外,Jarque-Bera 正態性檢驗讓我們有理由拒絕原假設,即在 99% 置信水平下分布是正態的。
二、波動集聚性
運行以下代碼,通過繪制收益序列來發現第二個典型化事實。
1、可視化收益序列:
- df.log_rtn.plot(title='Daily S&P 500 returns', figsize=(10, 6))
執行代碼會產生下圖:
我們可以觀察到明顯的波動集聚性——波動較大的正收益和負收益時期。
三、收益不存在自相關性
我們繼續去發現第三個典型化事實。
1、定義用于創建自相關圖的參數:
- N_LAGS = 50
- SIGNIFICANCE_LEVEL = 0.05
2、運行以下代碼以創建收益的自相關函數 (ACF) 圖:
- acf = smt.graphics.plot_acf(df.log_rtn,
- lags=N_LAGS,
- alpha=SIGNIFICANCE_LEVEL)
執行上面的代碼會產生下圖:
只有少數值位于置信區間之外并且可以被認為具有統計顯著性。我們可以假設已經驗證了收益序列中沒有自相關性。
四、平方/絕對收益的自相關性小且遞減
通過創建平方和絕對收益的 ACF 圖來研究第四個典型化事實。
1、創建 ACF 圖:
- fig, ax = plt.subplots(2, 1, figsize=(12, 10))
- smt.graphics.plot_acf(df.log_rtn ** 2, lags=N_LAGS,
- alpha=SIGNIFICANCE_LEVEL, axax = ax[0])
- ax[0].set(title='Autocorrelation Plots',
- ylabel='Squared Returns')
- smt.graphics.plot_acf(np.abs(df.log_rtn), lags=N_LAGS,
- alpha=SIGNIFICANCE_LEVEL, axax = ax[1])
- ax[1].set(ylabel='Absolute Returns',
- xlabel='Lag')
執行上面的代碼會產生以下圖:
我們可以觀察到平方回報和絕對回報的自相關值很小且不斷減小,這與第四種典型化事實一致。
五、杠桿效應
對于第五個事實,運行以下步驟來調查杠桿效應的存在。
1、將波動性度量計算為滾動標準偏差:
- df['moving_std_252'] = df[['log_rtn']].rolling(window=252).std()
- df['moving_std_21'] = df[['log_rtn']].rolling(window=21).std()
2、繪制所有系列以進行比較:
- fig, ax = plt.subplots(3, 1, figsize=(18, 15),
- sharex=True)
- df.adj_close.plot(axax=ax[0])
- ax[0].set(title='S&P 500 time series',
- ylabel='Price ($)')
- df.log_rtn.plot(axax=ax[1])
- ax[1].set(ylabel='Log returns (%)')
- df.moving_std_252.plot(axax=ax[2], color='r',
- label='Moving Volatility 252d')
- df.moving_std_21.plot(axax=ax[2], color='g',
- label='Moving Volatility 21d')
- ax[2].set(ylabel='Moving Volatility',
- xlabel='Date')
- ax[2].legend()
我們現在可以通過將價格序列與(滾動)波動率指標進行可視化比較來研究杠桿效應:
這一事實表明,資產波動性的大多數衡量標準與其回報呈負相關,我們確實可以觀察到價格下跌時波動性增加而價格上漲時波動性減少的模式。