Module quantfin.volatility.garch_sym
Symmetric GARCH
Fits the symmetric GARCH(1,1) model to returns data.
Usage
import quantfin as qf
params = qf.volatility.garch_sym.fit_model(R)
volatilities = qf.volatilty.garch_sym.sigma(R, params)
Source code
"""
# Symmetric GARCH
Fits the symmetric GARCH(1,1) model to returns data.
## Usage
```python
import quantfin as qf
params = qf.volatility.garch_sym.fit_model(R)
volatilities = qf.volatilty.garch_sym.sigma(R, params)
```
"""
import warnings
import numpy as np
from scipy.optimize import minimize
def sigma(R, params):
"""Calculates volatility using the symmetric GARCH(1,1) model
The symmetric GARCH(1,1) model is defined by the recursion relation:
sigma^{2}_{n+1} = omega + alpha * R^{2}_{n} + beta * sigma^{2}_{n}
where `sigma_n` is the volatilty at time-step `n`, and `R_n` are the returns
of the asset at time-step `n`. We assume that `sigma_0 = omega`.
Args:
R (numpy.array): Financial returns data from which to calculate
volatility.
params (numpy.array): The parameters of the GARCH model to use. Should
be in the form `[alpha, beta, omega]`.
Returns:
A numpy array of volatilties.
"""
alpha, beta, omega = params
N = len(R)
# Recursion relation for calculating sigma^2 using GARCH(1,1)
variance = np.zeros(N)
variance[0] = omega
for n in range(1, N):
variance[n] = omega + alpha * R[n-1]**2 + beta * variance[n - 1]
volatility = np.sqrt(variance)
return volatility
def fit_model(R, init=[5, 5, 5], verbose=False):
"""Calculates volatility using the symmetric GARCH(1,1) model.
For a definition of the model, see `sigma`.
The parameters for the model are cauluated using the maximum likelihood
method. The likelihood function is maximised using scipy.
Args:
R (numpy.array): Financial returns data from which to calculate
volatility.
init (list, optional): Initial values of the parameters to use in
optimisation
verbose (bool, optional): Whether or not to print warnings and
convergence information.
Returns:
An array containing the parameters of the model in the form
`[alpha, beta, omega]`.
Raises:
RuntimeError: If the optimisation algorithm fails to converge.
"""
N = len(R)
# Log of likelihood function
def L(params):
# Calculate variance using model
sigma_sq = sigma(R, params) ** 2
# ln(L) = -0.5 * sum_{n} {ln(sigma^2_n) + (r^2_n / sigma^2_n)}
value = np.log(sigma_sq) + ((R ** 2) / sigma_sq)
value = -0.5 * value.sum()
# Return -L instead of L (minimise -L => maximise L)
return -value
# Constraints for optimisation
# Use def instead of lambdas for speed
def w_con(x): # omega > 0
return np.array([x[2]])
def a_con(x): # alpha > 0
return np.array([x[0]])
def b_con(x): # beta > 0
return np.array([x[1]])
def ab_con(x): # alpha + beta < 1
return np.array([ 1 - x[0] - x[1] ])
omega_con = { 'type': 'ineq', 'fun': w_con }
alpha_con = { 'type': 'ineq', 'fun': a_con }
beta_con = { 'type': 'ineq', 'fun': b_con }
alpha_beta_con = { 'type': 'ineq', 'fun': ab_con }
cons = (alpha_con, beta_con, omega_con)
# Don't show warnings unless verbose flag specified
if not verbose:
warnings.filterwarnings('ignore')
# Minimise -L to find values of alpha, beta, and omega
res = minimize(L, init, constraints=cons,
options={ 'maxiter': 500, 'disp': verbose })
# Turn warnings back on if they were turned off above
if not verbose:
warnings.resetwarnings()
if res.success == False:
raise RuntimeError("Unable to fit GARCH(1,1) model: " + res.message)
return res.x
def expected(params):
"""Calculate the expected volatility predicted by the model.
Args:
params (numpy.array): The parameters from the fitted model of the form
`[alpha, beta, omega]`.
Raises:
ValueError: If the expected volatility is not well defined.
"""
alpha, beta, omega = params
if omega < 0:
raise ValueError("Expected volatility not defined for omega < 0")
if alpha + beta > 1:
raise ValueError("Expected volatility not defined for alpha + beta > 1")
return np.sqrt(omega / (1 - alpha - beta))
Functions
def expected(params)
-
Calculate the expected volatility predicted by the model.
Args
params
:numpy.array
- The parameters from the fitted model of the form
[alpha, beta, omega]
.
Raises
ValueError
- If the expected volatility is not well defined.
Source code
def expected(params): """Calculate the expected volatility predicted by the model. Args: params (numpy.array): The parameters from the fitted model of the form `[alpha, beta, omega]`. Raises: ValueError: If the expected volatility is not well defined. """ alpha, beta, omega = params if omega < 0: raise ValueError("Expected volatility not defined for omega < 0") if alpha + beta > 1: raise ValueError("Expected volatility not defined for alpha + beta > 1") return np.sqrt(omega / (1 - alpha - beta))
def fit_model(R, init=[5, 5, 5], verbose=False)
-
Calculates volatility using the symmetric GARCH(1,1) model.
For a definition of the model, see
sigma()
. The parameters for the model are cauluated using the maximum likelihood method. The likelihood function is maximised using scipy.Args
R
:numpy.array
- Financial returns data from which to calculate volatility.
init
:list
, optional- Initial values of the parameters to use in optimisation
verbose
:bool
, optional- Whether or not to print warnings and convergence information.
Returns
An array containing the parameters of the model in the form
[alpha, beta, omega]
.Raises
RuntimeError
- If the optimisation algorithm fails to converge.
Source code
def fit_model(R, init=[5, 5, 5], verbose=False): """Calculates volatility using the symmetric GARCH(1,1) model. For a definition of the model, see `sigma`. The parameters for the model are cauluated using the maximum likelihood method. The likelihood function is maximised using scipy. Args: R (numpy.array): Financial returns data from which to calculate volatility. init (list, optional): Initial values of the parameters to use in optimisation verbose (bool, optional): Whether or not to print warnings and convergence information. Returns: An array containing the parameters of the model in the form `[alpha, beta, omega]`. Raises: RuntimeError: If the optimisation algorithm fails to converge. """ N = len(R) # Log of likelihood function def L(params): # Calculate variance using model sigma_sq = sigma(R, params) ** 2 # ln(L) = -0.5 * sum_{n} {ln(sigma^2_n) + (r^2_n / sigma^2_n)} value = np.log(sigma_sq) + ((R ** 2) / sigma_sq) value = -0.5 * value.sum() # Return -L instead of L (minimise -L => maximise L) return -value # Constraints for optimisation # Use def instead of lambdas for speed def w_con(x): # omega > 0 return np.array([x[2]]) def a_con(x): # alpha > 0 return np.array([x[0]]) def b_con(x): # beta > 0 return np.array([x[1]]) def ab_con(x): # alpha + beta < 1 return np.array([ 1 - x[0] - x[1] ]) omega_con = { 'type': 'ineq', 'fun': w_con } alpha_con = { 'type': 'ineq', 'fun': a_con } beta_con = { 'type': 'ineq', 'fun': b_con } alpha_beta_con = { 'type': 'ineq', 'fun': ab_con } cons = (alpha_con, beta_con, omega_con) # Don't show warnings unless verbose flag specified if not verbose: warnings.filterwarnings('ignore') # Minimise -L to find values of alpha, beta, and omega res = minimize(L, init, constraints=cons, options={ 'maxiter': 500, 'disp': verbose }) # Turn warnings back on if they were turned off above if not verbose: warnings.resetwarnings() if res.success == False: raise RuntimeError("Unable to fit GARCH(1,1) model: " + res.message) return res.x
def sigma(R, params)
-
Calculates volatility using the symmetric GARCH(1,1) model
The symmetric GARCH(1,1) model is defined by the recursion relation:
sigma^{2}_{n+1} = omega + alpha * R^{2}_{n} + beta * sigma^{2}_{n}
where
sigma_n
is the volatilty at time-stepn
, andR_n
are the returns of the asset at time-stepn
. We assume thatsigma_0 = omega
.Args
R
:numpy.array
- Financial returns data from which to calculate volatility.
params
:numpy.array
- The parameters of the GARCH model to use. Should
be in the form
[alpha, beta, omega]
.
Returns
A numpy array of volatilties.
Source code
def sigma(R, params): """Calculates volatility using the symmetric GARCH(1,1) model The symmetric GARCH(1,1) model is defined by the recursion relation: sigma^{2}_{n+1} = omega + alpha * R^{2}_{n} + beta * sigma^{2}_{n} where `sigma_n` is the volatilty at time-step `n`, and `R_n` are the returns of the asset at time-step `n`. We assume that `sigma_0 = omega`. Args: R (numpy.array): Financial returns data from which to calculate volatility. params (numpy.array): The parameters of the GARCH model to use. Should be in the form `[alpha, beta, omega]`. Returns: A numpy array of volatilties. """ alpha, beta, omega = params N = len(R) # Recursion relation for calculating sigma^2 using GARCH(1,1) variance = np.zeros(N) variance[0] = omega for n in range(1, N): variance[n] = omega + alpha * R[n-1]**2 + beta * variance[n - 1] volatility = np.sqrt(variance) return volatility