def arch_recursion_python(parameters, resids, sigma2, p, nobs, backcast, var_bounds): """ Parameters ---------- parameters : ndarray Model parameters resids : ndarray Residuals to use in the recursion sigma2 : ndarray Conditional variances with same shape as resids p : int Number of lags in ARCH model nobs : int Length of resids backcast : float Value to use when initializing the recursion var_bounds : 2-d array nobs by 2-element array of upper and lower bounds for conditional variances for each time period """ for t in range(nobs): sigma2[t] = parameters[0] for i in range(p): if (t - i - 1) < 0: sigma2[t] += parameters[i + 1] * backcast else: sigma2[t] += parameters[i + 1] * resids[t - i - 1] ** 2 sigma2[t] = bounds_check(sigma2[t], var_bounds[t]) return sigma2
def _ar_forecast(y, horizon, start_index, constant, arp): """ Parameters ---------- y : array horizon : int start_index : int constant : float arp : array Returns ------- forecasts : array """ t = y.shape[0] p = arp.shape[0] fcasts = np.empty((t, p + horizon)) for i in range(p): fcasts[p - 1:, i] = y[i:(-p + i + 1)] if i < p - 1 else y[i:] for i in range(p, horizon + p): fcasts[:, i] = constant + fcasts[:, i-p:i].dot(arp[::-1]) fcasts[: start_index] = np.nan return fcasts[:, p:]
def _ar_forecast(y, horizon, start_index, constant, arp, exogp=None, x=None): """ Generate mean forecasts from an AR-X model Parameters ---------- y : ndarray horizon : int start_index : int constant : float arp : ndarray exogp : ndarray x : ndarray Returns ------- forecasts : array """ t = y.shape[0] p = arp.shape[0] fcasts = np.empty((t, p + horizon)) for i in range(p): fcasts[p - 1:, i] = y[i:(-p + i + 1)] if i < p - 1 else y[i:] for i in range(p, horizon + p): fcasts[:, i] = constant + fcasts[:, i - p:i].dot(arp[::-1]) fcasts[:start_index] = np.nan fcasts = fcasts[:, p:] if x is not None: exog_comp = np.dot(x, exogp[:, None]) fcasts[:-1] += exog_comp[1:] fcasts[-1] = np.nan fcasts[:, 1:] = np.nan return fcasts
def harch_recursion_python(parameters, resids, sigma2, lags, nobs, backcast, var_bounds): """ Parameters ---------- parameters : ndarray Model parameters resids : ndarray Residuals to use in the recursion sigma2 : ndarray Conditional variances with same shape as resids lags : ndarray Lag lengths in the HARCH nobs : int Length of resids backcast : float Value to use when initializing the recursion var_bounds : ndarray nobs by 2-element array of upper and lower bounds for conditional variances for each time period """ for t in range(nobs): sigma2[t] = parameters[0] for i in range(lags.shape[0]): param = parameters[i + 1] / lags[i] for j in range(lags[i]): if (t - j - 1) >= 0: sigma2[t] += param * resids[t - j - 1] * resids[t - j - 1] else: sigma2[t] += param * backcast sigma2[t] = bounds_check(sigma2[t], var_bounds[t]) return sigma2
def _ar_forecast(y, horizon, start_index, constant, arp, exogp=None, x=None): """ Generate mean forecasts from an AR-X model Parameters ---------- y : ndarray horizon : int start_index : int constant : float arp : ndarray exogp : ndarray x : ndarray Returns ------- forecasts : ndarray """ t = y.shape[0] p = arp.shape[0] fcasts = np.empty((t, p + horizon)) for i in range(p): fcasts[p - 1:, i] = y[i:(-p + i + 1)] if i < p - 1 else y[i:] for i in range(p, horizon + p): fcasts[:, i] = constant + fcasts[:, i - p:i].dot(arp[::-1]) fcasts[:start_index] = np.nan fcasts = fcasts[:, p:] if x is not None: exog_comp = np.dot(x, exogp[:, None]) fcasts[:-1] += exog_comp[1:] fcasts[-1] = np.nan fcasts[:, 1:] = np.nan return fcasts
def _ar_forecast(y, horizon, start_index, constant, arp): """ Parameters ---------- y : array horizon : int start_index : int constant : float arp : array Returns ------- forecasts : array """ t = y.shape[0] p = arp.shape[0] fcasts = np.empty((t, p + horizon)) for i in range(p): fcasts[p - 1:, i] = y[i:(-p + i + 1)] if i < p - 1 else y[i:] for i in range(p, horizon + p): fcasts[:, i] = constant + fcasts[:, i - p:i].dot(arp[::-1]) fcasts[:start_index] = np.nan return fcasts[:, p:]
def arch_recursion_python(parameters, resids, sigma2, p, nobs, backcast, var_bounds): """ Parameters ---------- parameters : ndarray Model parameters resids : ndarray Residuals to use in the recursion sigma2 : ndarray Conditional variances with same shape as resids p : int Number of lags in ARCH model nobs : int Length of resids backcast : float Value to use when initializing the recursion var_bounds : 2-d array nobs by 2-element array of upper and lower bounds for conditional variances for each time period """ for t in range(nobs): sigma2[t] = parameters[0] for i in range(p): if (t - i - 1) < 0: sigma2[t] += parameters[i + 1] * backcast else: sigma2[t] += parameters[i + 1] * resids[t - i - 1]**2 sigma2[t] = bounds_check(sigma2[t], var_bounds[t]) return sigma2
def garch_recursion_python(parameters, fresids, sresids, sigma2, p, o, q, nobs, backcast, var_bounds): """ Compute variance recursion for GARCH and related models Parameters ---------- parameters : ndarray Model parameters fresids : ndarray Absolute value of residuals raised to the power in the model. For example, in a standard GARCH model, the power is 2.0. sresids : ndarray Variable containing the sign of the residuals (-1.0, 0.0, 1.0) sigma2 : ndarray Conditional variances with same shape as resids p : int Number of symmetric innovations in model o : int Number of asymmetric innovations in model q : int Number of lags of the (transformed) variance in the model nobs : int Length of resids backcast : float Value to use when initializing the recursion var_bounds : 2-d array nobs by 2-element array of upper and lower bounds for conditional transformed variances for each time period """ for t in range(nobs): loc = 0 sigma2[t] = parameters[loc] loc += 1 for j in range(p): if (t - 1 - j) < 0: sigma2[t] += parameters[loc] * backcast else: sigma2[t] += parameters[loc] * fresids[t - 1 - j] loc += 1 for j in range(o): if (t - 1 - j) < 0: sigma2[t] += parameters[loc] * 0.5 * backcast else: sigma2[t] += parameters[loc] \ * fresids[t - 1 - j] * (sresids[t - 1 - j] < 0) loc += 1 for j in range(q): if (t - 1 - j) < 0: sigma2[t] += parameters[loc] * backcast else: sigma2[t] += parameters[loc] * sigma2[t - 1 - j] loc += 1 sigma2[t] = bounds_check(sigma2[t], var_bounds[t]) return sigma2
def test_arch_multiple_lags(self): arch = ARCH(p=5) sv = arch.starting_values(self.resids) assert_equal(sv.shape[0], arch.num_params) bounds = arch.bounds(self.resids) assert_equal(bounds[0], (0.0, 10.0 * np.mean(self.resids ** 2.0))) for i in range(1, 6): assert_equal(bounds[i], (0.0, 1.0)) var_bounds = arch.variance_bounds(self.resids) backcast = arch.backcast(self.resids) parameters = np.array([0.25, 0.17, 0.16, 0.15, 0.14, 0.13]) arch.compute_variance(parameters, self.resids, self.sigma2, backcast, var_bounds) cond_var_direct = np.zeros_like(self.sigma2) rec.arch_recursion(parameters, self.resids, cond_var_direct, 5, self.T, backcast, var_bounds) assert_allclose(self.sigma2, cond_var_direct) a, b = arch.constraints() a_target = np.vstack((np.eye(6), np.array([[0, -1.0, -1.0, -1.0, -1.0, -1.0]]))) b_target = np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0]) assert_array_equal(a, a_target) assert_array_equal(b, b_target) state = self.rng.get_state() rng = Normal() rng.random_state.set_state(state) sim_data = arch.simulate(parameters, self.T, rng.simulate([])) self.rng.set_state(state) e = self.rng.standard_normal(self.T + 500) initial_value = 1.0 sigma2 = np.zeros(self.T + 500) data = np.zeros(self.T + 500) for t in range(self.T + 500): sigma2[t] = parameters[0] for i in range(5): if t - i - 1 < 0: sigma2[t] += parameters[i + 1] * initial_value else: sigma2[t] += parameters[i + 1] * data[t - i - 1] ** 2.0 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)) names = arch.parameter_names() names_target = ['omega'] names_target.extend(['alpha[' + str(i + 1) + ']' for i in range(5)]) assert_equal(names, names_target) assert_equal(arch.num_params, 6) assert_equal(arch.name, 'ARCH')
def test_arch_multiple_lags(self): arch = ARCH(p=5) sv = arch.starting_values(self.resids) assert_equal(sv.shape[0], arch.num_params) bounds = arch.bounds(self.resids) assert_equal(bounds[0], (0.0, 10.0 * np.mean(self.resids ** 2.0))) for i in range(1, 6): assert_equal(bounds[i], (0.0, 1.0)) var_bounds = arch.variance_bounds(self.resids) backcast = arch.backcast(self.resids) parameters = np.array([0.25, 0.17, 0.16, 0.15, 0.14, 0.13]) arch.compute_variance(parameters, self.resids, self.sigma2, backcast, var_bounds) cond_var_direct = np.zeros_like(self.sigma2) rec.arch_recursion(parameters, self.resids, cond_var_direct, 5, self.T, backcast, var_bounds) assert_allclose(self.sigma2, cond_var_direct) A, b = arch.constraints() A_target = np.vstack((np.eye(6), np.array([[0, -1.0, -1.0, -1.0, -1.0, -1.0]]))) b_target = np.array([0.0, 0.0, 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 = arch.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) for t in range(self.T + 500): sigma2[t] = parameters[0] for i in range(5): if t - i - 1 < 0: sigma2[t] += parameters[i + 1] * initial_value else: sigma2[t] += parameters[i + 1] * data[t - i - 1] ** 2.0 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)) names = arch.parameter_names() names_target = ['omega'] names_target.extend(['alpha[' + str(i + 1) + ']' for i in range(5)]) assert_equal(names, names_target) assert_equal(arch.num_params, 6) assert_equal(arch.name, 'ARCH')
def midas_recursion_python(parameters, weights, resids, sigma2, nobs, backcast, var_bounds): """ Parameters ---------- parameters : ndarray Model parameters of the form (omega, alpha, gamma) where omega is the intercept, alpha is the scale for all shocks and gamma is the shock to negative returns (can be 0.0) for a symmetric model. weights : ndarray The weights on the lagged squared returns. Should sum to 1 resids : ndarray Residuals to use in the recursion sigma2 : ndarray Conditional variances with same shape as resids nobs : int Length of resids backcast : float Value to use when initializing the recursion var_bounds : ndarray nobs by 2-element array of upper and lower bounds for conditional variances for each time period """ omega, alpha, gamma = parameters m = weights.shape[0] aw = np.zeros(m) gw = np.zeros(m) for i in range(m): aw[i] = alpha * weights[i] gw[i] = gamma * weights[i] resids2 = np.zeros(nobs) for t in range(nobs): resids2[t] = resids[t] * resids[t] sigma2[t] = omega for i in range(m): if (t - i - 1) >= 0: sigma2[t] += (aw[i] + gw[i] * (resids[t - i - 1] < 0)) * resids2[t - i - 1] else: sigma2[t] += (aw[i] + 0.5 * gw[i]) * backcast if sigma2[t] < var_bounds[t, 0]: sigma2[t] = var_bounds[t, 0] elif sigma2[t] > var_bounds[t, 1]: if np.isinf(sigma2[t]): sigma2[t] = var_bounds[t, 1] + 1000 else: sigma2[t] = var_bounds[t, 1] + np.log( sigma2[t] / var_bounds[t, 1]) return sigma2
def midas_recursion_python(parameters, weights, resids, sigma2, nobs, backcast, var_bounds): """ Parameters ---------- parameters : ndarray Model parameters of the form (omega, alpha, gamma) where omega is the intercept, alpha is the scale for all shocks and gamma is the shock to negative returns (can be 0.0) for a symmetric model. weights : ndarray The weights on the lagged squared returns. Should sum to 1 resids : ndarray Residuals to use in the recursion sigma2 : ndarray Conditional variances with same shape as resids nobs : int Length of resids backcast : float Value to use when initializing the recursion var_bounds : ndarray nobs by 2-element array of upper and lower bounds for conditional variances for each time period """ omega, alpha, gamma = parameters m = weights.shape[0] aw = np.zeros(m) gw = np.zeros(m) for i in range(m): aw[i] = alpha * weights[i] gw[i] = gamma * weights[i] resids2 = np.zeros(nobs) for t in range(nobs): resids2[t] = resids[t] * resids[t] sigma2[t] = omega for i in range(m): if (t - i - 1) >= 0: sigma2[t] += (aw[i] + gw[i] * (resids[t - i - 1] < 0)) * resids2[t - i - 1] else: sigma2[t] += (aw[i] + 0.5 * gw[i]) * backcast if sigma2[t] < var_bounds[t, 0]: sigma2[t] = var_bounds[t, 0] elif sigma2[t] > var_bounds[t, 1]: if np.isinf(sigma2[t]): sigma2[t] = var_bounds[t, 1] + 1000 else: sigma2[t] = var_bounds[t, 1] + np.log(sigma2[t] / var_bounds[t, 1]) return sigma2
def figarch_recursion_python(parameters, fresids, sigma2, p, q, nobs, trunc_lag, backcast, var_bounds): """ Parameters ---------- parameters : ndarray Model parameters of the form (omega, phi, d, beta) where omega is the intercept, d is the fractional integration coefficient and phi and beta are parameters of the volatility process. fresids : ndarray Absolute value of residuals raised to the power in the model. For example, in a standard GARCH model, the power is 2.0. sigma2 : ndarray Conditional variances with same shape as resids p : int 0 or 1 to indicate whether the model contains phi q : int 0 or 1 to indicate whether the model contains beta nobs : int Length of resids trunc_lag : int Truncation lag for the ARCH approximations backcast : float Value to use when initializing the recursion var_bounds : ndarray nobs by 2-element array of upper and lower bounds for conditional variances for each time period Returns ------- sigma2 : ndarray Conditional variances """ omega = parameters[0] beta = parameters[1 + p + q] if q else 0.0 omega_tilde = omega / (1-beta) lam = figarch_weights(parameters[1:], p, q, trunc_lag) for t in range(nobs): bc_weight = 0.0 for i in range(t, trunc_lag): bc_weight += lam[i] sigma2[t] = omega_tilde + bc_weight * backcast for i in range(min(t, trunc_lag)): sigma2[t] += lam[i] * fresids[t - i - 1] sigma2[t] = bounds_check(sigma2[t], var_bounds[t]) return sigma2
def figarch_recursion_python(parameters, fresids, sigma2, p, q, nobs, trunc_lag, backcast, var_bounds): """ Parameters ---------- parameters : ndarray Model parameters of the form (omega, phi, d, beta) where omega is the intercept, d is the fractional integration coefficient and phi and beta are parameters of the volatility process. fresids : ndarray Absolute value of residuals raised to the power in the model. For example, in a standard GARCH model, the power is 2.0. sigma2 : ndarray Conditional variances with same shape as resids p : int 0 or 1 to indicate whether the model contains phi q : int 0 or 1 to indicate whether the model contains beta nobs : int Length of resids trunc_lag : int Truncation lag for the ARCH approximations backcast : float Value to use when initializing the recursion var_bounds : ndarray nobs by 2-element array of upper and lower bounds for conditional variances for each time period Returns ------- sigma2 : ndarray Conditional variances """ omega = parameters[0] beta = parameters[1 + p + q] if q else 0.0 omega_tilde = omega / (1 - beta) lam = figarch_weights(parameters[1:], p, q, trunc_lag) for t in range(nobs): bc_weight = 0.0 for i in range(t, trunc_lag): bc_weight += lam[i] sigma2[t] = omega_tilde + bc_weight * backcast for i in range(min(t, trunc_lag)): sigma2[t] += lam[i] * fresids[t - i - 1] sigma2[t] = bounds_check(sigma2[t], var_bounds[t]) return sigma2
def test_arch_lm(simulated_data): zm = ZeroMean(simulated_data, volatility=GARCH()) res = zm.fit(disp=DISPLAY) wald = res.arch_lm_test() nobs = simulated_data.shape[0] df = int(np.ceil(12. * np.power(nobs / 100., 1 / 4.))) assert wald.df == df assert 'Standardized' not in wald.null assert 'Standardized' not in wald.alternative assert 'H0: Standardized' not in wald.__repr__() assert 'heteroskedastic' in wald.__repr__() resids2 = res.resid**2 data = [resids2.shift(i) for i in range(df + 1)] data = pd.concat(data, 1).dropna() lhs = data.iloc[:, 0] rhs = smtools.add_constant(data.iloc[:, 1:]) ols_res = smlm.OLS(lhs, rhs).fit() assert_almost_equal(wald.stat, nobs * ols_res.rsquared) assert len(wald.critical_values) == 3 assert '10%' in wald.critical_values wald = res.arch_lm_test(lags=5) assert wald.df == 5 assert_almost_equal(wald.pval, 1 - stats.chi2(5).cdf(wald.stat)) wald = res.arch_lm_test(standardized=True) assert wald.df == df assert 'Standardized' in wald.null assert 'Standardized' in wald.alternative assert_almost_equal(wald.pval, 1 - stats.chi2(df).cdf(wald.stat)) assert 'H0: Standardized' in wald.__repr__()
def test_garch_no_symmetric(self): garch = GARCH(p=0, o=1, q=1) sv = garch.starting_values(self.resids) assert_equal(sv.shape[0], garch.num_params) bounds = garch.bounds(self.resids) assert_equal(bounds[0], (0.0, 10.0 * np.mean(self.resids ** 2.0))) assert_equal(bounds[1], (0.0, 2.0)) assert_equal(bounds[2], (0.0, 1.0)) var_bounds = garch.variance_bounds(self.resids) backcast = garch.backcast(self.resids) parameters = np.array([.1, .1, .8]) names = garch.parameter_names() names_target = ['omega', 'gamma[1]', 'beta[1]'] assert_equal(names, names_target) garch.compute_variance(parameters, self.resids, self.sigma2, backcast, var_bounds) cond_var_direct = np.zeros_like(self.sigma2) rec.garch_recursion(parameters, self.resids ** 2.0, np.sign(self.resids), cond_var_direct, 0, 1, 1, self.T, backcast, var_bounds) assert_allclose(self.sigma2, cond_var_direct) a, b = garch.constraints() a_target = np.vstack((np.eye(3), np.array([[0, -0.5, -1.0]]))) b_target = np.array([0.0, 0.0, 0.0, -1.0]) assert_array_equal(a, a_target) assert_array_equal(b, b_target) state = self.rng.get_state() rng = Normal() rng.random_state.set_state(state) sim_data = garch.simulate(parameters, self.T, rng.simulate([])) self.rng.set_state(state) e = self.rng.standard_normal(self.T + 500) initial_value = 1.0 sigma2 = np.zeros(self.T + 500) data = np.zeros(self.T + 500) for t in range(self.T + 500): sigma2[t] = parameters[0] shock = 0.5 * initial_value if t == 0 else \ data[t - 1] ** 2.0 * (data[t - 1] < 0) sigma2[t] += parameters[1] * shock lagged_value = initial_value if t == 0 else sigma2[t - 1] sigma2[t] += parameters[2] * lagged_value 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(garch.p, 0) assert_equal(garch.o, 1) assert_equal(garch.q, 1) assert_equal(garch.num_params, 3) assert_equal(garch.name, 'GJR-GARCH')
def test_constant_mean(self): cm = ConstantMean(self.y) parameters = np.array([5.0, 1.0]) cm.simulate(parameters, self.T) assert_equal(cm.num_params, 1) bounds = cm.bounds() assert_equal(bounds, [(-np.inf, np.inf)]) assert_equal(cm.constant, True) a, b = cm.constraints() assert_equal(a, np.empty((0, 1))) assert_equal(b, np.empty((0, ))) assert_true(isinstance(cm.volatility, ConstantVariance)) assert_true(isinstance(cm.distribution, Normal)) assert_equal(cm.first_obs, 0) assert_equal(cm.last_obs, 1000) assert_equal(cm.lags, None) res = cm.fit() assert_almost_equal(res.params, np.array([self.y.mean(), self.y.var()])) forecasts = res.forecast(horizon=20, start=20) direct = pd.DataFrame( index=np.arange(self.y.shape[0]), columns=['h.{0:>02d}'.format(i + 1) for i in range(20)], dtype=np.float64) direct.iloc[20:, :] = res.params.iloc[0] assert_frame_equal(direct, forecasts)
def test_ewma(self): ewma = EWMAVariance() sv = ewma.starting_values(self.resids) assert_equal(sv.shape[0], ewma.num_params) bounds = ewma.bounds(self.resids) assert_equal(len(bounds), 0) var_bounds = ewma.variance_bounds(self.resids) backcast = ewma.backcast(self.resids) parameters = np.array([]) names = ewma.parameter_names() names_target = [] assert_equal(names, names_target) ewma.compute_variance(parameters, self.resids, self.sigma2, backcast, var_bounds) cond_var_direct = np.zeros_like(self.sigma2) parameters = np.array([0.0, 0.06, 0.94]) rec.garch_recursion(parameters, self.resids ** 2.0, np.sign(self.resids), cond_var_direct, 1, 0, 1, self.T, backcast, var_bounds) assert_allclose(self.sigma2 / cond_var_direct, np.ones_like(self.sigma2)) a, b = ewma.constraints() a_target = np.empty((0, 0)) b_target = np.empty((0,)) assert_array_equal(a, a_target) assert_array_equal(b, b_target) state = self.rng.get_state() rng = Normal() rng.random_state.set_state(state) sim_data = ewma.simulate(parameters, self.T, rng.simulate([])) self.rng.set_state(state) e = self.rng.standard_normal(self.T + 500) initial_value = 1.0 sigma2 = np.zeros(self.T + 500) data = np.zeros(self.T + 500) sigma2[0] = initial_value data[0] = np.sqrt(initial_value) for t in range(1, self.T + 500): sigma2[t] = 0.94 * sigma2[t - 1] + 0.06 * data[t - 1] ** 2.0 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(ewma.num_params, 0) assert_equal(ewma.name, 'EWMA/RiskMetrics') assert isinstance(ewma.__str__(), str) txt = ewma.__repr__() assert str(hex(id(ewma))) in txt
def figarch_weights_python(parameters, p, q, truncation): r""" Parameters ---------- parameters : ndarray Model parameters of the form (omega, phi, d, beta) where omega is the intercept, d is the fractional integration coefficient and phi and beta are parameters of the volatility process. p : int 0 or 1 to indicate whether the model contains phi q : int 0 or 1 to indicate whether the model contains beta trunc_lag : int Truncation lag for the ARCH approximations Returns ------- lam : ndarray ARCH(:math:`\infty`) coefficients used to approximate model dynamics """ phi = parameters[0] if p else 0.0 d = parameters[1] if p else parameters[0] beta = parameters[p + q] if q else 0.0 # Recursive weight computation lam = np.empty(truncation) delta = np.empty(truncation) lam[0] = phi - beta + d delta[0] = d for i in range(1, truncation): delta[i] = (i - d) / (i + 1) * delta[i - 1] lam[i] = beta * lam[i - 1] + (delta[i] - phi * delta[i - 1]) return lam
def cgarch_recursion_python(parameters, fresids, sigma2, backcast, var_bounds, g2, q2): sqrd_resids = fresids nobs = len(sqrd_resids) alpha, beta, omega, raw, phi = parameters initial_sigma2 = backcast initial_q2 = 0.05 initial_g2 = initial_sigma2 - initial_q2 # g is short term variance and q is the long term one g2[0] = initial_g2 q2[0] = initial_q2 sigma2[0] = initial_sigma2 for t in range(1, nobs): g2[t] = alpha * (sqrd_resids[t - 1] - q2[t - 1]) + beta * g2[t - 1] q2[t] = omega + raw * q2[t - 1] + phi * (sqrd_resids[t - 1] - sigma2[t - 1]) sigma2[t] = g2[t] + q2[t] if sigma2[t] < var_bounds[t, 0]: sigma2[t] = var_bounds[t, 0] elif sigma2[t] > var_bounds[t, 1]: if not np.isinf(sigma2[t]): sigma2[t] = var_bounds[t, 1] + log( sigma2[t] / var_bounds[t, 1]) else: sigma2[t] = var_bounds[t, 1] + 1000 return sigma2
def test_ewma(self): ewma = EWMAVariance() sv = ewma.starting_values(self.resids) assert_equal(sv.shape[0], ewma.num_params) bounds = ewma.bounds(self.resids) assert_equal(len(bounds), 0) var_bounds = ewma.variance_bounds(self.resids) backcast = ewma.backcast(self.resids) parameters = np.array([]) names = ewma.parameter_names() names_target = [] assert_equal(names, names_target) ewma.compute_variance(parameters, self.resids, self.sigma2, backcast, var_bounds) cond_var_direct = np.zeros_like(self.sigma2) parameters = np.array([0.0, 0.06, 0.94]) rec.garch_recursion(parameters, self.resids ** 2.0, np.sign(self.resids), cond_var_direct, 1, 0, 1, self.T, backcast, var_bounds) # sigma3 = np.zeros_like(self.sigma2) # sigma3[0] = backcast # for t in range(1,self.T): # sigma3[t] = 0.94 * sigma3[t-1] + 0.06 * self.resids[t-1]**2.0 assert_allclose(self.sigma2 / cond_var_direct, np.ones_like(self.sigma2)) A, b = ewma.constraints() A_target = np.empty((0, 0)) b_target = np.empty((0,)) assert_array_equal(A, A_target) assert_array_equal(b, b_target) state = np.random.get_state() rng = Normal() sim_data = ewma.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) sigma2[0] = initial_value data[0] = np.sqrt(initial_value) for t in range(1, self.T + 500): sigma2[t] = 0.94 * sigma2[t - 1] + 0.06 * data[t - 1] ** 2.0 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(ewma.num_params, 0) assert_equal(ewma.name, 'EWMA/RiskMetrics')
def test_figarch_recursion(self): nobs, resids, = self.nobs, self.resids sigma2, backcast = self.sigma2, self.backcast parameters = np.array([1.0, 0.2, 0.4, 0.3]) fresids = resids**2 p = q = 1 trunc_lag = 1000 rec.figarch_recursion(parameters, fresids, sigma2, p, q, nobs, trunc_lag, backcast, self.var_bounds) lam = rec.figarch_weights(parameters[1:], p, q, truncation=trunc_lag) lam_rev = lam[::-1] omega_tilde = parameters[0] / (1 - parameters[-1]) sigma2_direct = np.empty_like(sigma2) for t in range(nobs): backcasts = trunc_lag - t sigma2_direct[t] = omega_tilde if backcasts: sigma2_direct[t] += backcast * lam_rev[:backcasts].sum() if t: sigma2_direct[t] += np.sum(lam_rev[-t:] * fresids[max(0, t - 1000):t]) assert_almost_equal(sigma2_direct, sigma2) recpy.figarch_recursion(parameters, fresids, sigma2, p, q, nobs, trunc_lag, backcast, self.var_bounds) sigma2_numba = sigma2.copy() recpy.figarch_recursion_python(parameters, fresids, sigma2, p, q, nobs, trunc_lag, backcast, self.var_bounds) sigma2_python = sigma2.copy() rec.figarch_recursion(parameters, fresids, sigma2, p, q, nobs, trunc_lag, backcast, self.var_bounds) assert_almost_equal(sigma2_numba, sigma2) assert_almost_equal(sigma2_python, sigma2)
def test_constant_mean(self): cm = ConstantMean(self.y) parameters = np.array([5.0, 1.0]) cm.simulate(parameters, self.T) assert_equal(cm.num_params, 1) bounds = cm.bounds() assert_equal(bounds, [(-np.inf, np.inf)]) assert_equal(cm.constant, True) a, b = cm.constraints() assert_equal(a, np.empty((0, 1))) assert_equal(b, np.empty((0,))) assert isinstance(cm.volatility, ConstantVariance) assert isinstance(cm.distribution, Normal) assert_equal(cm.lags, None) res = cm.fit(disp='off') expected = np.array([self.y.mean(), self.y.var()]) assert_almost_equal(res.params, expected) forecasts = res.forecast(horizon=20, start=20) direct = pd.DataFrame(index=np.arange(self.y.shape[0]), columns=['h.{0:>02d}'.format(i + 1) for i in range(20)], dtype=np.float64) direct.iloc[20:, :] = res.params.iloc[0] # TODO # assert_frame_equal(direct, forecasts) assert isinstance(forecasts, ARCHModelForecast)
def test_constant_mean(self): cm = ConstantMean(self.y) parameters = np.array([5.0, 1.0]) cm.simulate(parameters, self.T) assert_equal(cm.num_params, 1) with pytest.raises(ValueError): cm.simulate(parameters, self.T, x=np.array(10)) bounds = cm.bounds() assert_equal(bounds, [(-np.inf, np.inf)]) assert_equal(cm.constant, True) a, b = cm.constraints() assert_equal(a, np.empty((0, 1))) assert_equal(b, np.empty((0,))) assert isinstance(cm.volatility, ConstantVariance) assert isinstance(cm.distribution, Normal) assert_equal(cm.lags, None) res = cm.fit(disp='off') expected = np.array([self.y.mean(), self.y.var()]) assert_almost_equal(res.params, expected) forecasts = res.forecast(horizon=20, start=20) direct = pd.DataFrame(index=np.arange(self.y.shape[0]), columns=['h.{0:>02d}'.format(i + 1) for i in range(20)], dtype=np.float64) direct.iloc[20:, :] = res.params.iloc[0] # TODO # assert_frame_equal(direct, forecasts) assert isinstance(forecasts, ARCHModelForecast) assert isinstance(cm.__repr__(), str) assert isinstance(cm.__str__(), str) assert '<strong>' in cm._repr_html_()
def test_figarch_recursion(self): nobs, resids, = self.nobs, self.resids sigma2, backcast = self.sigma2, self.backcast parameters = np.array([1.0, 0.2, 0.4, 0.3]) fresids = resids ** 2 p = q = 1 trunc_lag = 1000 rec.figarch_recursion(parameters, fresids, sigma2, p, q, nobs, trunc_lag, backcast, self.var_bounds) lam = rec.figarch_weights(parameters[1:], p, q, truncation=trunc_lag) lam_rev = lam[::-1] omega_tilde = parameters[0] / (1 - parameters[-1]) sigma2_direct = np.empty_like(sigma2) for t in range(nobs): backcasts = trunc_lag - t sigma2_direct[t] = omega_tilde if backcasts: sigma2_direct[t] += backcast * lam_rev[:backcasts].sum() if t: sigma2_direct[t] += np.sum(lam_rev[-t:] * fresids[max(0, t - 1000):t]) assert_almost_equal(sigma2_direct, sigma2) recpy.figarch_recursion(parameters, fresids, sigma2, p, q, nobs, trunc_lag, backcast, self.var_bounds) sigma2_numba = sigma2.copy() recpy.figarch_recursion_python(parameters, fresids, sigma2, p, q, nobs, trunc_lag, backcast, self.var_bounds) sigma2_python = sigma2.copy() rec.figarch_recursion(parameters, fresids, sigma2, p, q, nobs, trunc_lag, backcast, self.var_bounds) assert_almost_equal(sigma2_numba, sigma2) assert_almost_equal(sigma2_python, sigma2)
def test_zero_mean(self): zm = ZeroMean(self.y) parameters = np.array([1.0]) data = zm.simulate(parameters, self.T) assert_equal(data.shape, (self.T, 3)) assert_equal(data['data'].shape[0], self.T) assert_equal(zm.num_params, 0) bounds = zm.bounds() assert_equal(bounds, []) assert_equal(zm.constant, False) a, b = zm.constraints() assert_equal(a, np.empty((0, 0))) assert_equal(b, np.empty((0,))) assert isinstance(zm.volatility, ConstantVariance) assert isinstance(zm.distribution, Normal) assert_equal(zm.lags, None) res = zm.fit(disp='off') assert_almost_equal(res.params, np.array([np.mean(self.y ** 2)])) forecasts = res.forecast(horizon=99) direct = pd.DataFrame(index=np.arange(self.y.shape[0]), columns=['h.{0:>02d}'.format(i + 1) for i in range(99)], dtype=np.float64) direct.iloc[:, :] = 0.0 assert isinstance(forecasts, ARCHModelForecast) # TODO # assert_frame_equal(direct, forecasts) garch = GARCH() zm.volatility = garch zm.fit(update_freq=0, disp=DISPLAY)
def test_zero_mean(self): zm = ZeroMean(self.y) parameters = np.array([1.0]) data = zm.simulate(parameters, self.T) assert_equal(data.shape, (self.T, 3)) assert_equal(data['data'].shape[0], self.T) assert_equal(zm.num_params, 0) bounds = zm.bounds() assert_equal(bounds, []) assert_equal(zm.constant, False) a, b = zm.constraints() assert_equal(a, np.empty((0, 0))) assert_equal(b, np.empty((0,))) assert isinstance(zm.volatility, ConstantVariance) assert isinstance(zm.distribution, Normal) assert_equal(zm.lags, None) res = zm.fit(disp='off') assert_almost_equal(res.params, np.array([np.mean(self.y ** 2)])) forecasts = res.forecast(horizon=99) direct = pd.DataFrame(index=np.arange(self.y.shape[0]), columns=['h.{0:>02d}'.format(i + 1) for i in range(99)], dtype=np.float64) direct.iloc[:, :] = 0.0 assert isinstance(forecasts, ARCHModelForecast) # TODO # assert_frame_equal(direct, forecasts) garch = GARCH() zm.volatility = garch zm.fit(update_freq=0, disp=DISPLAY) assert isinstance(zm.__repr__(), str) assert isinstance(zm.__str__(), str) assert '<strong>' in zm._repr_html_()
def test_garch(self): garch = GARCH() sv = garch.starting_values(self.resids) assert_equal(sv.shape[0], garch.num_params) bounds = garch.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)) backcast = garch.backcast(self.resids) w = 0.94**np.arange(75) assert_almost_equal(backcast, np.sum((self.resids[:75]**2) * (w / w.sum()))) var_bounds = garch.variance_bounds(self.resids) parameters = np.array([.1, .1, .8]) garch.compute_variance(parameters, self.resids, self.sigma2, backcast, var_bounds) cond_var_direct = np.zeros_like(self.sigma2) rec.garch_recursion(parameters, self.resids**2.0, np.sign(self.resids), cond_var_direct, 1, 0, 1, self.T, backcast, var_bounds) assert_allclose(self.sigma2, cond_var_direct) A, b = garch.constraints() A_target = np.vstack((np.eye(3), np.array([[0, -1.0, -1.0]]))) b_target = np.array([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 = garch.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) for t in range(self.T + 500): sigma2[t] = parameters[0] shock = initial_value if t == 0 else data[t - 1]**2.0 sigma2[t] += parameters[1] * shock lagged_value = initial_value if t == 0 else sigma2[t - 1] sigma2[t] += parameters[2] * lagged_value data[t] = e[t] * np.sqrt(sigma2[t]) data = data[500:] sigma2 = sigma2[500:] assert_almost_equal(data / sim_data[0], np.ones_like(data)) assert_almost_equal(sigma2 / sim_data[1], np.ones_like(sigma2)) names = garch.parameter_names() names_target = ['omega', 'alpha[1]', 'beta[1]'] assert_equal(names, names_target) assert_equal(garch.name, 'GARCH') assert_equal(garch.num_params, 3) assert_equal(garch.power, 2.0) assert_equal(garch.p, 1) assert_equal(garch.o, 0) assert_equal(garch.q, 1)
def test_egarch(self): nobs = self.nobs parameters = np.array([0.0, 0.1, -0.1, 0.95]) resids, sigma2 = self.resids, self.sigma2 p = o = q = 1 backcast = 0.0 var_bounds = self.var_bounds lnsigma2 = np.empty_like(sigma2) std_resids = np.empty_like(sigma2) abs_std_resids = np.empty_like(sigma2) recpy.egarch_recursion(parameters, resids, sigma2, p, o, q, nobs, backcast, var_bounds, lnsigma2, std_resids, abs_std_resids) sigma2_numba = sigma2.copy() recpy.egarch_recursion_python(parameters, resids, sigma2, p, o, q, nobs, backcast, var_bounds, lnsigma2, std_resids, abs_std_resids) sigma2_python = sigma2.copy() rec.egarch_recursion(parameters, resids, sigma2, p, o, q, nobs, backcast, var_bounds, lnsigma2, std_resids, abs_std_resids) assert_almost_equal(sigma2_numba, sigma2) assert_almost_equal(sigma2_python, sigma2) norm_const = np.sqrt(2 / np.pi) for t in range(nobs): lnsigma2[t] = parameters[0] if t == 0: lnsigma2[t] += parameters[3] * backcast else: stdresid = resids[t - 1] / np.sqrt(sigma2[t - 1]) lnsigma2[t] += parameters[1] * (np.abs(stdresid) - norm_const) lnsigma2[t] += parameters[2] * stdresid lnsigma2[t] += parameters[3] * lnsigma2[t - 1] sigma2[t] = np.exp(lnsigma2[t]) assert_almost_equal(sigma2_python, sigma2) parameters = np.array([-100.0, 0.1, -0.1, 0.95]) recpy.egarch_recursion_python(parameters, resids, sigma2, p, o, q, nobs, backcast, var_bounds, lnsigma2, std_resids, abs_std_resids) assert np.all(sigma2 >= self.var_bounds[:, 0]) assert np.all(sigma2 <= 2 * self.var_bounds[:, 1]) parameters = np.array([0.0, 0.1, -0.1, 9.5]) recpy.egarch_recursion_python(parameters, resids, sigma2, p, o, q, nobs, backcast, var_bounds, lnsigma2, std_resids, abs_std_resids) assert np.all(sigma2 >= self.var_bounds[:, 0]) assert np.all(sigma2 <= 2 * self.var_bounds[:, 1]) parameters = np.array([0.0, 0.1, -0.1, 0.95]) mod_resids = resids.copy() mod_resids[:1] = np.inf recpy.egarch_recursion_python(parameters, resids, sigma2, p, o, q, nobs, backcast, var_bounds, lnsigma2, std_resids, abs_std_resids) assert np.all(sigma2 >= self.var_bounds[:, 0]) assert np.all(sigma2 <= 2 * self.var_bounds[:, 1])
def test_garch_no_symmetric(self): garch = GARCH(p=0, o=1, q=1) sv = garch.starting_values(self.resids) assert_equal(sv.shape[0], garch.num_params) bounds = garch.bounds(self.resids) assert_equal(bounds[0], (0.0, 10.0 * np.mean(self.resids ** 2.0))) assert_equal(bounds[1], (0.0, 2.0)) assert_equal(bounds[2], (0.0, 1.0)) var_bounds = garch.variance_bounds(self.resids) backcast = garch.backcast(self.resids) parameters = np.array([.1, .1, .8]) names = garch.parameter_names() names_target = ['omega', 'gamma[1]', 'beta[1]'] assert_equal(names, names_target) garch.compute_variance(parameters, self.resids, self.sigma2, backcast, var_bounds) cond_var_direct = np.zeros_like(self.sigma2) rec.garch_recursion(parameters, self.resids ** 2.0, np.sign(self.resids), cond_var_direct, 0, 1, 1, self.T, backcast, var_bounds) assert_allclose(self.sigma2, cond_var_direct) A, b = garch.constraints() A_target = np.vstack((np.eye(3), np.array([[0, -0.5, -1.0]]))) b_target = np.array([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 = garch.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) for t in range(self.T + 500): sigma2[t] = parameters[0] shock = 0.5 * initial_value if t == 0 else \ data[t - 1] ** 2.0 * (data[t - 1] < 0) sigma2[t] += parameters[1] * shock lagged_value = initial_value if t == 0 else sigma2[t - 1] sigma2[t] += parameters[2] * lagged_value 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(garch.p, 0) assert_equal(garch.o, 1) assert_equal(garch.q, 1) assert_equal(garch.num_params, 3) assert_equal(garch.name, 'GJR-GARCH')
def test_figarch_weights(self): parameters = np.array([1.0, 0.4]) lam = rec.figarch_weights(parameters[1:], 0, 0, truncation=1000) lam_direct = np.empty_like(lam) lam_direct[0] = parameters[-1] for i in range(1, 1000): lam_direct[i] = (i - parameters[-1]) / (i + 1) * lam_direct[i - 1] assert_almost_equal(lam, lam_direct)
def test_arch(self): arch = ARCH() sv = arch.starting_values(self.resids) assert_equal(sv.shape[0], arch.num_params) bounds = arch.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)) backcast = arch.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([0.5, 0.7]) var_bounds = arch.variance_bounds(self.resids) arch.compute_variance(parameters, self.resids, self.sigma2, backcast, var_bounds) cond_var_direct = np.zeros_like(self.sigma2) rec.arch_recursion(parameters, self.resids, cond_var_direct, 1, self.T, backcast, var_bounds) assert_allclose(self.sigma2, cond_var_direct) a, b = arch.constraints() a_target = np.vstack((np.eye(2), np.array([[0, -1.0]]))) b_target = np.array([0.0, 0.0, -1.0]) assert_array_equal(a, a_target) assert_array_equal(b, b_target) state = self.rng.get_state() rng = Normal() rng.random_state.set_state(state) sim_data = arch.simulate(parameters, self.T, rng.simulate([])) self.rng.set_state(state) e = self.rng.standard_normal(self.T + 500) initial_value = 1.0 sigma2 = np.zeros(self.T + 500) data = np.zeros(self.T + 500) for t in range(self.T + 500): sigma2[t] = parameters[0] shock = initial_value if t == 0 else data[t - 1] ** 2.0 sigma2[t] += parameters[1] * shock 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)) names = arch.parameter_names() names_target = ['omega', 'alpha[1]'] assert_equal(names, names_target) assert_equal(arch.name, 'ARCH') assert_equal(arch.num_params, 2) assert_equal(arch.p, 1) assert isinstance(arch.__str__(), str) txt = arch.__repr__() assert str(hex(id(arch))) in txt
def test_arch(self): arch = ARCH() sv = arch.starting_values(self.resids) assert_equal(sv.shape[0], arch.num_params) bounds = arch.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)) backcast = arch.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([0.5, 0.7]) var_bounds = arch.variance_bounds(self.resids) arch.compute_variance(parameters, self.resids, self.sigma2, backcast, var_bounds) cond_var_direct = np.zeros_like(self.sigma2) rec.arch_recursion(parameters, self.resids, cond_var_direct, 1, self.T, backcast, var_bounds) assert_allclose(self.sigma2, cond_var_direct) A, b = arch.constraints() A_target = np.vstack((np.eye(2), np.array([[0, -1.0]]))) b_target = np.array([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 = arch.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) for t in range(self.T + 500): sigma2[t] = parameters[0] shock = initial_value if t == 0 else data[t - 1] ** 2.0 sigma2[t] += parameters[1] * shock 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)) names = arch.parameter_names() names_target = ['omega', 'alpha[1]'] assert_equal(names, names_target) assert_equal(arch.name, 'ARCH') assert_equal(arch.num_params, 2) assert_equal(arch.p, 1) assert_true(isinstance(arch.__str__(), str)) repr = arch.__repr__() assert_true(str(hex(id(arch))) in repr)
def _compute_statistic(self): overlap, debiased, robust = self._overlap, self._debiased, self._robust y, nobs, q, trend = self._y, self._nobs, self._lags, self._trend nq = nobs - 1 if not overlap: # Check length of y if nq % q != 0: extra = nq % q y = y[:-extra] warnings.warn( invalid_length_doc.format(var='y', block=q, drop=extra), InvalidLengthWarning) nobs = y.shape[0] if trend == 'nc': mu = 0 else: mu = (y[-1] - y[0]) / (nobs - 1) delta_y = diff(y) nq = delta_y.shape[0] sigma2_1 = sum((delta_y - mu)**2.0) / nq if not overlap: delta_y_q = y[q::q] - y[0:-q:q] sigma2_q = sum((delta_y_q - q * mu)**2.0) / nq self._summary_text = ['Computed with non-overlapping blocks'] else: delta_y_q = y[q:] - y[:-q] sigma2_q = sum((delta_y_q - q * mu)**2.0) / (nq * q) self._summary_text = ['Computed with overlapping blocks'] if debiased and overlap: sigma2_1 *= nq / (nq - 1) m = q * (nq - q + 1) * (1 - (q / nq)) sigma2_q *= (nq * q) / m self._summary_text = [ 'Computed with overlapping blocks ' '(de-biased)' ] if not overlap: self._stat_variance = 2.0 * (q - 1) elif not robust: self._stat_variance = (2 * (2 * q - 1) * (q - 1)) / (2 * q) else: z2 = (delta_y - mu)**2.0 scale = sum(z2)**2.0 theta = 0.0 for k in range(1, q): delta = nq * z2[k:].dot(z2[:-k]) / scale theta += (1 - k / q)**2.0 * delta self._stat_variance = theta self._vr = sigma2_q / sigma2_1 self._stat = sqrt(nq) * (self._vr - 1) / sqrt(self._stat_variance) self._pvalue = 2 - 2 * norm.cdf(abs(self._stat))
def _generate_lag_names(self): lags = self._lags names = [] var_name = self._y_series.name if len(var_name) > 10: var_name = var_name[:4] + '...' + var_name[-3:] for i in range(lags.shape[1]): names.append(var_name + '[' + str(lags[1, i]) + ']') return names
def test_align(self): dates = pd.date_range('2000-01-01', '2010-01-01', freq='M') columns = ['h.' + '{0:>02}'.format(str(h + 1)) for h in range(10)] forecasts = pd.DataFrame(np.random.randn(120, 10), index=dates, columns=columns) aligned = align_forecast(forecasts.copy(), align='origin') assert_frame_equal(aligned, forecasts) aligned = align_forecast(forecasts.copy(), align='target') direct = forecasts.copy() for i in range(10): direct.iloc[(i + 1):, i] = direct.iloc[:(120 - i - 1), i].values direct.iloc[:(i + 1), i] = np.nan assert_frame_equal(aligned, direct) assert_raises(ValueError, align_forecast, forecasts, align='unknown')
def _compute_statistic(self): overlap, debiased, robust = self._overlap, self._debiased, self._robust y, nobs, q, trend = self._y, self._nobs, self._lags, self._trend nq = nobs - 1 if not overlap: # Check length of y if nq % q != 0: extra = nq % q y = y[:-extra] warnings.warn(invalid_length_doc.format(var='y', block=q, drop=extra), InvalidLengthWarning) nobs = y.shape[0] if trend == 'nc': mu = 0 else: mu = (y[-1] - y[0]) / (nobs - 1) delta_y = diff(y) nq = delta_y.shape[0] sigma2_1 = sum((delta_y - mu) ** 2.0) / nq if not overlap: delta_y_q = y[q::q] - y[0:-q:q] sigma2_q = sum((delta_y_q - q * mu) ** 2.0) / nq self._summary_text = ['Computed with non-overlapping blocks'] else: delta_y_q = y[q:] - y[:-q] sigma2_q = sum((delta_y_q - q * mu) ** 2.0) / (nq * q) self._summary_text = ['Computed with overlapping blocks'] if debiased and overlap: sigma2_1 *= nq / (nq - 1) m = q * (nq - q + 1) * (1 - (q / nq)) sigma2_q *= (nq * q) / m self._summary_text = ['Computed with overlapping blocks ' '(de-biased)'] if not overlap: self._stat_variance = 2.0 * (q - 1) elif not robust: self._stat_variance = (2 * (2 * q - 1) * (q - 1)) / (2 * q) else: z2 = (delta_y - mu) ** 2.0 scale = sum(z2) ** 2.0 theta = 0.0 for k in range(1, q): delta = nq * z2[k:].dot(z2[:-k]) / scale theta += (1 - k / q) ** 2.0 * delta self._stat_variance = theta self._vr = sigma2_q / sigma2_1 self._stat = sqrt(nq) * (self._vr - 1) / sqrt(self._stat_variance) self._pvalue = 2 - 2 * norm.cdf(abs(self._stat))
def test_garch_power(self): garch = GARCH(power=1.0) assert_equal(garch.num_params, 3) assert_equal(garch.name, 'AVGARCH') assert_equal(garch.power, 1.0) sv = garch.starting_values(self.resids) assert_equal(sv.shape[0], garch.num_params) bounds = garch.bounds(self.resids) assert_equal(bounds[0], (0.0, 10.0 * np.mean(np.abs(self.resids)))) assert_equal(bounds[1], (0.0, 1.0)) assert_equal(bounds[2], (0.0, 1.0)) var_bounds = garch.variance_bounds(self.resids) backcast = garch.backcast(self.resids) w = 0.94 ** np.arange(75) assert_almost_equal(backcast, np.sum(np.abs(self.resids[:75]) * (w / w.sum()))) parameters = np.array([.1, .1, .8]) garch.compute_variance(parameters, self.resids, self.sigma2, backcast, var_bounds) cond_var_direct = np.zeros_like(self.sigma2) rec.garch_recursion(parameters, np.abs(self.resids), np.sign(self.resids), cond_var_direct, 1, 0, 1, self.T, backcast, var_bounds) cond_var_direct **= 2.0 # Square since recursion does not apply power assert_allclose(self.sigma2, cond_var_direct) a, b = garch.constraints() a_target = np.vstack((np.eye(3), np.array([[0, -1.0, -1.0]]))) b_target = np.array([0.0, 0.0, 0.0, -1.0]) assert_array_equal(a, a_target) assert_array_equal(b, b_target) state = self.rng.get_state() rng = Normal() rng.random_state.set_state(state) sim_data = garch.simulate(parameters, self.T, rng.simulate([])) self.rng.set_state(state) e = self.rng.standard_normal(self.T + 500) initial_value = 1.0 sigma = np.zeros(self.T + 500) data = np.zeros(self.T + 500) for t in range(self.T + 500): sigma[t] = parameters[0] shock = initial_value if t == 0 else np.abs(data[t - 1]) sigma[t] += parameters[1] * shock lagged_value = initial_value if t == 0 else sigma[t - 1] sigma[t] += parameters[2] * lagged_value data[t] = e[t] * sigma[t] data = data[500:] sigma2 = sigma[500:] ** 2.0 assert_almost_equal(data - sim_data[0] + 1.0, np.ones_like(data)) assert_almost_equal(sigma2 / sim_data[1], np.ones_like(sigma2))
def _check_specification(self): """Checks the specification for obvious errors """ if self._x is not None: if self._x.ndim != 2 or self._x.shape[0] != self._y.shape[0]: raise ValueError( 'x must be nobs by n, where nobs is the same as ' 'the number of elements in y') def_names = ['x' + str(i) for i in range(self._x.shape[1])] self._x_names, self._x_index = parse_dataframe(self._x, def_names) self._x = np.asarray(self._x)
def _autolag_ols(endog, exog, startlag, maxlag, method): """ Returns the results for the lag length that maximizes the info criterion. Parameters ---------- endog : {ndarray, Series} nobs array containing endogenous variable exog : {ndarray, DataFrame} nobs by (startlag + maxlag) array containing lags and possibly other variables startlag : int The first zero-indexed column to hold a lag. See Notes. maxlag : int The highest lag order for lag length selection. method : {'aic', 'bic', 't-stat'} aic - Akaike Information Criterion bic - Bayes Information Criterion t-stat - Based on last lag Returns ------- icbest : float Minimum value of the information criteria lag : int The lag length that maximizes the information criterion. Notes ----- Does estimation like mod(endog, exog[:,:i]).fit() where i goes from lagstart to lagstart + maxlag + 1. Therefore, lags are assumed to be in contiguous columns from low to high lag length with the highest lag in the last column. """ method = method.lower() q, r = qr(exog) qpy = q.T.dot(endog) ypy = endog.T.dot(endog) xpx = exog.T.dot(exog) effective_max_lag = min(maxlag, matrix_rank(xpx) - startlag) sigma2 = empty(effective_max_lag + 1) tstat = empty(effective_max_lag + 1) nobs = float(endog.shape[0]) tstat[0] = inf for i in range(startlag, startlag + effective_max_lag + 1): b = solve(r[:i, :i], qpy[:i]) sigma2[i - startlag] = (ypy - b.T.dot(xpx[:i, :i]).dot(b)) / nobs if method == 't-stat' and i > startlag: xpxi = inv(xpx[:i, :i]) stderr = sqrt(sigma2[i - startlag] * xpxi[-1, -1]) tstat[i - startlag] = b[-1] / stderr return _select_best_ic(method, nobs, sigma2, tstat)
def test_garch_power(self): garch = GARCH(power=1.0) assert_equal(garch.num_params, 3) assert_equal(garch.name, 'AVGARCH') assert_equal(garch.power, 1.0) sv = garch.starting_values(self.resids) assert_equal(sv.shape[0], garch.num_params) bounds = garch.bounds(self.resids) assert_equal(bounds[0], (0.0, 10.0 * np.mean(np.abs(self.resids)))) assert_equal(bounds[1], (0.0, 1.0)) assert_equal(bounds[2], (0.0, 1.0)) var_bounds = garch.variance_bounds(self.resids) backcast = garch.backcast(self.resids) w = 0.94 ** np.arange(75) assert_almost_equal(backcast, np.sum(np.abs(self.resids[:75]) * (w / w.sum()))) parameters = np.array([.1, .1, .8]) garch.compute_variance(parameters, self.resids, self.sigma2, backcast, var_bounds) cond_var_direct = np.zeros_like(self.sigma2) rec.garch_recursion(parameters, np.abs(self.resids), np.sign(self.resids), cond_var_direct, 1, 0, 1, self.T, backcast, var_bounds) cond_var_direct **= 2.0 # Square since recursion does not apply power assert_allclose(self.sigma2, cond_var_direct) A, b = garch.constraints() A_target = np.vstack((np.eye(3), np.array([[0, -1.0, -1.0]]))) b_target = np.array([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 = garch.simulate(parameters, self.T, rng.simulate([])) np.random.set_state(state) e = np.random.standard_normal(self.T + 500) initial_value = 1.0 sigma = np.zeros(self.T + 500) data = np.zeros(self.T + 500) for t in range(self.T + 500): sigma[t] = parameters[0] shock = initial_value if t == 0 else np.abs(data[t - 1]) sigma[t] += parameters[1] * shock lagged_value = initial_value if t == 0 else sigma[t - 1] sigma[t] += parameters[2] * lagged_value data[t] = e[t] * sigma[t] data = data[500:] sigma2 = sigma[500:] ** 2.0 assert_almost_equal(data - sim_data[0] + 1.0, np.ones_like(data)) assert_almost_equal(sigma2 / sim_data[1], np.ones_like(sigma2))
def test_garch_no_lagged_vol(self): garch = GARCH(p=1, o=1, q=0) sv = garch.starting_values(self.resids) assert_equal(sv.shape[0], garch.num_params) bounds = garch.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], (-1.0, 2.0)) backcast = garch.backcast(self.resids) parameters = np.array([.5, .25, .5]) var_bounds = garch.variance_bounds(self.resids) garch.compute_variance(parameters, self.resids, self.sigma2, backcast, var_bounds) cond_var_direct = np.zeros_like(self.sigma2) rec.garch_recursion(parameters, self.resids**2.0, np.sign(self.resids), cond_var_direct, 1, 1, 0, self.T, backcast, var_bounds) assert_allclose(self.sigma2, cond_var_direct) A, b = garch.constraints() A_target = np.vstack((np.eye(3), np.array([[0, -1.0, -0.5]]))) A_target[2, 1] = 1.0 b_target = np.array([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 = garch.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) for t in range(self.T + 500): sigma2[t] = parameters[0] shock = initial_value if t == 0 else data[t - 1]**2.0 sigma2[t] += parameters[1] * shock shock = 0.5 * initial_value if t == 0 else \ (data[t - 1] ** 2.0) * (data[t - 1] < 0) sigma2[t] += parameters[2] * shock 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(garch.p, 1) assert_equal(garch.o, 1) assert_equal(garch.q, 0) assert_equal(garch.num_params, 3) assert_equal(garch.name, 'GJR-GARCH')
def _generate_lag_names(self): """Generates lag names. Overridden by other models""" lags = self._lags names = [] var_name = self._y_series.name if len(var_name) > 10: var_name = var_name[:4] + '...' + var_name[-3:] for i in range(lags.shape[1]): names.append(var_name + '[' + str(lags[0, i]) + ':' + str(lags[1, i]) + ']') return names
def update_indices(self): """ Update indices for the next iteration of the bootstrap. This must be overridden when creating new bootstraps. """ randint = self._random_state.randint pos_indices = [randint(self._num_arg_items[i], size=self._num_arg_items[i]) for i in range(self._num_args)] kw_indices = {key: randint(self._num_kw_items[key], size=self._num_kw_items[key]) for key in self._kwargs} return pos_indices, kw_indices
def _generate_lag_names(self): """Generates lag names. Overridden by other models""" lags = self._lags names = [] var_name = self._y_series.name if len(var_name) > 10: var_name = var_name[:4] + '...' + var_name[-3:] for i in range(lags.shape[1]): names.append( var_name + '[' + str(lags[0, i]) + ':' + str(lags[1, i]) + ']') return names
def _ar_to_impulse(steps, params): p = params.shape[0] impulse = np.zeros(steps) impulse[0] = 1 if p == 0: return impulse for i in range(1, steps): k = min(p - 1, i - 1) st = max(i - p, 0) impulse[i] = impulse[st:i].dot(params[k::-1]) return impulse
def _reformat_lags(self): """ Reformats the input lags to a 2 by m array, which simplifies other operations. Output is stored in _lags """ lags = self.lags if lags is None: self._lags = None return lags = np.asarray(lags) if np.any(lags < 0): raise ValueError("Input to lags must be non-negative") if lags.ndim == 0: lags = np.arange(1, lags + 1) if lags.ndim == 1: if np.any(lags <= 0): raise ValueError('When using the 1-d format of lags, values ' 'must be positive') lags = np.unique(lags) temp = np.array([lags, lags]) if self.use_rotated: temp[0, 1:] = temp[0, 0:-1] temp[0, 0] = 0 else: temp[0, :] = 0 self._lags = temp elif lags.ndim == 2: if lags.shape[0] != 2: raise ValueError('When using a 2-d array, lags must by k by 2') if np.any(lags[0] < 0) or np.any(lags[1] <= 0): raise ValueError('Incorrect values in lags') ind = np.lexsort(np.flipud(lags)) lags = lags[:, ind] test_mat = zeros((lags.shape[1], np.max(lags))) for i in range(lags.shape[1]): test_mat[i, lags[0, i]:lags[1, i]] = 1.0 rank = np.linalg.matrix_rank(test_mat) if rank != lags.shape[1]: raise ValueError('lags contains redundant entries') self._lags = lags if self.use_rotated: from warnings import warn warn('Rotation is not available when using the ' '2-d lags input format') else: raise ValueError('Incorrect format for lags')
def test_harx(self): harx = HARX(self.y, self.x, lags=[1, 5, 22]) params = np.array([1.0, 0.4, 0.3, 0.2, 1.0, 1.0]) data = harx.simulate(params, self.T, x=randn(self.T + 500, 1)) iv = randn(22, 1) data = harx.simulate(params, self.T, x=randn(self.T + 500, 1), initial_value=iv) assert_equal(data.shape, (self.T, 3)) cols = ['data', 'volatility', 'errors'] for c in cols: assert_true(c in data) bounds = harx.bounds() for b in bounds: assert_equal(b[0], -np.inf) assert_equal(b[1], np.inf) assert_equal(len(bounds), 5) assert_equal(harx.num_params, 1 + 3 + self.x.shape[1]) assert_equal(harx.constant, True) a, b = harx.constraints() assert_equal(a, np.empty((0, 5))) assert_equal(b, np.empty(0)) res = harx.fit() assert_raises(RuntimeError, res.forecast, horizon=10) assert_raises(ValueError, res.forecast, params=np.array([1.0, 1.0])) nobs = self.T - 22 rhs = np.ones((nobs, 5)) y = self.y lhs = y[22:] for i in range(self.T - 22): rhs[i, 1] = y[i + 21] rhs[i, 2] = np.mean(y[i + 17:i + 22]) rhs[i, 3] = np.mean(y[i:i + 22]) rhs[:, 4] = self.x[22:, 0] params = np.linalg.pinv(rhs).dot(lhs) assert_almost_equal(params, res.params[:-1]) assert_equal(harx.first_obs, 22) assert_equal(harx.last_obs, 1000) assert_equal(harx.hold_back, None) assert_equal(harx.lags, [1, 5, 22]) assert_equal(harx.nobs, self.T - 22) assert_equal(harx.name, 'HAR-X') assert_equal(harx.use_rotated, False) harx harx._repr_html_() res = harx.fit(cov_type='mle') res
def test_egarch_100(self): egarch = EGARCH(p=1, o=0, q=0) sv = egarch.starting_values(self.resids) assert_equal(sv.shape[0], egarch.num_params) backcast = egarch.backcast(self.resids) w = 0.94 ** np.arange(75) backcast_test = np.sum((self.resids[:75] ** 2) * (w / w.sum())) assert_almost_equal(backcast, np.log(backcast_test)) var_bounds = egarch.variance_bounds(self.resids) parameters = np.array([.1, .4]) egarch.compute_variance(parameters, self.resids, self.sigma2, backcast, var_bounds) cond_var_direct = np.zeros_like(self.sigma2) lnsigma2 = np.empty(self.T) std_resids = np.empty(self.T) abs_std_resids = np.empty(self.T) rec.egarch_recursion(parameters, self.resids, cond_var_direct, 1, 0, 0, self.T, backcast, var_bounds, lnsigma2, std_resids, abs_std_resids) assert_allclose(self.sigma2, cond_var_direct) state = np.random.get_state() rng = Normal() sim_data = egarch.simulate(parameters, self.T, rng.simulate([])) np.random.set_state(state) e = np.random.standard_normal(self.T + 500) initial_value = 0.1 / (1 - 0.95) lnsigma2 = np.zeros(self.T + 500) lnsigma2[0] = initial_value sigma2 = np.zeros(self.T + 500) sigma2[0] = np.exp(lnsigma2[0]) data = np.zeros(self.T + 500) data[0] = np.sqrt(sigma2[0]) * e[0] norm_const = np.sqrt(2 / np.pi) for t in range(1, self.T + 500): lnsigma2[t] = parameters[0] lnsigma2[t] += parameters[1] * (np.abs(e[t - 1]) - norm_const) sigma2 = np.exp(lnsigma2) data = e * np.sqrt(sigma2) 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))
def reset(self, use_seed=True): """ Resets the bootstrap to either its initial state or the last seed. Parameters ---------- use_seed : bool, optional Flag indicating whether to use the last seed if provided. If False or if no seed has been set, the bootstrap will be reset to the initial state. Default is True """ pos_indices = [np.arange(self._num_arg_items[i]) for i in range(self._num_args)] kw_indices = {key: np.arange(self._num_kw_items[key]) for key in self._kwargs} self._index = pos_indices, kw_indices self._resample() self.random_state.set_state(self._initial_state) if use_seed and self._seed is not None: self.seed(self._seed) return None
def bootstrap(self, reps): """ Iterator for use when bootstrapping Parameters ---------- reps : int Number of bootstrap replications Returns ------- gen : generator Generator to iterate over in bootstrap calculations Example ------- The key steps are problem dependent and so this example shows the use as an iterator that does not produce any output >>> from arch.bootstrap import IIDBootstrap >>> import numpy as np >>> bs = IIDBootstrap(np.arange(100), x=np.random.randn(100)) >>> for posdata, kwdata in bs.bootstrap(1000): ... # Do something with the positional data and/or keyword data ... pass .. note:: Note this is a generic example and so the class used should be the name of the required bootstrap Notes ----- The iterator returns a tuple containing the data entered in positional arguments as a tuple and the data entered using keywords as a dictionary """ for _ in range(reps): self._index = self.update_indices() yield self._resample()