Solved – Rolling volatility estimation using GARCH family of models in python

archforecastinggarchpredictionpython

Problem: Correct usage of GARCH(1,1)

Aim of research: Forecasting volatility/variance.

Tools used: Python 3.3 with arch library

I am trying to obtain out-of-sample estimation of volatility using a fitted GARCH (or other model from the library), so I can compare it with other approaches – like recurrent neural networks.

However, I haven't found a way, how to use the fitted model in similar way to the R as mentioned here, where they fit the model and then obtain rolling forecast one period ahead.
I have looked through many examples and tutorial, but they always use in-sample estimates, when they already have the residuals as in example with in-sample estimation. I would like to "feed" the model historical data and obtain n periods ahead prediction (e.g. day ahead).

I believe the answer is very simple, however, I have not found it. Also, admittedly, I am quite new into using these types of models and python for statistical learning (I mostly used machine learning in the past).

Best Answer

Here is an example notebook:

# In[1]:

import pandas as pd
import numpy as np
import pandas_datareader as pdr
import datetime
import arch

# In[2]:

start = datetime.datetime(1995, 1, 1)
df = pdr.data.DataReader('SPY', 'yahoo', start=start)
del df['Open']
del df['High']
del df['Low']
del df['Adj Close']
del df['Volume']

# In[3]:

df['log_price'] = np.log(df['Close'])
df['pct_change'] = df['log_price'].diff()
df.head()

# In[4]:

df['stdev21'] = df['pct_change'].rolling(window=21, center=False).std()
df['hvol21'] = df['stdev21'] * (252**0.5) # Annualize.
#df['variance'] = df['hvol21']**2
df = df.dropna() # Remove rows with blank cells.

# In[5]:

df.head()

# In[6]:

returns = df['pct_change'] * 100
am = arch.arch_model(returns)

# In[7]:

res = am.fit(disp='off')
res.summary()

# In[8]:

df['forecast_vol'] = 0.1 * np.sqrt(res.params['omega'] + res.params['alpha[1]'] * res.resid**2 + res.conditional_volatility**2 * res.params['beta[1]'])

# In[9]:

df.tail()