def _adjust_sample(self, first_obs, last_obs): index = self._y_series.index _first_obs_index = cutoff_to_index(first_obs, index, 0) _first_obs_index += self._hold_back _last_obs_index = cutoff_to_index(last_obs, index, self._y.shape[0]) if _last_obs_index <= _first_obs_index: raise ValueError('first_obs and last_obs produce in an ' 'empty array.') self._fit_indices = [_first_obs_index, _last_obs_index] self._fit_y = self._y[_first_obs_index:_last_obs_index] reg = self.regressors self._fit_regressors = reg[_first_obs_index:_last_obs_index] self.volatility.start, self.volatility.stop = self._fit_indices
def _adjust_sample( self, first_obs: Optional[Union[int, DateLike]], last_obs: Optional[Union[int, DateLike]], ) -> None: index = self._y_series.index _first_obs_index = cutoff_to_index(first_obs, index, 0) _first_obs_index += self._hold_back _last_obs_index = cutoff_to_index(last_obs, index, self._y.shape[0]) if _last_obs_index <= _first_obs_index: raise ValueError("first_obs and last_obs produce in an empty array.") self._fit_indices = [_first_obs_index, _last_obs_index] self._fit_y = self._y[_first_obs_index:_last_obs_index] reg = self.regressors self._fit_regressors = reg[_first_obs_index:_last_obs_index] self.volatility.start, self.volatility.stop = self._fit_indices
def test_cutoff_to_index(self): dr = date_range('20000101', periods=3000, freq='W') y = Series(np.arange(3000.0), index=dr) date_index = y.index assert cutoff_to_index(1000, date_index, 0) == 1000 assert cutoff_to_index(int(1000), date_index, 0) == 1000 assert cutoff_to_index(np.int16(1000), date_index, 0) == 1000 assert cutoff_to_index(np.int64(1000), date_index, 0) == 1000 assert cutoff_to_index(date_index[1000], date_index, 0) == 1000 assert cutoff_to_index(None, date_index, 1000) == 1000
def test_cutoff_to_index(self): dr = date_range('20000101', periods=3000, freq='W') y = Series(np.arange(3000.0), index=dr) date_index = y.index assert cutoff_to_index(1000, date_index, 0) == 1000 assert cutoff_to_index(long(1000), date_index, 0) == 1000 assert cutoff_to_index(np.int16(1000), date_index, 0) == 1000 assert cutoff_to_index(np.int64(1000), date_index, 0) == 1000 assert cutoff_to_index(date_index[1000], date_index, 0) == 1000 assert cutoff_to_index(None, date_index, 1000) == 1000
def forecast( self, params: ArrayLike1D, horizon: int = 1, start: Optional[Union[int, DateLike]] = None, align: str = "origin", method: str = "analytic", simulations: int = 1000, rng: Optional[Callable[[Union[int, Tuple[int, ...]]], NDArray]] = None, random_state: Optional[np.random.RandomState] = None, ) -> ARCHModelForecast: # Check start earliest, default_start = self._fit_indices default_start = max(0, default_start - 1) start_index = cutoff_to_index(start, self._y_series.index, default_start) if start_index < (earliest - 1): raise ValueError( "Due to backcasting and/or data availability start cannot be less " "than the index of the largest value in the right-hand-side " "variables used to fit the first observation. In this model, " "this value is {0}.".format(max(0, earliest - 1))) # Parse params params = np.asarray(params) mp, vp, dp = self._parse_parameters(params) ##################################### # Compute residual variance forecasts ##################################### # Back cast should use only the sample used in fitting resids = self.resids(mp) backcast = self._volatility.backcast(resids) full_resids = self.resids(mp, self._y[earliest:], self.regressors[earliest:]) vb = self._volatility.variance_bounds(full_resids, 2.0) if rng is None: rng = self._distribution.simulate(dp) variance_start = max(0, start_index - earliest) vfcast = self._volatility.forecast( vp, full_resids, backcast, vb, start=variance_start, horizon=horizon, method=method, simulations=simulations, rng=rng, random_state=random_state, ) var_fcasts = vfcast.forecasts var_fcasts = _forecast_pad(earliest, var_fcasts) arp = self._har_to_ar(mp) nexog = 0 if self._x is None else self._x.shape[1] exog_p = np.empty([]) if self._x is None else mp[-nexog:] constant = arp[0] if self.constant else 0.0 dynp = arp[int(self.constant):] mean_fcast = _ar_forecast(self._y, horizon, start_index, constant, dynp, exog_p, self._x) # Compute total variance forecasts, which depend on model impulse = _ar_to_impulse(horizon, dynp) longrun_var_fcasts = var_fcasts.copy() for i in range(horizon): lrf = var_fcasts[:, :(i + 1)].dot(impulse[i::-1]**2) longrun_var_fcasts[:, i] = lrf if method.lower() in ("simulation", "bootstrap"): # TODO: This is not tested, but probably right variance_paths = _forecast_pad(earliest, vfcast.forecast_paths) long_run_variance_paths = variance_paths.copy() shocks = _forecast_pad(earliest, vfcast.shocks) for i in range(horizon): _impulses = impulse[i::-1][:, None] lrvp = variance_paths[start_index:, :, :(i + 1)].dot( _impulses**2) long_run_variance_paths[start_index:, :, i] = np.squeeze(lrvp) t, m = self._y.shape[0], self._max_lags mean_paths = np.full((t, simulations, m + horizon), np.nan) dynp_rev = dynp[::-1] for i in range(start_index, t): mean_paths[i, :, :m] = self._y[i - m + 1:i + 1] for j in range(horizon): mean_paths[i, :, m + j] = (constant + mean_paths[i, :, j:m + j].dot(dynp_rev) + shocks[i, :, j]) mean_paths = mean_paths[:, :, m:] else: variance_paths = mean_paths = shocks = long_run_variance_paths = None index = self._y_series.index return ARCHModelForecast( index, mean_fcast, longrun_var_fcasts, var_fcasts, align=align, simulated_paths=mean_paths, simulated_residuals=shocks, simulated_variances=long_run_variance_paths, simulated_residual_variances=variance_paths, )
def forecast(self, parameters, horizon=1, start=None, align='origin', method='analytic', simulations=1000): # Check start earliest, default_start = self._fit_indices default_start = max(0, default_start - 1) start_index = cutoff_to_index(start, self._y_series.index, default_start) if start_index < (earliest - 1): raise ValueError( 'Due ot backcasting and/or data availability start cannot be less ' 'than the index of the largest value in the right-hand-side ' 'variables used to fit the first observation. In this model, ' 'this value is {0}.'.format(max(0, earliest - 1))) # Parse params parameters = np.asarray(parameters) mp, vp, dp = self._parse_parameters(parameters) ##################################### # Compute residual variance forecasts ##################################### # Back cast should use only the sample used in fitting resids = self.resids(mp) backcast = self._volatility.backcast(resids) full_resids = self.resids(mp, self._y[earliest:], self.regressors[earliest:]) vb = self._volatility.variance_bounds(full_resids, 2.0) rng = self._distribution.simulate(dp) variance_start = max(0, start_index - earliest) vfcast = self._volatility.forecast(vp, full_resids, backcast, vb, start=variance_start, horizon=horizon, method=method, simulations=simulations, rng=rng) var_fcasts = vfcast.forecasts var_fcasts = _forecast_pad(earliest, var_fcasts) arp = self._har_to_ar(mp) nexog = 0 if self._x is None else self._x.shape[1] exog_p = np.empty([]) if self._x is None else mp[-nexog:] constant = arp[0] if self.constant else 0.0 dynp = arp[int(self.constant):] mean_fcast = _ar_forecast(self._y, horizon, start_index, constant, dynp, exog_p, self._x) # Compute total variance forecasts, which depend on model impulse = _ar_to_impulse(horizon, dynp) longrun_var_fcasts = var_fcasts.copy() for i in range(horizon): lrf = var_fcasts[:, :(i + 1)].dot(impulse[i::-1]**2) longrun_var_fcasts[:, i] = lrf if method.lower() in ('simulation', 'bootstrap'): # TODO: This is not tested, and probably wrong variance_paths = _forecast_pad(earliest, vfcast.forecast_paths) long_run_variance_paths = variance_paths.copy() shocks = _forecast_pad(earliest, vfcast.shocks) for i in range(horizon): _impulses = impulse[i::-1][:, None] lrvp = variance_paths[:, :, :(i + 1)].dot(_impulses**2) long_run_variance_paths[:, :, i] = np.squeeze(lrvp) t, m = self._y.shape[0], self._max_lags mean_paths = np.empty((t, simulations, m + horizon)) mean_paths.fill(np.nan) dynp_rev = dynp[::-1] for i in range(start_index, t): mean_paths[i, :, :m] = self._y[i - m + 1:i + 1] for j in range(horizon): mean_paths[i, :, m + j] = constant + \ mean_paths[i, :, j:m + j].dot(dynp_rev) + \ shocks[i, :, j] mean_paths = mean_paths[:, :, m:] else: variance_paths = mean_paths = shocks = long_run_variance_paths = None index = self._y_series.index return ARCHModelForecast(index, mean_fcast, longrun_var_fcasts, var_fcasts, align=align, simulated_paths=mean_paths, simulated_residuals=shocks, simulated_variances=long_run_variance_paths, simulated_residual_variances=variance_paths)
def forecast(self, parameters, horizon=1, start=None, align='origin', method='analytic', simulations=1000): if self._x is not None: raise RuntimeError('Forecasts are not available when the model ' 'contains exogenous regressors.') # Check start earliest, default_start = self._fit_indices default_start = max(0, default_start - 1) start_index = cutoff_to_index(start, self._y_series.index, default_start) if start_index < (earliest - 1): raise ValueError('Due ot backcasting and/or data availability start cannot be less ' 'than the index of the largest value in the right-hand-side ' 'variables used to fit the first observation. In this model, ' 'this value is {0}.'.format(max(0, earliest - 1))) # Parse params parameters = np.asarray(parameters) mp, vp, dp = self._parse_parameters(parameters) ##################################### # Compute residual variance forecasts ##################################### # Backcast should use only the sample used in fitting resids = self.resids(mp) backcast = self._volatility.backcast(resids) full_resids = self.resids(mp, self._y[earliest:], self.regressors[earliest:]) vb = self._volatility.variance_bounds(full_resids, 2.0) rng = self._distribution.simulate(dp) variance_start = max(0, start_index - earliest) vfcast = self._volatility.forecast(vp, full_resids, backcast, vb, start=variance_start, horizon=horizon, method=method, simulations=simulations, rng=rng) var_fcasts = vfcast.forecasts var_fcasts = _forecast_pad(earliest, var_fcasts) arp = self._har_to_ar(mp) constant = arp[0] if self.constant else 0.0 dynp = arp[int(self.constant):] mean_fcast = _ar_forecast(self._y, horizon, start_index, constant, dynp) # Compute total variance forecasts, which depend on model impulse = _ar_to_impulse(horizon, dynp) longrun_var_fcasts = var_fcasts.copy() for i in range(horizon): lrf = var_fcasts[:, :(i + 1)].dot(impulse[i::-1] ** 2) longrun_var_fcasts[:, i] = lrf if method.lower() in ('simulation', 'bootstrap'): # TODO: This is not tested, and probably wrong variance_paths = _forecast_pad(earliest, vfcast.forecast_paths) long_run_variance_paths = variance_paths.copy() shocks = _forecast_pad(earliest, vfcast.shocks) for i in range(horizon): _impulses = impulse[i::-1][:, None] lrvp = variance_paths[:, :, :(i + 1)].dot(_impulses ** 2) long_run_variance_paths[:, :, i] = np.squeeze(lrvp) t, m = self._y.shape[0], self._max_lags mean_paths = np.empty((t, simulations, m + horizon)) mean_paths.fill(np.nan) dynp_rev = dynp[::-1] for i in range(start_index, t): mean_paths[i, :, :m] = self._y[i - m + 1:i + 1] for j in range(horizon): mean_paths[i, :, m + j] = constant + \ mean_paths[i, :, j:m + j].dot(dynp_rev) + \ shocks[i, :, j] mean_paths = mean_paths[:, :, m:] else: variance_paths = mean_paths = shocks = long_run_variance_paths = None index = self._y_series.index return ARCHModelForecast(index, mean_fcast, longrun_var_fcasts, var_fcasts, align=align, simulated_paths=mean_paths, simulated_residuals=shocks, simulated_variances=long_run_variance_paths, simulated_residual_variances=variance_paths)