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 = pd.read_csv('ret_full.csv', index_col=0) returns.index = pd.to_datetime(returns.index)
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
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
This is a results that I was expecting.
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
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
Why is this happening? Maybe because of the rescaling? Do I have to do another adjust before the forecast?