def test_warnings(self): garch = GARCH() parameters = np.array([0.1, 0.2, 0.8, 4.0]) studt = StudentsT() with warnings.catch_warnings(record=True) as w: garch.simulate(parameters, 1000, studt.simulate([4.0])) assert_equal(len(w), 1) harch = HARCH(lags=[1, 5, 22]) parameters = np.array([0.1, 0.2, 0.4, 0.5]) with warnings.catch_warnings(record=True) as w: harch.simulate(parameters, 1000, studt.simulate([4.0])) assert_equal(len(w), 1)
def test_arch_harch(self): arch = ARCH(p=1) harch = HARCH(lags=1) assert_equal(arch.num_params, harch.num_params) parameters = np.array([0.5, 0.5]) backcast = arch.backcast(self.resids) assert_equal(backcast, harch.backcast(self.resids)) sigma2_arch = np.zeros_like(self.sigma2) sigma2_harch = np.zeros_like(self.sigma2) var_bounds = arch.variance_bounds(self.resids) arch.compute_variance(parameters, self.resids, sigma2_arch, backcast, var_bounds) harch.compute_variance(parameters, self.resids, sigma2_harch, backcast, var_bounds) assert_allclose(sigma2_arch, sigma2_harch) A, b = arch.constraints() Ah, bh = harch.constraints() assert_equal(A, Ah) assert_equal(b, bh)
def test_arch_harch(self): arch = ARCH(p=1) harch = HARCH(lags=1) assert_equal(arch.num_params, harch.num_params) parameters = np.array([0.5, 0.5]) backcast = arch.backcast(self.resids) assert_equal(backcast, harch.backcast(self.resids)) sigma2_arch = np.zeros_like(self.sigma2) sigma2_harch = np.zeros_like(self.sigma2) var_bounds = arch.variance_bounds(self.resids) arch.compute_variance(parameters, self.resids, sigma2_arch, backcast, var_bounds) harch.compute_variance(parameters, self.resids, sigma2_harch, backcast, var_bounds) assert_allclose(sigma2_arch, sigma2_harch) a, b = arch.constraints() ah, bh = harch.constraints() assert_equal(a, ah) assert_equal(b, bh) assert isinstance(arch.__str__(), str) txt = arch.__repr__() assert str(hex(id(arch))) in txt
def test_harch_scalar(self): harch = HARCH(lags=2) assert_equal(harch.num_params, 3) assert_equal(harch.name, 'HARCH')
def test_harch(self): harch = HARCH(lags=[1, 5, 22]) sv = harch.starting_values(self.resids) assert_equal(sv.shape[0], harch.num_params) bounds = harch.bounds(self.resids) assert_equal(bounds[0], (0.0, 10.0 * np.mean(self.resids ** 2.0))) assert_equal(bounds[1], (0.0, 1.0)) assert_equal(bounds[2], (0.0, 1.0)) assert_equal(bounds[3], (0.0, 1.0)) var_bounds = harch.variance_bounds(self.resids) backcast = harch.backcast(self.resids) w = 0.94 ** np.arange(75) assert_almost_equal(backcast, np.sum((self.resids[:75] ** 2) * (w / w.sum()))) parameters = np.array([.1, .4, .3, .2]) var_bounds = harch.variance_bounds(self.resids) harch.compute_variance(parameters, self.resids, self.sigma2, backcast, var_bounds) cond_var_direct = np.zeros_like(self.sigma2) lags = np.array([1, 5, 22], dtype=np.int32) rec.harch_recursion(parameters, self.resids, cond_var_direct, lags, self.T, backcast, var_bounds) names = harch.parameter_names() names_target = ['omega', 'alpha[1]', 'alpha[5]', 'alpha[22]'] assert_equal(names, names_target) assert_allclose(self.sigma2, cond_var_direct) a, b = harch.constraints() a_target = np.vstack((np.eye(4), np.array([[0, -1.0, -1.0, -1.0]]))) b_target = np.array([0.0, 0.0, 0.0, 0.0, -1.0]) assert_array_equal(a, a_target) assert_array_equal(b, b_target) state = np.random.get_state() rng = Normal() sim_data = harch.simulate(parameters, self.T, rng.simulate([])) np.random.set_state(state) e = np.random.standard_normal(self.T + 500) sigma2 = np.zeros(self.T + 500) data = np.zeros(self.T + 500) lagged = np.zeros(22) for t in range(self.T + 500): sigma2[t] = parameters[0] lagged[:] = backcast if t > 0: if t == 1: lagged[0] = data[0] ** 2.0 elif t < 22: lagged[:t] = data[t - 1::-1] ** 2.0 else: lagged = data[t - 1:t - 22:-1] ** 2.0 shock1 = data[t - 1] ** 2.0 if t > 0 else backcast if t >= 5: shock5 = np.mean(data[t - 5:t] ** 2.0) else: shock5 = 0.0 for i in range(5): shock5 += data[t - i - 1] if t - i - 1 >= 0 else backcast shock5 = shock5 / 5.0 if t >= 22: shock22 = np.mean(data[t - 22:t] ** 2.0) else: shock22 = 0.0 for i in range(22): shock22 += data[t - i - 1] if t - i - 1 >= 0 else backcast shock22 = shock22 / 22.0 sigma2[t] += parameters[1] * shock1 + parameters[2] * shock5 + parameters[3] * shock22 data[t] = e[t] * np.sqrt(sigma2[t]) data = data[500:] sigma2 = sigma2[500:] assert_almost_equal(data - sim_data[0] + 1.0, np.ones_like(data)) assert_almost_equal(sigma2 / sim_data[1], np.ones_like(sigma2)) assert_equal(harch.name, 'HARCH') assert_equal(harch.lags, [1, 5, 22]) assert_equal(harch.num_params, 4) assert isinstance(harch.__str__(), str) txt = harch.__repr__() assert str(hex(id(harch))) in txt
def arch_model( y: Optional[ArrayLike], x: Optional[ArrayLike] = None, mean: str = "Constant", lags: Optional[Union[int, List[int], NDArray]] = 0, vol: str = "Garch", p: Union[int, List[int]] = 1, o: int = 0, q: int = 1, power: float = 2.0, dist: str = "Normal", hold_back: Optional[int] = None, rescale: Optional[bool] = None, ) -> HARX: """ Initialization of common ARCH model specifications Parameters ---------- y : {ndarray, Series, None} The dependent variable x : {np.array, DataFrame}, optional Exogenous regressors. Ignored if model does not permit exogenous regressors. mean : str, optional Name of the mean model. Currently supported options are: 'Constant', 'Zero', 'LS', 'AR', 'ARX', 'HAR' and 'HARX' lags : int or list (int), optional Either a scalar integer value indicating lag length or a list of integers specifying lag locations. vol : str, optional Name of the volatility model. Currently supported options are: 'GARCH' (default), 'ARCH', 'EGARCH', 'FIARCH' and 'HARCH' p : int, optional Lag order of the symmetric innovation o : int, optional Lag order of the asymmetric innovation q : int, optional Lag order of lagged volatility or equivalent power : float, optional Power to use with GARCH and related models dist : int, optional Name of the error distribution. Currently supported options are: * Normal: 'normal', 'gaussian' (default) * Students's t: 't', 'studentst' * Skewed Student's t: 'skewstudent', 'skewt' * Generalized Error Distribution: 'ged', 'generalized error" hold_back : int Number of observations at the start of the sample to exclude when estimating model parameters. Used when comparing models with different lag lengths to estimate on the common sample. rescale : bool Flag indicating whether to automatically rescale data if the scale of the data is likely to produce convergence issues when estimating model parameters. If False, the model is estimated on the data without transformation. If True, than y is rescaled and the new scale is reported in the estimation results. Returns ------- model : ARCHModel Configured ARCH model Examples -------- >>> import datetime as dt >>> import pandas_datareader.data as web >>> djia = web.get_data_fred('DJIA') >>> returns = 100 * djia['DJIA'].pct_change().dropna() A basic GARCH(1,1) with a constant mean can be constructed using only the return data >>> from arch.univariate import arch_model >>> am = arch_model(returns) Alternative mean and volatility processes can be directly specified >>> am = arch_model(returns, mean='AR', lags=2, vol='harch', p=[1, 5, 22]) This example demonstrates the construction of a zero mean process with a TARCH volatility process and Student t error distribution >>> am = arch_model(returns, mean='zero', p=1, o=1, q=1, ... power=1.0, dist='StudentsT') Notes ----- Input that are not relevant for a particular specification, such as `lags` when `mean='zero'`, are silently ignored. """ known_mean = ("zero", "constant", "harx", "har", "ar", "arx", "ls") known_vol = ("arch", "figarch", "garch", "harch", "constant", "egarch") known_dist = ( "normal", "gaussian", "studentst", "t", "skewstudent", "skewt", "ged", "generalized error", ) mean = mean.lower() vol = vol.lower() dist = dist.lower() if mean not in known_mean: raise ValueError("Unknown model type in mean") if vol.lower() not in known_vol: raise ValueError("Unknown model type in vol") if dist.lower() not in known_dist: raise ValueError("Unknown model type in dist") if mean == "harx": am = HARX(y, x, lags, hold_back=hold_back, rescale=rescale) elif mean == "har": am = HARX(y, None, lags, hold_back=hold_back, rescale=rescale) elif mean == "arx": am = ARX(y, x, lags, hold_back=hold_back, rescale=rescale) elif mean == "ar": am = ARX(y, None, lags, hold_back=hold_back, rescale=rescale) elif mean == "ls": am = LS(y, x, hold_back=hold_back, rescale=rescale) elif mean == "constant": am = ConstantMean(y, hold_back=hold_back, rescale=rescale) else: # mean == "zero" am = ZeroMean(y, hold_back=hold_back, rescale=rescale) if vol in ("arch", "garch", "figarch", "egarch") and not isinstance(p, int): raise TypeError( "p must be a scalar int for all volatility processes except HARCH." ) if vol == "constant": v: VolatilityProcess = ConstantVariance() elif vol == "arch": assert isinstance(p, int) v = ARCH(p=p) elif vol == "figarch": assert isinstance(p, int) v = FIGARCH(p=p, q=q) elif vol == "garch": assert isinstance(p, int) v = GARCH(p=p, o=o, q=q, power=power) elif vol == "egarch": assert isinstance(p, int) v = EGARCH(p=p, o=o, q=q) else: # vol == 'harch' v = HARCH(lags=p) if dist in ("skewstudent", "skewt"): d: Distribution = SkewStudent() elif dist in ("studentst", "t"): d = StudentsT() elif dist in ("ged", "generalized error"): d = GeneralizedError() else: # ('gaussian', 'normal') d = Normal() am.volatility = v am.distribution = d return am
def test_harch(self): harch = HARCH(lags=[1, 5, 22]) sv = harch.starting_values(self.resids) assert_equal(sv.shape[0], harch.num_params) bounds = harch.bounds(self.resids) assert_equal(bounds[0], (0.0, 10.0 * np.mean(self.resids ** 2.0))) assert_equal(bounds[1], (0.0, 1.0)) assert_equal(bounds[2], (0.0, 1.0)) assert_equal(bounds[3], (0.0, 1.0)) var_bounds = harch.variance_bounds(self.resids) backcast = harch.backcast(self.resids) w = 0.94 ** np.arange(75) assert_almost_equal(backcast, np.sum((self.resids[:75] ** 2) * (w / w.sum()))) parameters = np.array([.1, .4, .3, .2]) var_bounds = harch.variance_bounds(self.resids) harch.compute_variance(parameters, self.resids, self.sigma2, backcast, var_bounds) cond_var_direct = np.zeros_like(self.sigma2) lags = np.array([1, 5, 22], dtype=np.int32) rec.harch_recursion(parameters, self.resids, cond_var_direct, lags, self.T, backcast, var_bounds) names = harch.parameter_names() names_target = ['omega', 'alpha[1]', 'alpha[5]', 'alpha[22]'] assert_equal(names, names_target) assert_allclose(self.sigma2, cond_var_direct) A, b = harch.constraints() A_target = np.vstack((np.eye(4), np.array([[0, -1.0, -1.0, -1.0]]))) b_target = np.array([0.0, 0.0, 0.0, 0.0, -1.0]) assert_array_equal(A, A_target) assert_array_equal(b, b_target) state = np.random.get_state() rng = Normal() sim_data = harch.simulate(parameters, self.T, rng.simulate([])) np.random.set_state(state) e = np.random.standard_normal(self.T + 500) initial_value = 1.0 sigma2 = np.zeros(self.T + 500) data = np.zeros(self.T + 500) lagged = np.zeros(22) for t in range(self.T + 500): sigma2[t] = parameters[0] lagged[:] = backcast if t > 0: if t == 1: lagged[0] = data[0] ** 2.0 elif t < 22: lagged[:t] = data[t - 1::-1] ** 2.0 else: lagged = data[t - 1:t - 22:-1] ** 2.0 shock1 = data[t - 1] ** 2.0 if t > 0 else backcast if t >= 5: shock5 = np.mean(data[t - 5:t] ** 2.0) else: shock5 = 0.0 for i in range(5): shock5 += data[t - i - 1] if t - i - 1 >= 0 else backcast shock5 = shock5 / 5.0 if t >= 22: shock22 = np.mean(data[t - 22:t] ** 2.0) else: shock22 = 0.0 for i in range(22): shock22 += data[t - i - 1] if t - i - 1 >= 0 else backcast shock22 = shock22 / 22.0 sigma2[t] += parameters[1] * shock1 \ + parameters[2] * shock5 \ + parameters[3] * shock22 data[t] = e[t] * np.sqrt(sigma2[t]) data = data[500:] sigma2 = sigma2[500:] assert_almost_equal(data - sim_data[0] + 1.0, np.ones_like(data)) assert_almost_equal(sigma2 / sim_data[1], np.ones_like(sigma2)) assert_equal(harch.name, 'HARCH') assert_equal(harch.lags, [1, 5, 22]) assert_equal(harch.num_params, 4)
def test_warnings_nonstationary_harch(self): studt = StudentsT() harch = HARCH(lags=[1, 5, 22]) parameters = np.array([0.1, 0.2, 0.4, 0.5]) with pytest.warns(InitialValueWarning): harch.simulate(parameters, 1000, studt.simulate([4.0]))
def arch_model(y, x=None, mean='Constant', lags=0, vol='Garch', p=1, o=0, q=1, power=2.0, dist='Normal', hold_back=None): """ Convenience function to simplify initialization of ARCH models Parameters ---------- y : {ndarray, Series, None} The dependent variable x : {np.array, DataFrame}, optional Exogenous regressors. Ignored if model does not permit exogenous regressors. mean : str, optional Name of the mean model. Currently supported options are: 'Constant', 'Zero', 'ARX' and 'HARX' lags : int or list (int), optional Either a scalar integer value indicating lag length or a list of integers specifying lag locations. vol : str, optional Name of the volatility model. Currently supported options are: 'GARCH' (default), "EGARCH', 'ARCH' and 'HARCH' p : int, optional Lag order of the symmetric innovation o : int, optional Lag order of the asymmetric innovation q : int, optional Lag order of lagged volatility or equivalent power : float, optional Power to use with GARCH and related models dist : int, optional Name of the error distribution. Currently supported options are: * Normal: 'normal', 'gaussian' (default) * Students's t: 't', 'studentst' * Skewed Student's t: 'skewstudent', 'skewt' * Generalized Error Distribution: 'ged', 'generalized error" hold_back : int Number of observations at the start of the sample to exclude when estimating model parameters. Used when comparing models with different lag lengths to estimate on the common sample. Returns ------- model : ARCHModel Configured ARCH model Examples -------- >>> import datetime as dt >>> import pandas_datareader.data as web >>> djia = web.get_data_fred('DJIA') >>> returns = 100 * djia['DJIA'].pct_change().dropna() A basic GARCH(1,1) with a constant mean can be constructed using only the return data >>> from arch.univariate import arch_model >>> am = arch_model(returns) Alternative mean and volatility processes can be directly specified >>> am = arch_model(returns, mean='AR', lags=2, vol='harch', p=[1, 5, 22]) This example demonstrates the construction of a zero mean process with a TARCH volatility process and Student t error distribution >>> am = arch_model(returns, mean='zero', p=1, o=1, q=1, ... power=1.0, dist='StudentsT') Notes ----- Input that are not relevant for a particular specification, such as `lags` when `mean='zero'`, are silently ignored. """ known_mean = ('zero', 'constant', 'harx', 'har', 'ar', 'arx', 'ls') known_vol = ('arch', 'garch', 'harch', 'constant', 'egarch') known_dist = ('normal', 'gaussian', 'studentst', 't', 'skewstudent', 'skewt', 'ged', 'generalized error') mean = mean.lower() vol = vol.lower() dist = dist.lower() if mean not in known_mean: raise ValueError('Unknown model type in mean') if vol.lower() not in known_vol: raise ValueError('Unknown model type in vol') if dist.lower() not in known_dist: raise ValueError('Unknown model type in dist') if mean == 'zero': am = ZeroMean(y, hold_back=hold_back) elif mean == 'constant': am = ConstantMean(y, hold_back=hold_back) elif mean == 'harx': am = HARX(y, x, lags, hold_back=hold_back) elif mean == 'har': am = HARX(y, None, lags, hold_back=hold_back) elif mean == 'arx': am = ARX(y, x, lags, hold_back=hold_back) elif mean == 'ar': am = ARX(y, None, lags, hold_back=hold_back) else: am = LS(y, x, hold_back=hold_back) if vol == 'constant': v = ConstantVariance() elif vol == 'arch': v = ARCH(p=p) elif vol == 'garch': v = GARCH(p=p, o=o, q=q, power=power) elif vol == 'egarch': v = EGARCH(p=p, o=o, q=q) else: # vol == 'harch' v = HARCH(lags=p) if dist in ('skewstudent', 'skewt'): d = SkewStudent() elif dist in ('studentst', 't'): d = StudentsT() elif dist in ('ged', 'generalized error'): d = GeneralizedError() else: # ('gaussian', 'normal') d = Normal() am.volatility = v am.distribution = d return am