Skip to content

Commit

Permalink
ENH: Let hold_back and last_obs work with dates
Browse files Browse the repository at this point in the history
Provide functionality so that these can accpet wither int or dates
Add testing for first_obs and last_obs
Improve appearance of plot
  • Loading branch information
bashtage committed Sep 4, 2014
1 parent 5a74b3a commit d1a8555
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 61 deletions.
1 change: 1 addition & 0 deletions arch/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,7 @@ def plot(self, annualize=None, scale=None):
ax = fig.add_subplot(2, 1, 1)
ax.plot(self._index, self.resid / self.conditional_volatility)
ax.set_title('Standardized Residuals')
ax.axes.xaxis.set_ticklabels([])

ax = fig.add_subplot(2, 1, 2)
vol = self.conditional_volatility
Expand Down
4 changes: 3 additions & 1 deletion arch/mean.py
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,9 @@ def _fit_no_arch_normal_errors(self, cov_type='robust'):
resids = np.empty_like(self._y, dtype=np.float64)
resids.fill(np.nan)
resids[first_obs:last_obs] = e
vol = np.zeros_like(resids) * np.sqrt(sigma2)
vol = np.zeros_like(resids)
vol.fill(np.nan)
vol[first_obs:last_obs] = np.sqrt(sigma2)
names = self._all_parameter_names()
loglikelihood = self._static_gaussian_loglikelihood(e)

Expand Down
65 changes: 64 additions & 1 deletion arch/tests/test_mean.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,10 +255,20 @@ def test_ar(self):
ar.__repr__()
ar = ARX(self.y_series, lags=5)
ar.__repr__()
res = ar.fit()
assert_true(isinstance(res.resid, pd.Series))
assert_true(isinstance(res.conditional_volatility, pd.Series))
# Smoke tests
summ = ar.fit().summary()
ar = ARX(self.y, lags=1, volatility=GARCH(), distribution=StudentsT())
res = ar.fit(iter=5)
res = ar.fit(iter=5, cov_type='mle')
res.param_cov
res.plot()
res.plot(annualize='D')
res.plot(annualize='W')
res.plot(annualize='M')
res.plot(scale=360)



def test_arch_model(self):
Expand Down Expand Up @@ -307,6 +317,10 @@ def test_arch_model(self):
am = arch_model(self.y, vol='arch')
assert_true(isinstance(am.volatility, ARCH))

am = arch_model(self.y, vol='egarch')
assert_true(isinstance(am.volatility, EGARCH))


assert_raises(ValueError, arch_model, self.y, mean='unknown')
assert_raises(ValueError, arch_model, self.y, vol='unknown')
assert_raises(ValueError, arch_model, self.y, dist='unknown')
Expand Down Expand Up @@ -445,3 +459,52 @@ def test_multiple_lags(self):
cm.volatility = process(p=p, o=o, q=q)
cm.fit(iter=0, disp='off')

def test_first_last_obs(self):
ar = ARX(self.y,lags=5, hold_back=100)
res = ar.fit(iter=0)
resids = res.resid
resid_copy = resids.copy()
resid_copy[:100] = np.nan
assert_equal(resids, resid_copy)

ar.volatility = GARCH()
res = ar.fit(iter=0)
resids = res.resid
resid_copy = resids.copy()
resid_copy[:100] = np.nan
assert_equal(resids, resid_copy)

ar = ARX(self.y,lags=5, last_obs=500)
ar.volatility = GARCH()
res = ar.fit(iter=0)
resids = res.resid
resid_copy = resids.copy()
resid_copy[500:] = np.nan
assert_equal(resids, resid_copy)

ar = ARX(self.y,lags=5, hold_back=100, last_obs=500)
ar.volatility = GARCH()
res = ar.fit(iter=0)
resids = res.resid
resid_copy = resids.copy()
resid_copy[:100] = np.nan
resid_copy[500:] = np.nan
assert_equal(resids, resid_copy)

vol = res.conditional_volatility
vol_copy = vol.copy()
vol_copy[:100] = np.nan
vol_copy[500:] = np.nan
assert_equal(vol, vol_copy)
assert_equal(self.y.shape[0], vol.shape[0])


