Theory


BetatEGARCH models introduced by Harvey and Chakravarty (2008) address some of the problems with GARCH models by using an EGARCH formulation to constrain volatility as positive without ad hoc parameter restrictions, and using the score of a t-distribution to drive parameter updates rather than squared residuals, leading to greater robustness to outliers:


y_{t} =  \mu + \exp\left(\lambda_{t\mid{t-1}}/2\right)\epsilon_{t}

\lambda_{t\mid{t-1}} = \alpha_{0} + \sum^{p}_{i=1}\alpha_{i}\lambda_{t-i} + \sum^{q}_{j=1}\beta_{j}\left(\frac{\left(\nu+1\right)y_{t-j}^{2}} {\nu\exp\left(\lambda_{t-j\mid{t-j-1}}\right) + y_{t-j}^{2}}-1\right)

\epsilon_{t} \sim t_{\nu}

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

Let’s fit an EGARCH(1,1) model using a point mass estimate z^{MLE}:

model = pf.EGARCH(returns,p=1,q=1)
x = model.fit()
x.summary()
EGARCH(1,1)                                                                                               
======================================================= =================================================
Dependent Variable: JPM Returns                         Method: MLE                                       
Start Date: 2006-01-05 00:00:00                         Log Likelihood: 6663.2492                         
End Date: 2016-03-10 00:00:00                           AIC: -13316.4985                                  
Number of observations: 2562                            BIC: -13287.2557                                  
=========================================================================================================
Latent Variable                          Estimate   Std Error  z        P>|z|    95% C.I.                 
======================================== ========== ========== ======== ======== ========================
Vol Constant                             -0.0575    0.0166     -3.4695  0.0005   (-0.0899 | -0.025)       
p(1)                                     0.9933                                                           
q(1)                                     0.103                                                            
v                                        6.0794                                                           
Returns Constant                         0.0007     0.0247     0.0292   0.9767   (-0.0477 | 0.0492)       
=========================================================================================================

By default, the EGARCH latent variables are constrained in the range \left(0,1\right), so standard errors are not shown above. If you wish to obtain standard errors, then you can remove the constraints and initialize as you see fit. 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.016908
2016-03-10 0.016882
2016-03-11 0.016855
2016-03-12 0.016829
2016-03-13 0.016803
2016-03-14 0.016778
2016-03-17 0.016752
2016-03-18 0.016727
2016-03-19 0.016702
2016-03-20 0.016677

model.plot_predict(h=10,figsize=(15,5))
png

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

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



Leverage Extension

Past evidence suggests a leverage effect in stock returns, see Black (1976), that observes that volatility increases more after bad news than good news. Following Harvey and Succarrat (2014), we can incorporate a leverage effect in the Beta-t-EGARCH model as follows:


\lambda_{t\mid{t-1}} = \alpha_{0} + \sum^{p}_{i=1}\alpha_{i}\lambda_{t-i} + \sum^{q}_{j=1}\beta_{j}u_{t-j} + \kappa\left(\text{sgn}\left(-\epsilon_{t-1}\right)(u_{t-1}+1)\right)


Where \kappa is the leverage coefficient. It is easy to amend our model to include a leverage effect:

model.add_leverage()
x = model.fit()
x.summary()
EGARCH(1,1)                                                                                               
======================================================= =================================================
Dependent Variable: JPM Returns                         Method: MLE                                       
Start Date: 2006-01-05 00:00:00                         Log Likelihood: 6688.2732                         
End Date: 2016-03-10 00:00:00                           AIC: -13364.5465                                  
Number of observations: 2562                            BIC: -13329.4552                                  
=========================================================================================================
Latent Variable                          Estimate   Std Error  z        P>|z|    95% C.I.                 
======================================== ========== ========== ======== ======== ========================
Vol Constant                             -0.0586    0.0219     -2.6753  0.0075   (-0.1015 | -0.0157)      
p(1)                                     0.9934                                                           
q(1)                                     0.0781                                                           
Leverage Term                            0.0578     0.0012     49.8546  0.0      (0.0555 | 0.0601)        
v                                        6.3724                                                           
Returns Constant                         0.0005     0.0        160.6585 0.0      (0.0005 | 0.0005)        
=========================================================================================================
We have a small leverage effect for this time series:

model.plot_z([0,3],figsize=(15,5))
png We can plot the fit again with plot_fit:

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

And plot predictions with plot_predict:

model.plot_predict(h=30,figsize=(15,5))
png