Skip to content
All library documents

Using GARCH(1,1) Forecasts of VIX Variance

Article Quant Q&A · Author: GusC

Summary

The document presents an attempt to forecast VIX using a constant-mean GARCH(1,1) model fitted to daily log changes in the VIX. It shows a historical sample, a training cutoff, a multi-step forecast, and forecasted conditional variances across dates and horizons. The author questions whether the displayed forecasts correspond to future dates and how variance forecasts could help predict S&P 500 adjusted closing prices through a separate regression.

The material is primarily a modeling question with code and output, not a demonstrated forecasting method. It supplies estimated model parameters and a forecast table, but no out-of-sample accuracy assessment or evidence that the proposed VIX-to-index regression is useful. The output concerns conditional variance of VIX log changes, not future VIX levels or S&P 500 prices directly, so interpreting it as a price forecast would require additional modeling choices and validation.

Key ideas

  • The example fits a constant-mean GARCH(1,1) model to daily VIX log changes.
  • The displayed multi-horizon forecasts are conditional variances, not forecasts of VIX levels.
  • The author is uncertain how forecast origins and future dates should be interpreted.
  • Using VIX forecasts to predict S&P 500 prices would require a separate model linking the variables.
  • The document provides no out-of-sample validation of either forecasting stage.

Tags

Full text
# Forecasting VIX with GARCH(1,1)


# 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.

Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.