bashtage / arch

ARCH models in Python
Other
1.32k stars 245 forks source link

Probably bug in FIGARCH implementation with horizon > 1 #670

Closed and15121512 closed 1 year ago

and15121512 commented 1 year ago

I use arch 6.1.0, Python 3.10.6, Ubuntu 22.04.

To reproduce:

  1. Loading some data
    
    import datetime as dt
    import pandas_datareader.data as web
    from arch import arch_model
    import yfinance as yfin
    yfin.pdr_override()

start = dt.datetime(2000, 1, 1).strftime('%Y-%m-%d') end = dt.datetime(2014, 1, 1).strftime('%Y-%m-%d') sp500 = web.DataReader('^GSPC', start, end) returns = 100 * sp500['Adj Close'].pct_change().dropna()

2. The model with horizon=**1** runs OK.

garch = arch_model(returns, vol='figarch', p=1, o=0, q=1, dist='normal').fit(disp='off')

pred = garch.forecast(horizon=1) print(pred.variance)

            h.1

Date
2000-01-04 NaN 2000-01-05 NaN 2000-01-06 NaN 2000-01-07 NaN 2000-01-10 NaN ... ... 2013-12-24 NaN 2013-12-26 NaN 2013-12-27 NaN 2013-12-30 NaN 2013-12-31 0.378491

[3520 rows x 1 columns]

3. The model with horizon=**2** fails.

garch = arch_model(returns, vol='figarch', p=1, o=0, q=1, dist='normal').fit(disp='off')

pred = garch.forecast(horizon=2) print(pred.variance)

Full traceback:

IndexError Traceback (most recent call last) Cell In[24], line 3 1 garch = arch_model(returns, vol='figarch', p=1, o=0, q=1, dist='normal').fit(disp='off') ----> 3 pred = garch.forecast(horizon=2) 4 pred.variance

File ~/AndProjects/Least_Corr_Assets/venv/lib/python3.10/site-packages/arch/univariate/base.py:1516, in ARCHModelFixedResult.forecast(self, params, horizon, start, align, method, simulations, rng, random_state, reindex, x) 1514 if not isinstance(horizon, (int, np.integer)) or horizon < 1: 1515 raise ValueError("horizon must be an integer >= 1.") -> 1516 return self.model.forecast( 1517 params, 1518 horizon, 1519 start, 1520 align, 1521 method, 1522 simulations, 1523 rng, 1524 random_state, 1525 reindex=reindex, 1526 x=x, 1527 )

File ~/AndProjects/Least_Corr_Assets/venv/lib/python3.10/site-packages/arch/univariate/mean.py:981, in HARX.forecast(self, params, horizon, start, align, method, simulations, rng, random_state, reindex, x) 979 rng = self._distribution.simulate(dp) 980 variance_start = max(0, start_index - earliest) --> 981 vfcast = self._volatility.forecast( 982 vp, 983 full_resids, 984 backcast, 985 vb, 986 start=variance_start, 987 horizon=horizon, 988 method=method, 989 simulations=simulations, 990 rng=rng, 991 random_state=random_state, 992 ) 993 var_fcasts = vfcast.forecasts 994 assert var_fcasts is not None

File ~/AndProjects/Least_Corr_Assets/venv/lib/python3.10/site-packages/arch/univariate/volatility.py:733, in VolatilityProcess.forecast(self, parameters, resids, backcast, var_bounds, start, horizon, method, simulations, rng, random_state) 731 start = len(resids) - 1 if start is None else start 732 if method_name == "analytic": --> 733 return self._analytic_forecast( 734 parameters, resids, backcast, var_bounds, start, horizon 735 ) 736 elif method == "simulation": 737 # TODO: This looks like a design flaw.It is optional above but then must 738 # be present. This happens because the caller of this function is 739 # expected to know when to provide the rng or not 740 assert rng is not None

File ~/AndProjects/Least_Corr_Assets/venv/lib/python3.10/site-packages/arch/univariate/volatility.py:3249, in FIGARCH._analytic_forecast(self, parameters, resids, backcast, var_bounds, start, horizon) 3245 lagged_forecasts = temp_forecasts[h : truncation + h] 3246 temp_forecasts[truncation + h] = omega_tilde + lam_rev.dot( 3247 lagged_forecasts 3248 ) -> 3249 forecasts[i, :] = temp_forecasts[truncation:] 3251 forecasts[:start] = np.nan 3252 return VarianceForecast(forecasts)

IndexError: index 3519 is out of bounds for axis 0 with size 1



**Possible reason**

There are problems with iteration indices within this function:
https://github.com/bashtage/arch/blob/72fbca484795163de2097c00bab835bf4d03598c/arch/univariate/volatility.py#L3212

The variable *forecasts* is defined by a function call:
https://github.com/bashtage/arch/blob/72fbca484795163de2097c00bab835bf4d03598c/arch/univariate/volatility.py#L3221

It's shape is:
https://github.com/bashtage/arch/blob/72fbca484795163de2097c00bab835bf4d03598c/arch/univariate/volatility.py#L352

But iteration bounds are:
https://github.com/bashtage/arch/blob/72fbca484795163de2097c00bab835bf4d03598c/arch/univariate/volatility.py#L3237

So it fails here:
https://github.com/bashtage/arch/blob/72fbca484795163de2097c00bab835bf4d03598c/arch/univariate/volatility.py#L3249

It seems that replacing iteration bounds may fix the problem. But the code logic is quite complex, so I cannot provide correct solution for now.

Could you fix it, please?
bashtage commented 1 year ago

Thanks for reporting. Should be fixed in #673