Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: Allow in- and out-of-sample parameters to be set #388

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Forecasting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
1. Compute the 1-step ahead forecast in sample
2. If parameters are not common, then
1. Update the 1-step ahead forecast out-of-sample.
3.
55 changes: 41 additions & 14 deletions arch/univariate/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -712,9 +712,9 @@ def compute_param_cov(self, params, backcast=None, robust=True):

@abstractmethod
def forecast(self, params, horizon=1, start=None, align='origin', method='analytic',
simulations=1000, rng=None):
simulations=1000, rng=None, insample_params=None):
"""
Construct forecasts from estimated model
Construct forecasts from a model

Parameters
----------
Expand Down Expand Up @@ -749,6 +749,11 @@ def forecast(self, params, horizon=1, start=None, align='origin', method='analyt
Custom random number generator to use in simulation-based forecasts.
Must produce random samples using the syntax `rng(size)` where size
the 2-element tuple (simulations, horizon).
insample_params : {ndarray, Series}, optional
Parameters to use when computing in-sample residuals. If not
provided, insample_params is set to params. Setting this input
allows for alternative parameters to be used to produce forecasts
while keeping the in-sample parameters fixed.

Returns
-------
Expand All @@ -765,7 +770,7 @@ def forecast(self, params, horizon=1, start=None, align='origin', method='analyt
>>> sim_data.index = pd.date_range('2000-01-01',periods=250)
>>> am = arch_model(sim_data['data'],mean='HAR',lags=[1,5,22], vol='Constant')
>>> res = am.fit()
>>> fig = res.hedgehog_plot()
>>> forecasts = res.forecast(horizon=5)

Notes
-----
Expand Down Expand Up @@ -1114,13 +1119,13 @@ def _set_tight_x(axis, index):
return fig

def forecast(self, params=None, horizon=1, start=None, align='origin', method='analytic',
simulations=1000, rng=None):
simulations=1000, rng=None, insample_params=None):
"""
Construct forecasts from estimated model
Construct forecasts from a model

Parameters
----------
params : ndarray, optional
params : {ndarray, Series}, optional
Alternative parameters to use. If not provided, the parameters
estimated when fitting the model are used. Must be identical in
shape to the parameters computed by fitting the model.
Expand Down Expand Up @@ -1151,6 +1156,11 @@ def forecast(self, params=None, horizon=1, start=None, align='origin', method='a
Custom random number generator to use in simulation-based forecasts.
Must produce random samples using the syntax `rng(size)` where size
the 2-element tuple (simulations, horizon).
insample_params : {ndarray, Series}, optional
Parameters to use when computing in-sample residuals. If not
provided, insample_params is set to params. Setting this input
allows for alternative parameters to be used to produce forecasts
while keeping the in-sample parameters fixed.

Returns
-------
Expand Down Expand Up @@ -1182,19 +1192,25 @@ def forecast(self, params=None, horizon=1, start=None, align='origin', method='a
if params is None:
params = self._params
else:
if (params.size != np.array(self._params).size or
if (params.size != np.asarray(self._params).size or
params.ndim != self._params.ndim):
raise ValueError('params have incorrect dimensions')
return self.model.forecast(params, horizon, start, align, method, simulations, rng)
if insample_params is not None:
if (insample_params.size != np.asarray(params).size or
insample_params.ndim != params.ndim):
raise ValueError('model_params have incorrect dimensions')

def hedgehog_plot(self, params=None, horizon=10, step=10, start=None,
type='volatility', method='analytic', simulations=1000):
return self.model.forecast(params, horizon, start, align, method, simulations, rng,
insample_params)

def hedgehog_plot(self, params=None, horizon=10, step=10, start=None, type='volatility',
method='analytic', simulations=1000, rng=None, insample_params=None):
"""
Plot forecasts from estimated model

Parameters
----------
params : {ndarray, Series}
params : {ndarray, Series}, optional
Alternative parameters to use. If not provided, the parameters
computed by fitting the model are used. Must be 1-d and identical
in shape to the parameters computed by fitting the model.
Expand All @@ -1219,6 +1235,15 @@ def hedgehog_plot(self, params=None, horizon=10, step=10, start=None,
simulations : int
Number of simulations to run when computing the forecast using
either simulation or bootstrap.
rng : callable, optional
Custom random number generator to use in simulation-based forecasts.
Must produce random samples using the syntax `rng(size)` where size
the 2-element tuple (simulations, horizon).
insample_params : {ndarray, Series}, optional
Parameters to use when computing in-sample residuals. If not
provided, insample_params is set to params. Setting this input
allows for alternative parameters to be used to produce forecasts
while keeping the in-sample parameters fixed.

Returns
-------
Expand All @@ -1244,14 +1269,16 @@ def hedgehog_plot(self, params=None, horizon=10, step=10, start=None,
start = 0
while invalid_start:
try:
forecasts = self.forecast(params, horizon, start,
method=method, simulations=simulations)
forecasts = self.forecast(params, horizon, start, method=method,
simulations=simulations, rng=rng,
insample_params=insample_params)
invalid_start = False
except ValueError:
start += 1
else:
forecasts = self.forecast(params, horizon, start, method=method,
simulations=simulations)
simulations=simulations, rng=rng,
insample_params=insample_params)

fig, ax = plt.subplots(1, 1)
use_date = isinstance(self._dep_var.index, pd.DatetimeIndex)
Expand Down
14 changes: 9 additions & 5 deletions arch/univariate/mean.py
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,7 @@ def _fit_no_arch_normal_errors(self, cov_type='robust'):
copy.deepcopy(self))

def forecast(self, params, horizon=1, start=None, align='origin',
method='analytic', simulations=1000, rng=None):
method='analytic', simulations=1000, rng=None, insample_params=None):
# Check start
earliest, default_start = self._fit_indices
default_start = max(0, default_start - 1)
Expand All @@ -623,22 +623,26 @@ def forecast(self, params, horizon=1, start=None, align='origin',
# Parse params
params = np.asarray(params)
mp, vp, dp = self._parse_parameters(params)

insample_mp, insample_vp, insample_db = mp, vp, dp
if insample_params is not None:
insample_mp, insample_vp, insample_db = self._parse_parameters(insample_params)
#####################################
# Compute residual variance forecasts
#####################################
# Back cast should use only the sample used in fitting
resids = self.resids(mp)
resids = self.resids(insample_mp)
backcast = self._volatility.backcast(resids)
full_resids = self.resids(mp, self._y[earliest:], self.regressors[earliest:])
full_resids = self.resids(insample_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)
# TODO: Adapt for in-sample parameters
vfcast = self._volatility.forecast(vp, full_resids, backcast, vb,
start=variance_start,
horizon=horizon, method=method,
simulations=simulations, rng=rng)
simulations=simulations, rng=rng,
insample_params=insample_vp)
var_fcasts = vfcast.forecasts
var_fcasts = _forecast_pad(earliest, var_fcasts)

Expand Down
Loading