Forecasting VIX with GARCH(1,1)

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()


The end result is this plot:

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.

• With regards to the code, setting the horizon $h$ to 30 in the arch package computes multistep recursive forecasts of the GARCH model (see here p. 449) for each day. This is why you get a $Date \times 30$ forecast matrix. Also when $h \rightarrow \infty$ the conditional forecast converges towards the unconditional variance of the GARCH process ($\frac{\omega}{1- \alpha - \beta}=0.463$ in your case). This is likely the reason why the forecast-values for $h=30$ are close to 0.46.
– Pleb
Commented Jun 17, 2022 at 8:44
• Thank you @Pleb! I was wondering why variance seemed to converge at around 0.46X. That being said, I don't think my h is that large. Is there a way to fix it?
– GusC
Commented Jun 18, 2022 at 11:39
• In my opinion your $h$ is quite large. Another way to forecast 30 days (1 month) ahead is simply to sparse sample your data to monthly data. Then $h=1$ will be the next monthly estimate. This, of course, has the downside of not using all available data.
– Pleb
Commented Jun 18, 2022 at 12:03
• I see, what do you think would be a reasonable h? As for the forecast, I sadly need to work with daily data, particularly because the idea is to use the results from this model to be able to predict the SP500, which also has daily data.
– GusC
Commented Jun 18, 2022 at 15:11
• If you don't need monthly forecasts, then set $h=1$ and work with 1-step ahead forecasts. This will also be more straightforward as the 1-step ahead forecast is "embedded" into the GARCH equation. While I don't have much expertise in forecasting the VIX index, I found two papers (one focuses on GARCH and another on the HAR model) that tries to forecast the VIX index. They are provided here and here and might give you some inspiration. In the GARCH paper, they compare their findings to the HAR model of the latter paper.
– Pleb
Commented Jun 18, 2022 at 17:26