## 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 datetime import datetime
import matplotlib.pyplot as plt
%matplotlib inline

jpm = DataReader('JPM',  'yahoo', datetime(2006,1,1), datetime(2016,3,10))
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');


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');


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))


We can plot the fit with plot_fit:

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


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))