Beispiel #1
0
    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,
        )
Beispiel #2
0
    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)