Skip to content

Commit

Permalink
Merge pull request #673 from bashtage/bug-figarch-forecast
Browse files Browse the repository at this point in the history
BUG: Correct multistep forecasting for FIGARCH
  • Loading branch information
bashtage authored Jul 12, 2023
2 parents 6bf7e77 + 647dea2 commit 98a2bfa
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 2 deletions.
51 changes: 51 additions & 0 deletions arch/tests/univariate/test_forecast.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,27 @@
EGARCH(),
]

ANALYTICAL_VOLATILITIES = [
ConstantVariance(),
GARCH(),
FIGARCH(),
EWMAVariance(lam=0.94),
MIDASHyperbolic(),
HARCH(lags=[1, 5, 22]),
RiskMetrics2006(),
]


MODEL_SPECS = list(product(MEAN_MODELS, VOLATILITIES))
ANALYTICAL_MODEL_SPECS = list(product(MEAN_MODELS, ANALYTICAL_VOLATILITIES))

IDS = [
f"{str(mean).split('(')[0]}-{str(vol).split('(')[0]}" for mean, vol in MODEL_SPECS
]
ANALYTICAL_IDS = [
f"{str(mean).split('(')[0]}-{str(vol).split('(')[0]}"
for mean, vol in ANALYTICAL_MODEL_SPECS
]


@pytest.fixture(params=MODEL_SPECS, ids=IDS)
Expand All @@ -63,6 +79,13 @@ def model_spec(request):
return mean


@pytest.fixture(params=ANALYTICAL_MODEL_SPECS, ids=ANALYTICAL_IDS)
def analytical_model_spec(request):
mean, vol = request.param
mean.volatility = vol
return mean


class TestForecasting:
@classmethod
def setup_class(cls):
Expand Down Expand Up @@ -1053,3 +1076,31 @@ def test_rescale_ar():
fcasts = res.forecast(horizon=100).variance
fcasts_no_rs = res_no_rs.forecast(horizon=100).variance
assert_allclose(fcasts.iloc[0, -10:], fcasts_no_rs.iloc[0, -10:], rtol=1e-5)


def test_figarch_multistep():
# GH 670
mod = ConstantMean(SP500, volatility=FIGARCH())
res = mod.fit(disp="off")
fcasts = res.forecast(horizon=10)
rv = fcasts.residual_variance
assert np.all(np.isfinite(rv))
assert rv.shape == (1, 10)
fcasts_ri = res.forecast(horizon=10, reindex=True)
rv_ri = fcasts_ri.residual_variance
assert_frame_equal(rv, rv_ri.iloc[-1:])
assert rv_ri.shape == (SP500.shape[0], 10)


def test_multistep(analytical_model_spec):
# GH 670
# Ensure all work as expected
res = analytical_model_spec.fit(disp="off")
fcasts = res.forecast(horizon=10)
rv = fcasts.residual_variance
assert np.all(np.isfinite(rv))
assert rv.shape == (1, 10)
fcasts_ri = res.forecast(horizon=10, reindex=True)
rv_ri = fcasts_ri.residual_variance
assert_frame_equal(rv, rv_ri.iloc[-1:])
assert rv_ri.shape == (SP500.shape[0], 10)
4 changes: 2 additions & 2 deletions arch/univariate/volatility.py
Original file line number Diff line number Diff line change
Expand Up @@ -3235,6 +3235,7 @@ def _analytic_forecast(
temp_forecasts = np.empty(truncation + horizon)
resids2 = resids**2
for i in range(start, t):
fcast_loc = i - start
available = i + 1 - max(0, i - truncation + 1)
temp_forecasts[truncation - available : truncation] = resids2[
max(0, i - truncation + 1) : i + 1
Expand All @@ -3246,9 +3247,8 @@ def _analytic_forecast(
temp_forecasts[truncation + h] = omega_tilde + lam_rev.dot(
lagged_forecasts
)
forecasts[i, :] = temp_forecasts[truncation:]
forecasts[fcast_loc, :] = temp_forecasts[truncation:]

forecasts[:start] = np.nan
return VarianceForecast(forecasts)

def _simulation_forecast(
Expand Down

0 comments on commit 98a2bfa

Please sign in to comment.