ar = ARX(self.y,lags=5, last_obs=500)
ar.volatility = GARCH()
res = ar.fit(iter=0)
resids = res.resid
resid_copy = resids.copy()
resid_copy[:5] = np.nan
resid_copy[500:] = np.nan
assert_equal(resids, resid_copy)

15 changes: 13 additions & 2 deletions arch/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@

from numpy.testing import assert_equal, assert_raises
import numpy as np
from pandas import Series, DataFrame
from pandas import Series, DataFrame, date_range

from arch.utils import ensure1d, parse_dataframe, DocStringInheritor
from arch.utils import ensure1d, parse_dataframe, DocStringInheritor, \
date_to_index
from arch.base import implicit_constant
from arch.compat.python import add_metaclass, range

Expand Down Expand Up @@ -86,6 +87,16 @@ class B(A):
"""
assert_equal(B.__doc__,ds)

def test_date_to_index(self):
dr = date_range('20000101',periods=3000, freq='W')
y = Series(np.arange(3000.0), index=dr)
date_index = y.index
import datetime as dt
#TODO: Finish Test
# date_to_index(dt.datetime(2001, 3, 3), date_index)






Expand Down
54 changes: 54 additions & 0 deletions arch/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,57 @@ def __new__(meta, name, bases, clsdict):
attribute.__doc__=doc
break
return type.__new__(meta, name, bases, clsdict)

def date_to_index(date, date_index, method='first'):
"""
Looks up a
Parameters
----------
date : datetime or datetime64
date_index : 1-d array of datetime64
method : str, optional
Method to use. Choices are 'first', 'last', 'exact' First will return
the index where date_index >= date. Last will return the index where
date_index <= date. Exact will find the first instance where
date_index == date.
"""
import datetime as dt
import pandas as pd
from pandas.core.common import is_datetime64_dtype

if not is_datetime64_dtype(date_index):
raise ValueError('date_index must be a datetime64 array')
if not isinstance(date, (dt.datetime, np.datetime64, str)):
raise ValueError("date must be a datetime, datetime64 or string")
elif isinstance(date, dt.datetime):
date = np.datetime64(date)
elif isinstance(date, str):
orig_date = date
date = pd.to_datetime(date, coerce=True)
if date == pd.NaT:
raise ValueError('date:' + orig_date +
' cannot be parsed to a date.')

date_index = np.asarray(date_index)

if method == 'first':
locs = np.nonzero(date_index >= date)[0]
if locs.shape[0] == 0:
raise ValueError('All dates in date_index occur before date')
else:
return locs.min()
elif method == 'last':
locs = np.nonzero(date_index <= date)[0]
if locs.shape[0] == 0:
raise ValueError('All dates in date_index occur after date')
else:
return locs.max()
elif method == 'exact':
locs = np.nonzero(date_index == date)[0]
if locs.shape[0] == 0:
raise ValueError('date not in date_index')
else:
return locs.max()
else:
raise ValueError('method is unknown')
20 changes: 11 additions & 9 deletions doc/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,6 @@ as
An complete ARCH model is divided into three components:

.. toctree::
:maxdepth: 1

Examples <examples>
Mean Models <mean>
Volatility Processes <volatility>
Distributions <distribution>

..
.. Theoretical Background <background>
Expand All @@ -45,10 +38,10 @@ blocks of an ARCH model

from arch.mean import ConstantMean
from arch.volatiltiy import GARCH
from arch.distribution impot StudentsT
from arch.distribution import Normal
am = ConstantMean(returns)
am.volatility = GARCH(1,0,1)
am.distribution = StudentsT()
am.distribution = Normal()

In either case, model parameters are estimated using

Expand All @@ -57,6 +50,15 @@ In either case, model parameters are estimated using
res = am.fit()


.. toctree::
:maxdepth: 1

Examples <examples>
Mean Models <mean>
Volatility Processes <volatility>
Distributions <distribution>


Model Constructor
-----------------
While models can be carefully specified using the individual components, most common specifications can be specified
Expand Down
76 changes: 28 additions & 48 deletions examples/examples.ipynb

Large diffs are not rendered by default.

0 comments on commit d1a8555

Please sign in to comment.