Theory


A GARCH model is a simple observation-driven model that captures dynamic conditional volatility. The form of a standard GARCH(p,q) model is as follows:


y_{t} = \mu + \sigma_{t}\epsilon_{t}

\sigma_{t}^{2} = \alpha_{0} + \sum^{p}_{i=1}\alpha_{i}\sigma_{t-i}^{2} + \sum^{q}_{j=1}\beta_{j}\epsilon_{t-j}^{2}

\epsilon_{t} \sim N\left(0,1\right)


The model is observation-driven as it used the squared residuals to inform the parameter update for the volatility term. A GARCH(1,1) has been shown to be effective for most financial time series. There are some problems, however: including the fact that most asset returns display heavy tails, and even with an assumption of t-distributed errors, the ARCH terms will likely overreact to tail events. Another problem is the fact that the volatility process is not explicitly constrained to be >0, which can lead to some difficulties with optimization. See EGARCH models for an alternative that helps address these concerns.

PyFlux


First let us load some financial time series data from Yahoo Finance:

import numpy as np
import pyflux as pf
import pandas as pd
from pandas.io.data import DataReader
from datetime import datetime
import matplotlib.pyplot as plt
%matplotlib inline 

jpm = DataReader('JPM',  'yahoo', datetime(2006,1,1), datetime(2016,3,10))
returns = pd.DataFrame(np.diff(np.log(jpm['Adj Close'].values)))
returns.index = jpm.index.values[1:jpm.index.values.shape[0]]
returns.columns = ['JPM Returns']

plt.figure(figsize=(15,5));
plt.plot(returns.index,returns);
plt.ylabel('Returns');
plt.title('JPM Returns');
png

One way to visualize the underlying volatility of the series is to plot the absolute returns \mid{y}\mid:

plt.figure(figsize=(15,5))
plt.plot(returns.index, np.abs(returns))
plt.ylabel('Absolute Returns')
plt.title('JP Morgan Absolute Returns');
png

There appears to be some evidence of volatility clustering over this period. Let’s fit a GARCH(1,1) model using a point mass estimate z^{MLE}:

model = pf.GARCH(returns,p=1,q=1)
x = model.fit()
x.summary()
GARCH(1,1)                                                                                                
======================================================= =================================================
Dependent Variable: JPM Returns                         Method: MLE                                       
Start Date: 2006-01-05 00:00:00                         Log Likelihood: 6594.7911                         
End Date: 2016-03-10 00:00:00                           AIC: -13181.5822                                  
Number of observations: 2562                            BIC: -13158.188                                   
=========================================================================================================
Latent Variable                          Estimate   Std Error  z        P>|z|    95% C.I.                 
======================================== ========== ========== ======== ======== ========================
Vol Constant                             0.0                                                              
q(1)                                     0.0933                                                           
p(1)                                     0.9013                                                           
Returns Constant                         0.0009     0.0065     0.1359   0.8919   (-0.0119 | 0.0137)       
=========================================================================================================

We can plot the GARCH parameters with plot_z:

model.plot_z([1,2],figsize=(15,5))
png

We can plot the fit with plot_fit:

model.plot_fit(figsize=(15,5))
png

And obtain predictions of future conditional volatility with predict:

model.predict(h=10)
JPM Returns
2016-03-07 0.000451
2016-03-10 0.000411
2016-03-11 0.000374
2016-03-12 0.000341
2016-03-13 0.000312
2016-03-14 0.000285
2016-03-17 0.000261
2016-03-18 0.000239
2016-03-19 0.000220
2016-03-20 0.000202

And view how well we predicted using dynamic in-sample rolling prediction with plot_predict_is:

model.plot_predict_is(h=50,figsize=(15,5))
png