0
$\begingroup$

I have a coded my own Garch class in order to implement the Heston-Nandi Garch model.

import numpy as np
import pandas as pd
import math
from scipy.optimize import *

Ticker=['^GSPC']
df=pd.DataFrame()
for i in Ticker:
      df[i]=wb.DataReader(i,'yahoo', start='01-09-2012',end = '01-09-2014')['Adj Close']

df2 = np.log(df/df.shift(1)).dropna() * 100

This code extracts the data and rescale them by multiplying the rate of returns by 100 for stability purpose(otherwise we end up with a messy log likelihood function to optimize).The following class compute our Garch.

class NGARCH :
    def __init__(self,df,r = 0):
        
        self.df = np.array(df)
        self.r = r
        self.NGarch_Log_Like()
        
    def NGarch(self,params):
        w,Beta,alpha,y,lambda_  = params
        h = np.zeros(len(self.df))
        e = np.zeros(len(self.df))
        for i in range(0,len(self.df)):
            if i == 0:
                h[0] = (w + alpha) / ( 1 - alpha * y**2 - Beta ) #Unconditional Variance 
                if h[0] < 0 or 1 - alpha * y**2 - Beta < 1e-3 :#or w > 1e-8 or alpha > 1e-05 or w < 0 or alpha < 0 or Beta > 0.90 :
                    return 1e50
            else :
                h[i] = w + Beta * h[i-1] + alpha * (e[i-1] - y * np.sqrt(h[i-1]))**2
                e[i] = (self.df[i] - self.r - lambda_ * h[i] + h[i] / 2)/np.sqrt(h[i])
        LogL = - .5 * np.sum(-np.log( 2 * np.pi) - np.log(h[:]) - (e[:])**2)
        return LogL
    
    def NGarch_Model(self):
        h = np.zeros(len(self.df))
        e = np.zeros(len(self.df))
        for i in range(0,len(self.df)):
            if i == 0:
                h[0] = (self.w + self.alpha) / (1 - self.alpha * self.y**2 - self.Beta)
            else :
                h[i] =  self.w + self.Beta * h[i-1] + self.alpha * (e[i-1]- self.y * np.sqrt(h[i-1]))**2
                e[i] = (self.df[i] - self.r - self.lambda_ * h[i] + h[i] / 2)/np.sqrt(h[i])
        return h,e
   
    def NGarch_Log_Like(self):
        #w,Beta,alpha,y,lambda_ = 9.765e-10, 0.90,2.194e-06,100.15,10
        #x0 = np.array([w,Beta,alpha,y,lambda_])
        #cons = ({'type': 'ineq', 'fun': lambda x: 1-x[1]-x[2]*(x[3]**2)})#{'type': 'ineq', 'fun': lambda x: np.array(x)})
        bounds = ((1e-8,1e-120),(1e-6,1),(1e-6,1e-12),(1e-10,1e3),(1e-10,100))
        #sol = minimize(self.NGarch,x0,bounds = bounds,constraints = cons,tol = 1e-9,method = 'Nelder-Mead')
        sol = differential_evolution(self.NGarch,bounds = bounds,tol = 1e-9,polish = False,workers = -1)
        self.w,self.Beta,self.alpha,self.y,self.lambda_ = sol.x
        print("Log Likelihood : {} ".format(-sol.fun))
        print(100 * "-")
        print("Stationarity Condition distance : ", 1-(self.Beta + self.alpha * self.y**2 ))
        print(100 * "-")
        print(" Parameters : ",sol.x)
        print(100 * "-")

However if you insert:

f = NGARCH(df2,0)

The result is such :

Log Likelihood : -9949.302700236756 
----------------------------------------------------------------------------------------------------
Stationarity Condition distance :  0.0010000008123174364
----------------------------------------------------------------------------------------------------
 Parameters :  [9.99632246e-09 9.17942150e-01 9.99999894e-07 2.84706616e+02
 1.13789977e+01]
----------------------------------------------------------------------------------------------------

The log likelihood is terrible for a dataframe with less than 700 data and it seems like the differential evolution algorithm is maximizing the stationary condition’s constraint and therefore our generated variance is always barely stationary.Better log likelihood appears if we are using the Local optimisor(Nelder-Mead).However the process stays barely stationary.

Could someone help because I was stuck with that during the whole day.

Thank you.

PS : The whole math behind that is available on the following link: Problem with the maximum likelihood for a GARCH-type of model

$\endgroup$
3
  • $\begingroup$ Hi there, did you remove the mean from your return data? Also, could it be that you have a sign error in your likelihood function? $\endgroup$ May 7, 2021 at 23:25
  • $\begingroup$ The log likelihood was expressed negatively in order to be maximized and the Heston & Nandi Garch doesn’t use a mean constant but rather the parameters showed on the link . $\endgroup$
    – lays
    May 7, 2021 at 23:41
  • $\begingroup$ I think I missed a bracket when parsing the code. $\endgroup$ May 8, 2021 at 4:14

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.