Aim: Forecast VIX using GARCH(1,1)
Reason: I want to be able to forecast VIX on several horizons, in order to be able to forecast the SP500 index through linear regression.
Tools used: Python, arch_model from the arch library, YahooFinancials
I am building a model to be able to forecast future values for the SP500's Adjusted Closing Prices using VIX as the independent variable, as it has a (negative) correlation with the SP500. In order to do that, I need to first forecast VIX future values, and I've been thinking about using GARCH(1,1) to achieve that. However, I'm not quite sure if what I'm doing is correct. I would highly appreciate any input.
The following code is only for the GARCH(1,1) to forecast VIX. The linear regression to forecast the SP500's Adjusted Closing Prices isn't included here, as I'm still trying to figure out how to add the forecasted VIX to that model.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from rpy2.robjects.packages import importr
import rpy2.robjects as robjects
from rpy2.robjects import numpy2ri
pd.options.mode.chained_assignment = None
import yfinance as yf
from yahoofinancials import YahooFinancials
import pandas_datareader.data as wb
import datetime
import datetime as dt
from datetime import date
from datetime import timedelta
from arch import arch_model
#First we define the start and end dates
start_date = date(1990, 1, 1)
end_date = date.today() - datetime.timedelta(days=1)
#We then import the data from YahooFinance's API
In [3]: VIX_df = yf.download('^VIX', start = start_date, end = end_date, interval = '1d')
Out[3]: [*********************100%***********************] 1 of 1 completed
#Then we get the log returns
In [4]: VIX_df['log_returns'] = np.log(VIX_df['Adj Close']) - np.log(VIX_df['Adj Close'].shift(1))
...: returns = VIX_df['log_returns'].dropna()
...: returns
Out[4]: Date
...: 1990-01-03 0.053640
...: 1990-01-04 0.055079
...: 1990-01-05 0.045266
...: 1990-01-08 0.007431
...: 1990-01-09 0.091444
...: ...
...: 2022-06-09 0.085166
...: 2022-06-10 0.061684
...: 2022-06-13 0.203713
...: 2022-06-14 -0.039879
...: 2022-06-15 -0.098619
...: Name: log_returns, Length: 8177, dtype: float64
#The horizon is defined and the model is created
n_test = 30
model = arch_model(returns, mean='constant', vol='GARCH', p=1, q=1, dist='Normal', rescale=True)
#The model is fit
In [6]: split_date = dt.datetime(2021,12,31)
...: res = model.fit(update_freq=5, last_obs=split_date)
...: scale = res.scale
...: print(model_fit.summary())
Out[6]: Iteration: 5, Func. Count: 41, Neg. LLF: 7764.529955193779
Optimization terminated successfully. (Exit mode 0)
Current function value: 7764.463716026663
Iterations: 9
Function evaluations: 68
Gradient evaluations: 9
Constant Mean - GARCH Model Results
==============================================================================
Dep. Variable: log_returns R-squared: 0.000
Mean Model: Constant Mean Adj. R-squared: 0.000
Vol Model: GARCH Log-Likelihood: -7909.06
Distribution: Normal AIC: 15826.1
Method: Maximum Likelihood BIC: 15854.2
No. Observations: 8177
Date: Fri, Jun 17 2022 Df Residuals: 8176
Time: 00:26:36 Df Model: 1
Mean Model
==============================================================================
coef std err t P>|t| 95.0% Conf. Int.
------------------------------------------------------------------------------
mu -8.0763e-04 6.478e-03 -0.125 0.901 [-1.350e-02,1.189e-02]
Volatility Model
============================================================================
coef std err t P>|t| 95.0% Conf. Int.
----------------------------------------------------------------------------
omega 0.0507 1.303e-02 3.891 9.980e-05 [2.517e-02,7.627e-02]
alpha[1] 0.1322 2.438e-02 5.423 5.876e-08 [8.442e-02, 0.180]
beta[1] 0.7583 4.677e-02 16.213 4.098e-59 [ 0.667, 0.850]
============================================================================
Covariance estimator: robust
#Then we produce the forcast
In [7]: forecasts = res.forecast(horizon=n_test, start=split_date, reindex=False)
...: print(forecasts.variance.iloc[-n_test:])
Out[7]: h.01 h.02 h.03 h.04 h.05 h.06 \
Date
2022-05-04 0.878434 0.831696 0.790164 0.753259 0.720464 0.691323
2022-05-05 1.272253 1.181647 1.101133 1.029588 0.966013 0.909519
2022-05-06 1.027305 0.963984 0.907716 0.857716 0.813286 0.773805
2022-05-09 1.090585 1.020215 0.957684 0.902118 0.852742 0.808866
2022-05-10 0.911314 0.860913 0.816127 0.776329 0.740965 0.709540
2022-05-11 0.742402 0.710817 0.682750 0.657809 0.635647 0.615954
2022-05-12 0.620353 0.602363 0.586378 0.572172 0.559549 0.548333
2022-05-13 0.641197 0.620885 0.602836 0.586797 0.572545 0.559881
2022-05-16 0.568479 0.556268 0.545417 0.535774 0.527206 0.519592
2022-05-17 0.515429 0.509127 0.503527 0.498551 0.494129 0.490199
2022-05-18 0.827829 0.786728 0.750205 0.717751 0.688912 0.663285
2022-05-19 0.714628 0.686137 0.660819 0.638322 0.618330 0.600566
2022-05-20 0.591563 0.576780 0.563644 0.551971 0.541599 0.532381
2022-05-23 0.512542 0.506562 0.501247 0.496525 0.492329 0.488600
2022-05-24 0.453644 0.454224 0.454740 0.455198 0.455605 0.455967
2022-05-25 0.412472 0.417638 0.422229 0.426309 0.429934 0.433156
2022-05-26 0.375723 0.384983 0.393211 0.400523 0.407021 0.412795
2022-05-27 0.394275 0.401468 0.407861 0.413541 0.418588 0.423074
2022-05-31 0.353645 0.365364 0.375778 0.385032 0.393255 0.400562
2022-06-01 0.323358 0.338451 0.351863 0.363781 0.374371 0.383782
2022-06-02 0.315089 0.331103 0.345334 0.357979 0.369216 0.379201
2022-06-03 0.289474 0.308341 0.325107 0.340005 0.353244 0.365008
2022-06-06 0.271703 0.292550 0.311075 0.327536 0.342164 0.355162
2022-06-07 0.280641 0.300493 0.318133 0.333808 0.347737 0.360115
2022-06-08 0.263383 0.285157 0.304506 0.321699 0.336977 0.350553
2022-06-09 0.346689 0.359183 0.370286 0.380151 0.388918 0.396708
2022-06-10 0.363898 0.374475 0.383874 0.392227 0.399648 0.406243
2022-06-13 0.876871 0.830307 0.788930 0.752162 0.719490 0.690457
2022-06-14 0.735047 0.704281 0.676943 0.652649 0.631062 0.611879
2022-06-15 0.735374 0.704572 0.677201 0.652879 0.631266 0.612060
h.07 h.08 h.09 h.10 ... h.21 h.22 \
Date ...
2022-05-04 0.665427 0.642417 0.621969 0.603799 ... 0.498392 0.493987
2022-05-05 0.859318 0.814710 0.775070 0.739846 ... 0.535502 0.526964
2022-05-06 0.738722 0.707546 0.679844 0.655227 ... 0.512420 0.506453
2022-05-09 0.769877 0.735231 0.704445 0.677088 ... 0.518383 0.511752
2022-05-10 0.681615 0.656801 0.634751 0.615158 ... 0.501490 0.496741
2022-05-11 0.598454 0.582904 0.569085 0.556806 ... 0.485573 0.482597
2022-05-12 0.538365 0.529508 0.521638 0.514644 ... 0.474072 0.472377
2022-05-13 0.548627 0.538627 0.529741 0.521845 ... 0.476036 0.474122
2022-05-16 0.512826 0.506814 0.501471 0.496724 ... 0.469184 0.468033
2022-05-17 0.486708 0.483605 0.480848 0.478398 ... 0.464185 0.463591
2022-05-18 0.640513 0.620277 0.602296 0.586318 ... 0.493623 0.489750
2022-05-19 0.584780 0.570753 0.558288 0.547212 ... 0.482956 0.480271
2022-05-20 0.524191 0.516913 0.510446 0.504699 ... 0.471359 0.469966
2022-05-23 0.485286 0.482342 0.479725 0.477400 ... 0.463913 0.463349
2022-05-24 0.456289 0.456574 0.456828 0.457054 ... 0.458363 0.458417
2022-05-25 0.436018 0.438562 0.440822 0.442831 ... 0.454483 0.454970
2022-05-26 0.417925 0.422484 0.426536 0.430136 ... 0.451020 0.451892
2022-05-27 0.427059 0.430601 0.433748 0.436544 ... 0.452768 0.453446
2022-05-31 0.407055 0.412825 0.417953 0.422509 ... 0.448939 0.450044
2022-06-01 0.392144 0.399575 0.406178 0.412046 ... 0.446085 0.447508
2022-06-02 0.388073 0.395958 0.402964 0.409189 ... 0.445306 0.446815
2022-06-03 0.375462 0.384751 0.393006 0.400340 ... 0.442892 0.444670
2022-06-06 0.366713 0.376977 0.386097 0.394202 ... 0.441218 0.443182
2022-06-07 0.371113 0.380887 0.389572 0.397289 ... 0.442060 0.443931
2022-06-08 0.362617 0.373337 0.382863 0.391328 ... 0.440434 0.442486
2022-06-09 0.403631 0.409782 0.415248 0.420106 ... 0.448284 0.449461
2022-06-10 0.412104 0.417311 0.421939 0.426051 ... 0.449906 0.450902
2022-06-13 0.664658 0.641733 0.621362 0.603259 ... 0.498244 0.493856
2022-06-14 0.594833 0.579686 0.566226 0.554266 ... 0.484880 0.481981
2022-06-15 0.594994 0.579829 0.566353 0.554379 ... 0.484911 0.482008
h.23 h.24 h.25 h.26 h.27 h.28 \
Date
2022-05-04 0.490074 0.486596 0.483506 0.480760 0.478319 0.476151
2022-05-05 0.519377 0.512635 0.506644 0.501321 0.496590 0.492387
2022-05-06 0.501151 0.496439 0.492252 0.488532 0.485226 0.482288
2022-05-09 0.505859 0.500623 0.495971 0.491836 0.488162 0.484897
2022-05-10 0.492520 0.488770 0.485438 0.482476 0.479845 0.477507
2022-05-11 0.479952 0.477602 0.475513 0.473657 0.472008 0.470543
2022-05-12 0.470870 0.469532 0.468342 0.467285 0.466346 0.465511
2022-05-13 0.472421 0.470910 0.469567 0.468374 0.467313 0.466371
2022-05-16 0.467010 0.466102 0.465294 0.464577 0.463939 0.463373
2022-05-17 0.463063 0.462594 0.462178 0.461807 0.461478 0.461186
2022-05-18 0.486308 0.483250 0.480532 0.478118 0.475972 0.474065
2022-05-19 0.477885 0.475765 0.473881 0.472207 0.470720 0.469398
2022-05-20 0.468728 0.467628 0.466651 0.465782 0.465010 0.464325
2022-05-23 0.462848 0.462403 0.462008 0.461657 0.461344 0.461067
2022-05-24 0.458466 0.458509 0.458547 0.458581 0.458612 0.458639
2022-05-25 0.455402 0.455787 0.456128 0.456432 0.456702 0.456941
2022-05-26 0.452668 0.453357 0.453969 0.454513 0.454997 0.455426
2022-05-27 0.454048 0.454584 0.455059 0.455482 0.455857 0.456191
2022-05-31 0.451025 0.451897 0.452672 0.453361 0.453972 0.454516
2022-06-01 0.448771 0.449895 0.450892 0.451779 0.452567 0.453268
2022-06-02 0.448156 0.449348 0.450407 0.451348 0.452184 0.452927
2022-06-03 0.446250 0.447654 0.448902 0.450010 0.450995 0.451871
2022-06-06 0.444928 0.446479 0.447858 0.449082 0.450171 0.451138
2022-06-07 0.445593 0.447070 0.448383 0.449549 0.450585 0.451506
2022-06-08 0.444309 0.445929 0.447369 0.448648 0.449785 0.450795
2022-06-09 0.450507 0.451437 0.452263 0.452997 0.453650 0.454229
2022-06-10 0.451788 0.452575 0.453274 0.453896 0.454448 0.454939
2022-06-13 0.489957 0.486493 0.483414 0.480678 0.478247 0.476087
2022-06-14 0.479405 0.477115 0.475081 0.473273 0.471667 0.470240
2022-06-15 0.479429 0.477137 0.475100 0.473291 0.471682 0.470253
h.29 h.30
Date
2022-05-04 0.474224 0.472512
2022-05-05 0.488651 0.485332
2022-05-06 0.479678 0.477358
2022-05-09 0.481996 0.479418
2022-05-10 0.475429 0.473582
2022-05-11 0.469241 0.468084
2022-05-12 0.464770 0.464111
2022-05-13 0.465533 0.464789
2022-05-16 0.462869 0.462422
2022-05-17 0.460926 0.460695
2022-05-18 0.472370 0.470865
2022-05-19 0.468223 0.467180
2022-05-20 0.463715 0.463174
2022-05-23 0.460820 0.460601
2022-05-24 0.458663 0.458684
2022-05-25 0.457154 0.457344
2022-05-26 0.455808 0.456147
2022-05-27 0.456488 0.456751
2022-05-31 0.454999 0.455429
2022-06-01 0.453890 0.454443
2022-06-02 0.453587 0.454173
2022-06-03 0.452648 0.453340
2022-06-06 0.451997 0.452761
2022-06-07 0.452325 0.453052
2022-06-08 0.451693 0.452490
2022-06-09 0.454744 0.455202
2022-06-10 0.455375 0.455762
2022-06-13 0.474167 0.472461
2022-06-14 0.468971 0.467844
2022-06-15 0.468983 0.467855
[30 rows x 30 columns]
#Finally, we plot the forecast
In [8]: plt.rcParams["figure.figsize"] = 18, 5
...: plt.plot(forecasts.variance[-5:])
...: plt.show()
Which makes me wonder if I'm forecasting anything at all, because every so-called step-ahead is stacked on top of each date, rather than being forecasted as new data on new dates starting from the last date available. I know my code is quite faulty, and I feel like a headless chicken, because I have no idea what to fix. Furthermore, as I said before, I'm still trying to figure out how to use the output of this GARCH to forecast the Adjusted Closing Prices of the SP500, considering the output from GARCH is variance.
Any help is highly appreciated. Thanks in advance.