1.5 預測情形
1.5.1 波動率情形
客戶端自主隨機數生成器可以用於衝擊具有特定模式的情況。比如,假定你想知道5天大約平均值的衝擊會發生什麼。在大多數情況下,此類衝擊具有單位方差。但是,可以會產生4倍方差或兩倍標準差的情況。
另外一種情形可能是特定衝擊期間的樣本導致。當使用標準自舉方法(歷史模擬過濾)時,衝擊可以通過歷史數據的正態分佈刻畫出來。當該方法符合實際情況時,可能比較適合描繪特定期間的情形。這可以通過使用客戶自主隨機數生成器來實現。當統一從全部歷史數據中抽樣時,這種策略可以精確的從內部展示出歷史模擬過濾法是如何執行的。
首先配置一下前提條件:
import matplotlib
# %matplotlib inline
from arch.univariate import ConstantMean, GARCH, Normal
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn
import pandas_datareader as pdr
seaborn.set_style('darkgrid')
seaborn.mpl.rcParams['figure.figsize'] = (10.0, 6.0)
seaborn.mpl.rcParams['savefig.dpi'] = 90
seaborn.mpl.rcParams['font.family'] = 'serif'
seaborn.mpl.rcParams['font.size'] = 14
NASDAQCOM
DATE
2000-01-03 4131.15
2000-01-04 3901.69
2000-01-05 3877.54
2000-01-06 3727.13
2000-01-07 3882.62
該例使用了NASDAQ指數收益率。這種自舉情形使用2008年金融危機發生前至期間的數據。
下一步,計算收益率,並使用收益率數據來構建模型。該模型可用已有的程序模塊構建。這是一種標準化模型,相當於使用如下方法構建:
mod = arch_model(rets, mean='constant', p=1, o=1, q=1)
這種構建模型的優點之一,就是模型模擬所用的NumPy的 RandomState結果可以由外部決定。如果需要的話,這允許生成器種子很容易設定及重置狀態。
注意:估計ARCH模型時,通常使用百分數表示比較方便。這有助於優化器進行轉換,因爲波動率截距大小更接近於模型中其他參數。
rets = 100 * nasdaq.pct_change().dropna()
# Build components to set the state for the distribution
random_state = np.random.RandomState(1)
dist = Normal(random_state=random_state)
volatility = GARCH(1, 1, 1)
mod = ConstantMean(rets, volatility=volatility, distribution=dist)
res = mod.fit(disp='off')
res
擬合結果爲標準模型。
Constant Mean - GJR-GARCH Model Results
==============================================================================
Dep. Variable: NASDAQCOM R-squared: -0.000
Mean Model: Constant Mean Adj. R-squared: -0.000
Vol Model: GJR-GARCH Log-Likelihood: -7472.03
Distribution: Normal AIC: 14954.1
Method: Maximum Likelihood BIC: 14986.3
No. Observations: 4695
Date: Wed, Feb 13 2019 Df Residuals: 4690
Time: 10:01:54 Df Model: 5
Mean Model
============================================================================
coef std err t P>|t| 95.0% Conf. Int.
----------------------------------------------------------------------------
mu 0.0297 1.491e-02 1.992 4.643e-02 [4.704e-04,5.893e-02]
Volatility Model
=============================================================================
coef std err t P>|t| 95.0% Conf. Int.
-----------------------------------------------------------------------------
omega 0.0169 4.601e-03 3.670 2.424e-04 [7.868e-03,2.590e-02]
alpha[1] 7.0146e-16 7.140e-03 9.825e-14 1.000 [-1.399e-02,1.399e-02]
gamma[1] 0.1265 1.744e-02 7.251 4.137e-13 [9.228e-02, 0.161]
beta[1] 0.9256 1.244e-02 74.415 0.000 [ 0.901, 0.950]
=============================================================================
Covariance estimator: robust
ARCHModelResult, id: 0xefc5ac8
GJR-GARCH模型默認支持解析預測,使用估計所得到的參數,預測2017年全部數據。
h.01 h.02 h.03 ... h.08 h.09 h.10
DATE ...
2017-01-02 0.580045 0.590476 0.600792 ... 0.650674 0.660320 0.669858
2017-01-03 0.553798 0.564522 0.575126 ... 0.626404 0.636320 0.646126
2017-01-04 0.529503 0.540497 0.551369 ... 0.603940 0.614105 0.624158
2017-01-05 0.507015 0.518259 0.529378 ... 0.583145 0.593543 0.603824
2017-01-06 0.486199 0.497675 0.509023 ... 0.563897 0.574509 0.585002
所有的GARCH 設定都是一致的,也就是說它們都表明了一種分佈。這可以通過模型假定來模擬。forecast函數可以用來使用假定分佈來產生模擬數據,具體方法爲:
method='simulation'
.
這些預測與上述解析預測類似。隨着模擬數值趨向無窮大,基於模擬的預測將會收斂於解析值。
h.01 h.02 h.03 ... h.08 h.09 h.10
DATE ...
2017-01-02 0.580045 0.590403 0.598096 ... 0.640617 0.647898 0.656073
2017-01-03 0.553798 0.567418 0.581017 ... 0.627658 0.633192 0.641493
2017-01-04 0.529503 0.541442 0.552064 ... 0.600379 0.612958 0.622361
2017-01-05 0.507015 0.516400 0.526907 ... 0.576138 0.587728 0.593812
2017-01-06 0.486199 0.495461 0.505577 ... 0.565625 0.574218 0.588634
1.5.2 自主隨機數生成器
forecast
方法可以將模型的殘差分佈修改爲任何一種生成器。一種衝擊生成器通常應該產生單一的方差。然而,在這個案例中,前五個衝擊產生了2倍方差,然而其餘的爲標準方差。這種情形包含了一種持續變化的波動率,且因某種原因而發生了改變。
預測方差比前面提到的任何一種方差都要大,並且變化更快。這反映了在最初5天裏波動率的增長。
i
import numpy as np
random_state = np.random.RandomState(1)
def scenario_rng(size):
shocks = random_state.standard_normal(size)
shocks[:, :5] *= np.sqrt(2)
return shocks
scenario_forecasts = res.forecast(start='1-1-2017', method='simulation', horizon=10, rng=scenario_rng)
print(scenario_forecasts.residual_variance.dropna().head())
h.01 h.02 h.03 ... h.08 h.09 h.10
DATE ...
2017-01-02 0.580045 0.627008 0.670593 ... 0.835040 0.839207 0.846161
2017-01-03 0.553798 0.605332 0.660221 ... 0.816872 0.818132 0.823917
1.5.3 自舉情形
forecast方法支持歷史模擬過濾法
(FHS) ,使用參數: method='bootstrap'
. 這是一種有效的模擬方法,其產生的模擬衝擊是採用正態分佈方法,從歷史去中心化和標準化的收益率數據中隨機抽取。 自主自舉法是rng方法的另一種應用。這裏使用一種對象來表示衝擊,該對象通過rng方法,類似於隨機數生成器,不同的是它僅僅返回使用衝擊參數產生的值。
FHS的內部運行採用的shocks包含全部歷史數據,這與實際情況一致。
h.01 h.02 h.03 ... h.08 h.09 h.10
DATE ...
2017-01-02 0.580045 0.627731 0.671806 ... 0.916472 0.973876 1.038470
2017-01-03 0.553798 0.601034 0.643942 ... 0.876280 0.930863 0.984509
2017-01-04 0.529503 0.573559 0.615961 ... 0.870309 0.931131 0.988081
2017-01-05 0.507015 0.551867 0.598752 ... 0.833911 0.883571 0.947948
2017-01-06 0.486199 0.520973 0.557449 ... 0.814151 0.863551 0.909780
[5 rows x 10 columns]
1.5.4 差異圖形化
最終預測值可用來說明差別程度。解析法和標準模擬法本質上是 一致的。模擬情形中,差異在最初5個時期內快速增加,然後減慢。 自舉情形下,差異快速上升,且與金融危機發生衝擊的程度一致。
import pandas as pd
df = pd.concat([forecasts.residual_variance.iloc[-1],
sim_forecasts.residual_variance.iloc[-1],
scenario_forecasts.residual_variance.iloc[-1],
bs_forecasts.residual_variance.iloc[-1]], 1)
df.columns = ['Analytic','Simulation','Scenario Sim','Bootstrp Scenario']
# Plot annualized vol
subplot = np.sqrt(252 * df).plot(legend=False)
legend = subplot.legend(frameon=False)
1.5.5 路徑比較
不同的路徑可以通過 simulations屬性來實現
. 繪製路徑可以將上圖所示的兩者之間超越平均差別的顯著性變化表示出來。兩者始於同一點:
fig, axes = plt.subplots(1, 2)
colors = seaborn.color_palette('dark')
# The paths for the final observation
sim_paths = sim_forecasts.simulations.residual_variances[-1].T
bs_paths = bs_forecasts.simulations.residual_variances[-1].T
# Plot the paths and the mean, set the axis to have the same limit
axes[0].plot(np.sqrt(252 * sim_paths), color=colors[0], alpha=0.1)
axes[0].plot(np.sqrt(252 * sim_forecasts.residual_variance.iloc[-1]),
color='k', alpha=1)
axes[0].set_title('Model-based Simulation')
axes[0].set_xticklabels(np.arange(1, 11))
axes[0].set_ylim(5, 40)
axes[1].plot(np.sqrt(252 * bs_paths), color=colors[1], alpha=0.1)
axes[1].plot(np.sqrt(252 * bs_forecasts.residual_variance.iloc[-1]),
color='k', alpha=1)
axes[1].set_xticklabels(np.arange(1, 11))
axes[1].set_ylim(5, 40)
title = axes[1].set_title('Bootstrap Scenario')
1.5.6 跨年比較
一種 hedgehog繪圖方法在描繪這兩種預測方法的跨年而非跨日差別時比較有用。
analytic = forecasts.residual_variance.dropna()
bs = bs_forecasts.residual_variance.dropna()
fig, ax = plt.subplots(1, 1)
vol = res.conditional_volatility['2017-1-1':'2018-1-1']
idx = vol.index
ax.plot(np.sqrt(252) * vol)
for i in range(0, len(vol), 22):
a = analytic.iloc[i]
b = bs.iloc[i]
loc = idx.get_loc(a.name)
new_idx = idx[loc + 1:loc + 11]
a.index = new_idx
b.index = new_idx
ax.plot(np.sqrt(252 * a), color=colors[1])
ax.plot(np.sqrt(252 * b), color=colors[2])
labels = ['Annualized Vol.', 'Analytic Forecast',
'Bootstrap Scenario Forecast']
legend = ax.legend(labels, frameon=False)