# Forecasting Volatility using GARCH in Python - Arch Package

Disclaimer: Posted this on stackoverflow, but maybe here should be the right place to ask something about GARCH

I'm testing ARCH package to forecast the Variance (Standard Deviation) of two series using GARCH(1,1).

This is the first part of my code

import pandas as pd
import numpy as np
from arch import arch_model

returns.index = pd.to_datetime(returns.index)


# Ibovespa Returns

The first series is the 1st Future Contract of Ibovespa Index, has an observed annualized volatility really close to the Garch Forecast.

The first problem that I've found is that you need to rescale your sample by 100. To do this, you can multiply your return series by 100 or setting the parameter rescale=True in the arch_model function.

Why is necessary to do this?

# Ibov
ret_ibov = returns['IBOV_1st']
model_ibov = arch_model(ret_ibov, vol='Garch', p=1, o=0, q=1, dist='Normal', rescale=True)
res_ibov = model_ibov.fit()


After fitting the model I forecast the Variance (just 5 steps to illustrate the problem), get the Standard Deviation and annualize it. Obs: Since I had to rescale my return series, I divide my forecast by 10000 (100**2, because of rescale)

# Forecast
forecast_ibov = res_ibov.forecast(horizon=5)

# Getting Annualized Standard Deviation
# Garch Vol
vol_ibov_for = (forecast_ibov.variance.iloc[-1]/10000)**0.5 * np.sqrt(252) * 100
# Observed Vol
vol_ibov = ret_ibov.std() * np.sqrt(252) * 100


And that's the forecast output

vol_ibov_for
h.1    24.563208
h.2    24.543245
h.3    24.523969
h.4    24.505357
h.5    24.487385


Which is really close to Observed Vol 23.76

This is a results that I was expecting.

# IRFM Returns

When I do exactly the same process a less volatile series, I got a really weird result.

# IRFM
ret_irfm = returns['IRFM1M']
model_irfm = arch_model(ret_irfm, vol='Garch', p=1, o=0, q=1, dist='Normal', rescale=True)
res_irfm = model_irfm.fit()

# Forecast
forecasts_irfm = res_irfm.forecast(horizon=5)

# Getting Annualized Standard Deviation
# Garch Vol
vol_irfm_for = (forecasts_irfm.variance.iloc[-1]/10000)**0.5 * np.sqrt(252) * 100
# Observed Vol
vol_irfm = ret_irfm.std() * np.sqrt(252) * 100


Forecast output:

vol_irfm_for
h.1    47.879679
h.2    49.322351
h.3    50.519282
h.4    51.517356
h.5    52.352894


And this is significantly different from the Observed Volatility 5.39

Why is this happening? Maybe because of the rescaling? Do I have to do another adjust before the forecast?

Thanks

The rescale=True is used when the model fails to converge to a result. So rescale could be a solution for the problem. If the model doesn't need rescale, even if the parameter is True, it will not do anything.

Point of Attempion: If the rescale=True and, in fact, rescaled the series. It's necessary to adjust the outputs. In my question I was confused about how high my volatility was. That's because I was assuming that my rescale values was 100, which not necessarily is true.

The correct thing to do is to set the parameter as True and get the rescale value after that.

To do this, just need to insert the following code:

# IRFM
ret_irfm = returns['IRFM1M']
model_irfm = arch_model(ret_irfm, vol='Garch', p=1, o=0, q=1, dist='Normal', rescale=True, mean='Zero')
res_irfm = model_irfm.fit()
scale = res_irfm.scale  # New part of the code

# Forecast
forecasts_irfm = res_irfm.forecast(horizon=5)

# Getting Annualized Standard Deviation
# Garch Vol
# New part of the code: Divide variance by scale^2
vol_irfm_for = (forecasts_irfm.variance.iloc[-1] / np.power(scale, 2))**0.5 * np.sqrt(252) * 100
# Observed Vol
vol_irfm = ret_irfm.std() * np.sqrt(252) * 100


Hope this help another users with the same problem. It's a really simple thing.

Thanks.