Repository: statsmodels/statsmodels

Issue:
BUG: ARMA model is not immutable
#### Describe the bug

`ARMA` mutaes on each call.  This leads to many problems, including

#### Code Sample, a copy-pastable example if possible


```python
import statsmodels.api as sm
import numpy as np
mod = sm.tsa.ARMA(np.random.randn(1000),(2,0))
mod.fit()
mod.fit()
...
ValueError: x contains a constant. Adding a constant with trend='c' is not allowed.
```
<details>

**Note**: As you can see, there are many issues on our GitHub tracker, so it is very possible that your issue has been posted before. Please check first before submitting so that we do not have to handle and close duplicates.

**Note**: Please be sure you are using the latest released version of `statsmodels`, or a recent build of `master`. If your problem has been fixed in an unreleased version, you might be able to use `master` until a new release occurs. 

**Note**: If you are using a released version, have you verified that the bug exists in the master branch of this repository? It helps the limited resources if we know problems exist in the current master so that they do not need to check whether the code sample produces a bug in the next release.

</details>


#### Expected Output

Never mutatute the model.  Will need a depreacation cycle, but worth it.

#### Output of ``import statsmodels.api as sm; sm.show_versions()``

<details>

INSTALLED VERSIONS
------------------
Python: 3.7.3.final.0

Statsmodels
===========

Installed: 0.10.0 (C:\Anaconda\lib\site-packages\statsmodels)

Required Dependencies
=====================

cython: 0.29.11 (C:\Anaconda\lib\site-packages\Cython)
numpy: 1.16.4 (C:\Anaconda\lib\site-packages\numpy)
scipy: 1.2.1 (C:\Anaconda\lib\site-packages\scipy)
pandas: 0.24.2 (C:\Anaconda\lib\site-packages\pandas)
    dateutil: 2.8.0 (C:\Anaconda\lib\site-packages\dateutil)
patsy: 0.5.1 (C:\Anaconda\lib\site-packages\patsy)

Optional Dependencies
=====================

matplotlib: 3.1.0 (C:\Anaconda\lib\site-packages\matplotlib)
    backend: module://ipykernel.pylab.backend_inline 
cvxopt: Not installed
joblib: 0.13.2 (C:\Anaconda\lib\site-packages\joblib)

Developer Tools
================

IPython: 7.6.1 (C:\Anaconda\lib\site-packages\IPython)
    jinja2: 2.10.1 (C:\Anaconda\lib\site-packages\jinja2)
sphinx: 2.1.2 (C:\Anaconda\lib\site-packages\sphinx)
    pygments: 2.4.2 (C:\Anaconda\lib\site-packages\pygments)
pytest: 5.0.0 (C:\Anaconda\lib\site-packages)
virtualenv: Not installed
</details>



Discussion:
> Never mutatute the model. Will need a depreacation cycle, but worth it.

Are you thinking of just patching ARMA to avoid attribute setting (which I'm +1 on regardless) or getting at the root of the problem with the constructor args/kwargs?
Both, short term patch, but start deprecation for API change

Resolving patch:
diff --git a/statsmodels/tools/validation/validation.py b/statsmodels/tools/validation/validation.py
--- a/statsmodels/tools/validation/validation.py
+++ b/statsmodels/tools/validation/validation.py
@@ -33,7 +33,7 @@ def _right_squeeze(arr, stop_dim=0):
 
 
 def array_like(obj, name, dtype=np.double, ndim=1, maxdim=None,
-               shape=None, order='C', contiguous=False):
+               shape=None, order='C', contiguous=False, optional=False):
     """
     Convert array-like to an array and check conditions
 
@@ -61,6 +61,8 @@ def array_like(obj, name, dtype=np.double, ndim=1, maxdim=None,
         Order of the array
     contiguous : bool
         Ensure that the array's data is contiguous with order ``order``
+    optional : bool
+        Flag indicating whether None is allowed
 
     Examples
     --------
@@ -112,6 +114,8 @@ def array_like(obj, name, dtype=np.double, ndim=1, maxdim=None,
      ...
     ValueError: x is required to have shape (*, 4, 4) but has shape (4, 10, 4)
     """
+    if optional and obj is None:
+        return None
     arr = np.asarray(obj, dtype=dtype, order=order)
     if maxdim is not None:
         if arr.ndim > maxdim:
diff --git a/statsmodels/tsa/ar_model.py b/statsmodels/tsa/ar_model.py
--- a/statsmodels/tsa/ar_model.py
+++ b/statsmodels/tsa/ar_model.py
@@ -1,36 +1,33 @@
 # -*- coding: utf-8 -*-
-from statsmodels.compat.python import iteritems, lmap
-
 import numpy as np
-from numpy import dot, identity
 from numpy.linalg import inv, slogdet
 from scipy.stats import norm
 
+import statsmodels.base.model as base
+import statsmodels.base.wrapper as wrap
 from statsmodels.iolib.summary import Summary
 from statsmodels.regression.linear_model import OLS
-from statsmodels.tsa.tsatools import (lagmat, add_trend,
-                                      _ar_transparams, _ar_invtransparams)
-import statsmodels.tsa.base.tsa_model as tsbase
-import statsmodels.base.model as base
 from statsmodels.tools.decorators import cache_readonly, cache_writable
 from statsmodels.tools.numdiff import approx_fprime, approx_hess
+from statsmodels.tools.validation import array_like
+from statsmodels.tsa.base import tsa_model
 from statsmodels.tsa.kalmanf.kalmanfilter import KalmanFilter
-import statsmodels.base.wrapper as wrap
+from statsmodels.tsa.tsatools import (lagmat, add_trend, _ar_transparams,
+                                      _ar_invtransparams)
 from statsmodels.tsa.vector_ar import util
 
-
 __all__ = ['AR']
 
+REPEATED_FIT_ERROR = """
+Model has been fit using maxlag={0}, method={1}, ic={2}, trend={3}. These
+cannot be changed in subsequent calls to `fit`. Instead, use a new instance of
+AR.
+"""
+
 
 def sumofsq(x, axis=0):
     """Helper function to calculate sum of squares along first axis"""
-    return np.sum(x**2, axis=axis)
-
-
-def _check_ar_start(start, k_ar, method, dynamic):
-    if (method == 'cmle' or dynamic) and start < k_ar:
-        raise ValueError("Start must be >= k_ar for conditional MLE "
-                         "or dynamic forecast. Got %d" % start)
+    return np.sum(x ** 2, axis=axis)
 
 
 def _ar_predict_out_of_sample(y, params, k_ar, k_trend, steps, start=0):
@@ -40,25 +37,25 @@ def _ar_predict_out_of_sample(y, params, k_ar, k_trend, steps, start=0):
     # dynamic endogenous variable
     endog = np.zeros(k_ar + steps)  # this is one too big but does not matter
     if start:
-        endog[:k_ar] = y[start-k_ar:start]
+        endog[:k_ar] = y[start - k_ar:start]
     else:
         endog[:k_ar] = y[-k_ar:]
 
     forecast = np.zeros(steps)
     for i in range(steps):
-        fcast = mu + np.dot(arparams, endog[i:i+k_ar])
+        fcast = mu + np.dot(arparams, endog[i:i + k_ar])
         forecast[i] = fcast
         endog[i + k_ar] = fcast
 
     return forecast
 
 
-class AR(tsbase.TimeSeriesModel):
-    __doc__ = tsbase._tsa_doc % {"model": "Autoregressive AR(p) model",
-                                 "params": """endog : array_like
+class AR(tsa_model.TimeSeriesModel):
+    __doc__ = tsa_model._tsa_doc % {"model": "Autoregressive AR(p) model",
+                                    "params": """endog : array_like
         1-d endogenous response variable. The independent variable.""",
-                                 "extra_params": base._missing_param_doc,
-                                 "extra_sections": ""}
+                                    "extra_params": base._missing_param_doc,
+                                    "extra_sections": ""}
 
     def __init__(self, endog, dates=None, freq=None, missing='none'):
         super(AR, self).__init__(endog, None, dates, freq, missing=missing)
@@ -68,6 +65,7 @@ def __init__(self, endog, dates=None, freq=None, missing='none'):
             self.endog = endog  # to get shapes right
         elif endog.ndim > 1 and endog.shape[1] != 1:
             raise ValueError("Only the univariate case is implemented")
+        self._fit_params = None
 
     def initialize(self):
         pass
@@ -83,7 +81,7 @@ def _transparams(self, params):
         p = self.k_ar
         k = self.k_trend
         newparams = params.copy()
-        newparams[k:k+p] = _ar_transparams(params[k:k+p].copy())
+        newparams[k:k + p] = _ar_transparams(params[k:k + p].copy())
         return newparams
 
     def _invtransparams(self, start_params):
@@ -93,7 +91,7 @@ def _invtransparams(self, start_params):
         p = self.k_ar
         k = self.k_trend
         newparams = start_params.copy()
-        newparams[k:k+p] = _ar_invtransparams(start_params[k:k+p].copy())
+        newparams[k:k + p] = _ar_invtransparams(start_params[k:k + p].copy())
         return newparams
 
     def _presample_fit(self, params, start, p, end, y, predictedvalues):
@@ -112,24 +110,23 @@ def _presample_fit(self, params, start, p, end, y, predictedvalues):
 
         # Initial State mean and variance
         alpha = np.zeros((p, 1))
-        Q_0 = dot(inv(identity(p**2)-np.kron(T_mat, T_mat)),
-                  dot(R_mat, R_mat.T).ravel('F'))
+        Q_0 = np.dot(inv(np.identity(p ** 2) - np.kron(T_mat, T_mat)),
+                     np.dot(R_mat, R_mat.T).ravel('F'))
 
         Q_0 = Q_0.reshape(p, p, order='F')  # TODO: order might need to be p+k
         P = Q_0
         Z_mat = KalmanFilter.Z(p)
         for i in range(end):  # iterate p-1 times to fit presample
-            v_mat = y[i] - dot(Z_mat, alpha)
-            F_mat = dot(dot(Z_mat, P), Z_mat.T)
-            Finv = 1./F_mat  # inv. always scalar
-            K = dot(dot(dot(T_mat, P), Z_mat.T), Finv)
+            v_mat = y[i] - np.dot(Z_mat, alpha)
+            F_mat = np.dot(np.dot(Z_mat, P), Z_mat.T)
+            Finv = 1. / F_mat  # inv. always scalar
+            K = np.dot(np.dot(np.dot(T_mat, P), Z_mat.T), Finv)
             # update state
-            alpha = dot(T_mat, alpha) + dot(K, v_mat)
-            L = T_mat - dot(K, Z_mat)
-            P = dot(dot(T_mat, P), L.T) + dot(R_mat, R_mat.T)
-            #P[0,0] += 1 # for MA part, R_mat.R_mat.T above
+            alpha = np.dot(T_mat, alpha) + np.dot(K, v_mat)
+            L = T_mat - np.dot(K, Z_mat)
+            P = np.dot(np.dot(T_mat, P), L.T) + np.dot(R_mat, R_mat.T)
             if i >= start - 1:  # only record if we ask for it
-                predictedvalues[i + 1 - start] = dot(Z_mat, alpha)
+                predictedvalues[i + 1 - start] = np.dot(Z_mat, alpha)
 
     def _get_prediction_index(self, start, end, dynamic, index=None):
         method = getattr(self, 'method', 'mle')
@@ -146,12 +143,10 @@ def _get_prediction_index(self, start, end, dynamic, index=None):
         start, end, out_of_sample, prediction_index = (
             super(AR, self)._get_prediction_index(start, end, index))
 
-        # This replaces the _validate() call
-        if 'mle' not in method and start < k_ar:
-            raise ValueError("Start must be >= k_ar for conditional MLE or "
-                             "dynamic forecast. Got %s" % start)
         # Other validation
-        _check_ar_start(start, k_ar, method, dynamic)
+        if (method == 'cmle' or dynamic) and start < k_ar:
+            raise ValueError("Start must be >= k_ar for conditional MLE "
+                             "or dynamic forecast. Got %d" % start)
 
         return start, end, out_of_sample, prediction_index
 
@@ -188,13 +183,12 @@ def predict(self, params, start=None, end=None, dynamic=False):
         values. The exact initial Kalman Filter is used. See Durbin and Koopman
         in the references for more information.
         """
+        if not (hasattr(self, 'k_ar') and hasattr(self, 'k_trend')):
+            raise RuntimeError('Model must be fit before calling predict')
         # will return an index of a date
         start, end, out_of_sample, _ = (
             self._get_prediction_index(start, end, dynamic))
 
-        if start - end > 1:
-            raise ValueError("end is before start")
-
         k_ar = self.k_ar
         k_trend = self.k_trend
         method = self.method
@@ -210,15 +204,15 @@ def predict(self, params, start=None, end=None, dynamic=False):
         # fit pre-sample
         if method == 'mle':  # use Kalman Filter to get initial values
             if k_trend:
-                mu = params[0]/(1-np.sum(params[k_trend:]))
+                mu = params[0] / (1 - np.sum(params[k_trend:]))
             else:
                 mu = 0
 
             # modifies predictedvalues in place
             if start < k_ar:
-                self._presample_fit(params, start, k_ar, min(k_ar-1, end),
+                self._presample_fit(params, start, k_ar, min(k_ar - 1, end),
                                     endog[:k_ar] - mu, predictedvalues)
-                predictedvalues[:k_ar-start] += mu
+                predictedvalues[:k_ar - start] += mu
 
         if end < k_ar:
             return predictedvalues
@@ -228,7 +222,7 @@ def predict(self, params, start=None, end=None, dynamic=False):
 
         pv_start = max(k_ar - start, 0)
         fv_start = max(start - k_ar, 0)
-        fv_end = min(len(fittedvalues), end-k_ar+1)
+        fv_end = min(len(fittedvalues), end - k_ar + 1)
         predictedvalues[pv_start:] = fittedvalues[fv_start:fv_end]
 
         if out_of_sample:
@@ -249,15 +243,14 @@ def _presample_varcov(self, params):
         """
         k = self.k_trend
         p = self.k_ar
-        p1 = p+1
 
         # get inv(Vp) Hamilton 5.3.7
         params0 = np.r_[-1, params[k:]]
 
         Vpinv = np.zeros((p, p), dtype=params.dtype)
-        for i in range(1, p1):
-            Vpinv[i-1, i-1:] = np.correlate(params0, params0[:i],)[:-1]
-            Vpinv[i-1, i-1:] -= np.correlate(params0[-i:], params0,)[:-1]
+        for i in range(1, p + 1):
+            Vpinv[i - 1, i - 1:] = np.correlate(params0, params0[:i])[:-1]
+            Vpinv[i - 1, i - 1:] -= np.correlate(params0[-i:], params0)[:-1]
 
         Vpinv = Vpinv + Vpinv.T - np.diag(Vpinv.diagonal())
         return Vpinv
@@ -270,9 +263,8 @@ def _loglike_css(self, params):
         Y = self.Y
         X = self.X
         ssr = sumofsq(Y.squeeze() - np.dot(X, params))
-        sigma2 = ssr/nobs
-        return (-nobs/2 * (np.log(2 * np.pi) + np.log(sigma2)) -
-                ssr/(2 * sigma2))
+        sigma2 = ssr / nobs
+        return -nobs / 2 * (np.log(2 * np.pi) + np.log(sigma2) + 1)
 
     def _loglike_mle(self, params):
         """
@@ -304,15 +296,15 @@ def _loglike_mle(self, params):
         ssr = sumofsq(endog[k_ar:].squeeze() - np.dot(X, params))
 
         # concentrating the likelihood means that sigma2 is given by
-        sigma2 = 1./nobs * (diffpVpinv + ssr)
+        sigma2 = 1. / nobs * (diffpVpinv + ssr)
         self.sigma2 = sigma2
         logdet = slogdet(Vpinv)[1]  # TODO: add check for singularity
-        loglike = -1/2. * (nobs * (np.log(2 * np.pi) + np.log(sigma2)) -
-                           logdet + diffpVpinv / sigma2 + ssr / sigma2)
+        loglike = -1 / 2. * (nobs * (np.log(2 * np.pi) + np.log(sigma2))
+                             - logdet + diffpVpinv / sigma2 + ssr / sigma2)
         return loglike
 
     def loglike(self, params):
-        """
+        r"""
         The loglikelihood of an AR(p) process
 
         Parameters
@@ -330,20 +322,31 @@ def loglike(self, params):
         Contains constant term.  If the model is fit by OLS then this returns
         the conditional maximum likelihood.
 
-        .. math:: \\frac{\\left(n-p\\right)}{2}\\left(\\log\\left(2\\pi\\right)+\\log\\left(\\sigma^{2}\\right)\\right)-\\frac{1}{\\sigma^{2}}\\sum_{i}\\epsilon_{i}^{2}
+        .. math::
+
+           \frac{\left(n-p\right)}{2}\left(\log\left(2\pi\right)
+           +\log\left(\sigma^{2}\right)\right)
+           -\frac{1}{\sigma^{2}}\sum_{i}\epsilon_{i}^{2}
 
         If it is fit by MLE then the (exact) unconditional maximum likelihood
         is returned.
 
-        .. math:: -\\frac{n}{2}log\\left(2\\pi\\right)-\\frac{n}{2}\\log\\left(\\sigma^{2}\\right)+\\frac{1}{2}\\left|V_{p}^{-1}\\right|-\\frac{1}{2\\sigma^{2}}\\left(y_{p}-\\mu_{p}\\right)^{\\prime}V_{p}^{-1}\\left(y_{p}-\\mu_{p}\\right)-\\frac{1}{2\\sigma^{2}}\\sum_{t=p+1}^{n}\\epsilon_{i}^{2}
+        .. math::
+
+           -\frac{n}{2}log\left(2\pi\right)
+           -\frac{n}{2}\log\left(\sigma^{2}\right)
+           +\frac{1}{2}\left|V_{p}^{-1}\right|
+           -\frac{1}{2\sigma^{2}}\left(y_{p}
+           -\mu_{p}\right)^{\prime}V_{p}^{-1}\left(y_{p}-\mu_{p}\right)
+           -\frac{1}{2\sigma^{2}}\sum_{t=p+1}^{n}\epsilon_{i}^{2}
 
         where
 
-        :math:`\\mu_{p}` is a (`p` x 1) vector with each element equal to the
-        mean of the AR process and :math:`\\sigma^{2}V_{p}` is the (`p` x `p`)
+        :math:`\mu_{p}` is a (`p` x 1) vector with each element equal to the
+        mean of the AR process and :math:`\sigma^{2}V_{p}` is the (`p` x `p`)
         variance-covariance matrix of the first `p` observations.
         """
-        # TODO: Math is on Hamilton ~pp 124-5
+        # Math is on Hamilton ~pp 124-5
         if self.method == "cmle":
             return self._loglike_css(params)
 
@@ -425,14 +428,14 @@ def select_order(self, maxlag, ic, trend='c', method='mle'):
         results = {}
 
         if ic != 't-stat':
-            for lag in range(k, maxlag+1):
+            for lag in range(k, maxlag + 1):
                 # have to reinstantiate the model to keep comparable models
-                endog_tmp = endog[maxlag-lag:]
+                endog_tmp = endog[maxlag - lag:]
                 fit = AR(endog_tmp).fit(maxlag=lag, method=method,
                                         full_output=0, trend=trend,
                                         maxiter=100, disp=0)
                 results[lag] = getattr(fit, ic)
-            bestic, bestlag = min((res, k) for k, res in iteritems(results))
+            bestic, bestlag = min((res, k) for k, res in results.items())
 
         else:  # choose by last t-stat.
             stop = 1.6448536269514722  # for t-stat, norm.ppf(.95)
@@ -519,17 +522,22 @@ def fit(self, maxlag=None, method='cmle', ic=None, trend='c',
         --------
         statsmodels.base.model.LikelihoodModel.fit
         """
+        start_params = array_like(start_params, 'start_params', ndim=1,
+                                  optional=True)
         method = method.lower()
-        if method not in ['cmle', 'yw', 'mle']:
+        if method not in ['cmle', 'mle']:
             raise ValueError("Method %s not recognized" % method)
         self.method = method
         self.trend = trend
         self.transparams = transparams
         nobs = len(self.endog)  # overwritten if method is 'cmle'
         endog = self.endog
-
+        # The parameters are no longer allowed to change in an instance
+        fit_params = (maxlag, method, ic, trend)
+        if self._fit_params is not None and self._fit_params != fit_params:
+            raise RuntimeError(REPEATED_FIT_ERROR.format(*self._fit_params))
         if maxlag is None:
-            maxlag = int(round(12*(nobs/100.)**(1/4.)))
+            maxlag = int(round(12 * (nobs / 100.) ** (1 / 4.)))
         k_ar = maxlag  # stays this if ic is None
 
         # select lag length
@@ -551,13 +559,13 @@ def fit(self, maxlag=None, method='cmle', ic=None, trend='c',
         self.Y = Y
         self.X = X
 
-        if method == "cmle":     # do OLS
+        if method == "cmle":  # do OLS
             arfit = OLS(Y, X).fit()
             params = arfit.params
             self.nobs = nobs - k_ar
-            self.sigma2 = arfit.ssr/arfit.nobs  # needed for predict fcasterr
+            self.sigma2 = arfit.ssr / arfit.nobs  # needed for predict fcasterr
 
-        elif method == "mle":
+        else:  # method == "mle"
             solver = solver.lower()
             self.nobs = nobs
             if start_params is None:
@@ -583,24 +591,19 @@ def fit(self, maxlag=None, method='cmle', ic=None, trend='c',
                 params = self._transparams(params)
                 self.transparams = False  # turn off now for other results
 
-        # do not use yw, because we cannot estimate the constant
-        #elif method == "yw":
-        #    params, omega = yule_walker(endog, order=maxlag,
-        #            method="mle", demean=False)
-        #    # how to handle inference after Yule-Walker?
-        #    self.params = params #TODO: do not attach here
-        #    self.omega = omega
-
         pinv_exog = np.linalg.pinv(X)
         normalized_cov_params = np.dot(pinv_exog, pinv_exog.T)
         arfit = ARResults(self, params, normalized_cov_params)
         if method == 'mle' and full_output:
             arfit.mle_retvals = mlefit.mle_retvals
             arfit.mle_settings = mlefit.mle_settings
+        # Set fit params since completed the fit
+        if self._fit_params is None:
+            self._fit_params = fit_params
         return ARResultsWrapper(arfit)
 
 
-class ARResults(tsbase.TimeSeriesModelResults):
+class ARResults(tsa_model.TimeSeriesModelResults):
     """
     Class to hold results from fitting an AR model.
 
@@ -693,7 +696,7 @@ def __init__(self, model, params, normalized_cov_params=None, scale=1.):
         if k_trend > 0:
             trendorder = k_trend - 1
         self.trendorder = trendorder
-        #TODO: cmle vs mle?
+        # TODO: cmle vs mle?
         self.df_model = k_ar + k_trend
         self.df_resid = self.model.df_resid = n_totobs - self.df_model
 
@@ -705,7 +708,7 @@ def sigma2(self):
         else:
             return self.model.sigma2
 
-    @cache_writable()   # for compatability with RegressionResults
+    @cache_writable()  # for compatability with RegressionResults
     def scale(self):
         return self.sigma2
 
@@ -722,18 +725,18 @@ def bse(self):  # allow user to specify?
 
     @cache_readonly
     def pvalues(self):
-        return norm.sf(np.abs(self.tvalues))*2
+        return norm.sf(np.abs(self.tvalues)) * 2
 
     @cache_readonly
     def aic(self):
-        #JP: this is based on loglike with dropped constant terms ?
+        # TODO: this is based on loglike with dropped constant terms ?
         # Lutkepohl
-        #return np.log(self.sigma2) + 1./self.model.nobs * self.k_ar
+        # return np.log(self.sigma2) + 1./self.model.nobs * self.k_ar
         # Include constant as estimated free parameter and double the loss
-        return np.log(self.sigma2) + 2 * (1 + self.df_model)/self.nobs
+        return np.log(self.sigma2) + 2 * (1 + self.df_model) / self.nobs
         # Stata defintion
-        #nobs = self.nobs
-        #return -2 * self.llf/nobs + 2 * (self.k_ar+self.k_trend)/nobs
+        # nobs = self.nobs
+        # return -2 * self.llf/nobs + 2 * (self.k_ar+self.k_trend)/nobs
 
     @cache_readonly
     def hqic(self):
@@ -741,11 +744,11 @@ def hqic(self):
         # Lutkepohl
         # return np.log(self.sigma2)+ 2 * np.log(np.log(nobs))/nobs * self.k_ar
         # R uses all estimated parameters rather than just lags
-        return (np.log(self.sigma2) + 2 * np.log(np.log(nobs))/nobs *
-                (1 + self.df_model))
+        return (np.log(self.sigma2) + 2 * np.log(np.log(nobs))
+                / nobs * (1 + self.df_model))
         # Stata
-        #nobs = self.nobs
-        #return -2 * self.llf/nobs + 2 * np.log(np.log(nobs))/nobs * \
+        # nobs = self.nobs
+        # return -2 * self.llf/nobs + 2 * np.log(np.log(nobs))/nobs * \
         #        (self.k_ar + self.k_trend)
 
     @cache_readonly
@@ -753,15 +756,15 @@ def fpe(self):
         nobs = self.nobs
         df_model = self.df_model
         # Lutkepohl
-        return ((nobs+df_model)/(nobs-df_model))*self.sigma2
+        return ((nobs + df_model) / (nobs - df_model)) * self.sigma2
 
     @cache_readonly
     def bic(self):
         nobs = self.nobs
         # Lutkepohl
-        #return np.log(self.sigma2) + np.log(nobs)/nobs * self.k_ar
+        # return np.log(self.sigma2) + np.log(nobs)/nobs * self.k_ar
         # Include constant as est. free parameter
-        return np.log(self.sigma2) + (1 + self.df_model) * np.log(nobs)/nobs
+        return np.log(self.sigma2) + (1 + self.df_model) * np.log(nobs) / nobs
         # Stata
         # return -2 * self.llf/nobs + np.log(nobs)/nobs * (self.k_ar + \
         #       self.k_trend)
@@ -776,10 +779,6 @@ def resid(self):
         else:
             return model.endog.squeeze() - self.fittedvalues
 
-    #def ssr(self):
-    #    resid = self.resid
-    #    return np.dot(resid, resid)
-
     @cache_readonly
     def roots(self):
         k = self.k_trend
@@ -801,6 +800,36 @@ def fittedvalues(self):
         return self.model.predict(self.params)
 
     def predict(self, start=None, end=None, dynamic=False):
+        """
+        Returns in-sample and out-of-sample prediction.
+
+        Parameters
+        ----------
+        start : int, str, or datetime
+            Zero-indexed observation number at which to start forecasting, ie.,
+            the first forecast is start. Can also be a date string to
+            parse or a datetime type.
+        end : int, str, or datetime
+            Zero-indexed observation number at which to end forecasting, ie.,
+            the first forecast is start. Can also be a date string to
+            parse or a datetime type.
+        dynamic : bool
+            The `dynamic` keyword affects in-sample prediction. If dynamic
+            is False, then the in-sample lagged values are used for
+            prediction. If `dynamic` is True, then in-sample forecasts are
+            used in place of lagged dependent variables. The first forecasted
+            value is `start`.
+
+        Returns
+        -------
+        predicted values : array
+
+        Notes
+        -----
+        The linear Gaussian Kalman filter is used to return pre-sample fitted
+        values. The exact initial Kalman Filter is used. See Durbin and Koopman
+        in the references for more information.
+        """
         params = self.params
         predictedvalues = self.model.predict(params, start, end, dynamic)
         return predictedvalues
@@ -895,85 +924,11 @@ def summary(self, alpha=.05):
 
 class ARResultsWrapper(wrap.ResultsWrapper):
     _attrs = {}
-    _wrap_attrs = wrap.union_dicts(tsbase.TimeSeriesResultsWrapper._wrap_attrs,
-                                   _attrs)
+    _wrap_attrs = wrap.union_dicts(
+        tsa_model.TimeSeriesResultsWrapper._wrap_attrs, _attrs)
     _methods = {}
     _wrap_methods = wrap.union_dicts(
-        tsbase.TimeSeriesResultsWrapper._wrap_methods, _methods)
-wrap.populate_wrapper(ARResultsWrapper, ARResults)  # noqa:E305
-
-
-if __name__ == "__main__":
-    import statsmodels.api as sm
-    sunspots = sm.datasets.sunspots.load(as_pandas=False)
-# Why does R demean the data by defaut?
-    ar_ols = AR(sunspots.endog)
-    res_ols = ar_ols.fit(maxlag=9)
-    ar_mle = AR(sunspots.endog)
-    res_mle_bfgs = ar_mle.fit(maxlag=9, method="mle", solver="bfgs",
-                              maxiter=500, gtol=1e-10)
-#    res_mle2 = ar_mle.fit(maxlag=1, method="mle", maxiter=500, penalty=True,
-#            tol=1e-13)
-
-#    ar_yw = AR(sunspots.endog)
-#    res_yw = ar_yw.fit(maxlag=4, method="yw")
-
-#    # Timings versus talkbox
-#    from timeit import default_timer as timer
-#    print "Time AR fit vs. talkbox"
-#    # generate a long series of AR(2) data
-#
-#    nobs = 1000000
-#    y = np.empty(nobs)
-#    y[0:2] = 0
-#    for i in range(2,nobs):
-#        y[i] = .25 * y[i-1] - .75 * y[i-2] + np.random.rand()
-#
-#    mod_sm = AR(y)
-#    t = timer()
-#    res_sm = mod_sm.fit(method="yw", trend="nc", demean=False, maxlag=2)
-#    t_end = timer()
-#    print str(t_end - t) + " seconds for sm.AR with yule-walker, 2 lags"
-#    try:
-#        import scikits.talkbox as tb
-#    except:
-#        raise ImportError("You need scikits.talkbox installed for timings")
-#    t = timer()
-#    mod_tb = tb.lpc(y, 2)
-#    t_end = timer()
-#    print str(t_end - t) + " seconds for talkbox.lpc"
-#    print """For higher lag lengths ours quickly fills up memory and starts
-#thrashing the swap.  Should we include talkbox C code or Cythonize the
-#Levinson recursion algorithm?"""
-
-    ## Try with a pandas series
-    import pandas
-    import scikits.timeseries as ts
-    d1 = ts.Date(year=1700, freq='A')
-    #NOTE: have to have yearBegin offset for annual data until parser rewrite
-    #should this be up to the user, or should it be done in TSM init?
-    #NOTE: not anymore, it's end of year now
-    ts_dr = ts.date_array(start_date=d1, length=len(sunspots.endog))
-    pandas_dr = pandas.DatetimeIndex(start=d1.datetime,
-                                 periods=len(sunspots.endog),
-                                     freq='A-DEC')
-    #pandas_dr = pandas_dr.shift(-1, pandas.datetools.yearBegin)
-
-    dates = np.arange(1700, 1700 + len(sunspots.endog))
-    dates = ts.date_array(dates, freq='A')
-    #sunspots = pandas.Series(sunspots.endog, index=dates)
-
-    #NOTE: pandas only does business days for dates it looks like
-    import datetime
-    dt_dates = np.asarray(lmap(datetime.datetime.fromordinal,
-                              ts_dr.toordinal().astype(int)))
-    sunspots = pandas.Series(sunspots.endog, index=dt_dates)
-
-    #NOTE: pandas cannot handle pre-1900 dates
-    mod = AR(sunspots, freq='A')
-    res = mod.fit(method='mle', maxlag=9)
-
-# some data for an example in Box Jenkins
-    IBM = np.asarray([460, 457, 452, 459, 462, 459, 463, 479, 493, 490.])
-    w = np.diff(IBM)
-    theta = .5
+        tsa_model.TimeSeriesResultsWrapper._wrap_methods, _methods)
+
+
+wrap.populate_wrapper(ARResultsWrapper, ARResults)
diff --git a/statsmodels/tsa/arima_model.py b/statsmodels/tsa/arima_model.py
--- a/statsmodels/tsa/arima_model.py
+++ b/statsmodels/tsa/arima_model.py
@@ -8,28 +8,32 @@
 
 import numpy as np
 import pandas as pd
-from scipy import optimize
-from scipy.stats import t, norm
-from scipy.signal import lfilter
 from numpy import dot, log, zeros, pi
 from numpy.linalg import inv
+from scipy import optimize
+from scipy.signal import lfilter
+from scipy.stats import t, norm
 
-
-from statsmodels.tools.decorators import cache_readonly
-import statsmodels.tsa.base.tsa_model as tsbase
 import statsmodels.base.wrapper as wrap
 from statsmodels.regression.linear_model import yule_walker, OLS
+from statsmodels.tools.decorators import cache_readonly
+from statsmodels.tools.numdiff import approx_hess_cs, approx_fprime_cs
+from statsmodels.tools.sm_exceptions import SpecificationWarning
+from statsmodels.tools.validation import array_like
+from statsmodels.tsa.ar_model import AR
+from statsmodels.tsa.arima_process import arma2ma
+from statsmodels.tsa.base import tsa_model
+from statsmodels.tsa.kalmanf import KalmanFilter
 from statsmodels.tsa.tsatools import (lagmat, add_trend,
                                       _ar_transparams, _ar_invtransparams,
                                       _ma_transparams, _ma_invtransparams,
                                       unintegrate, unintegrate_levels)
 from statsmodels.tsa.vector_ar import util
-from statsmodels.tsa.ar_model import AR
-from statsmodels.tsa.arima_process import arma2ma
-from statsmodels.tools.numdiff import approx_hess_cs, approx_fprime_cs
-from statsmodels.tools.validation import array_like
-from statsmodels.tools.sm_exceptions import SpecificationWarning
-from statsmodels.tsa.kalmanf import KalmanFilter
+
+REPEATED_FIT_ERROR = """
+Model has been fit using trend={0} and method={1}. These cannot be changed
+in subsequent calls to `fit`. Instead, use a new instance of {mod}.
+"""
 
 _armax_notes = r"""
     Notes
@@ -50,12 +54,11 @@
     change for the case of the `css` model in future versions.
 """
 
-_arma_params = \
-"""endog : array_like
+_arma_params = """endog : array_like
         The endogenous variable.
     order : iterable
         The (p,q) order of the model for the number of AR parameters,
-        differences, and MA parameters to use.
+        and MA parameters to use.
     exog : array_like, optional
         An optional array of exogenous variables. This should *not* include a
         constant or trend. You can specify this in the `fit` method."""
@@ -64,8 +67,7 @@
 
 _arima_model = "Autoregressive Integrated Moving Average ARIMA(p,d,q) Model"
 
-_arima_params = \
-"""endog : array_like
+_arima_params = """endog : array_like
         The endogenous variable.
     order : iterable
         The (p,d,q) order of the model for the number of AR parameters,
@@ -145,17 +147,17 @@
 
 """
 
-_arma_predict = _predict % {"Model" : "ARMA",
-                            "params" : """params : array_like
+_arma_predict = _predict % {"Model": "ARMA",
+                            "params": """params : array_like
             The fitted parameters of the model.""",
-                            "extra_params" : "",
-                            "returns" : _predict_returns,
-                            "extra_section" : _predict_notes}
-
-_arma_results_predict = _predict % {"Model" : "ARMA", "params" : "",
-                                    "extra_params" : "",
-                                    "returns" : _predict_returns,
-                                    "extra_section" : _results_notes}
+                            "extra_params": "",
+                            "returns": _predict_returns,
+                            "extra_section": _predict_notes}
+
+_arma_results_predict = _predict % {"Model": "ARMA", "params": "",
+                                    "extra_params": "",
+                                    "returns": _predict_returns,
+                                    "extra_section": _results_notes}
 _arima_extras = """typ : str {'linear', 'levels'}
 
             - 'linear' : Linear prediction in terms of the differenced
@@ -163,18 +165,18 @@
             - 'levels' : Predict the levels of the original endogenous
               variables.\n"""
 
-_arima_predict = _predict % {"Model" : "ARIMA",
-                             "params" : """params : array_like
+_arima_predict = _predict % {"Model": "ARIMA",
+                             "params": """params : array_like
             The fitted parameters of the model.""",
-                             "extra_params" : _arima_extras,
-                             "returns" : _predict_returns,
-                             "extra_section" : _predict_notes}
+                             "extra_params": _arima_extras,
+                             "returns": _predict_returns,
+                             "extra_section": _predict_notes}
 
-_arima_results_predict = _predict % {"Model" : "ARIMA",
-                                     "params" : "",
-                                     "extra_params" :_arima_extras,
-                                     "returns" : _predict_returns,
-                                     "extra_section" : _results_notes}
+_arima_results_predict = _predict % {"Model": "ARIMA",
+                                     "params": "",
+                                     "extra_params": _arima_extras,
+                                     "returns": _predict_returns,
+                                     "extra_section": _results_notes}
 
 _arima_plot_predict_example = """        Examples
         --------
@@ -209,24 +211,22 @@
     "returns": """fig : matplotlib.Figure
             The plotted Figure instance""",
     "extra_section": ('\n' + _arima_plot_predict_example +
-                       '\n' + _results_notes)
+                      '\n' + _results_notes)
 }
 
 _arima_plot_predict = ("""
         Plot forecasts
                       """ + '\n'.join(_predict.split('\n')[2:])) % {
-    "params" : "",
-    "extra_params" : _plot_extras,
-    "returns" : """fig : matplotlib.Figure
+    "params": "",
+    "extra_params": _plot_extras,
+    "returns": """fig : matplotlib.Figure
             The plotted Figure instance""",
-    "extra_section" : ('\n' + _arima_plot_predict_example +
-                                   '\n' +
-                                   '\n'.join(_results_notes.split('\n')[:3]) +
-                              ("""
+    "extra_section": ('\n' + _arima_plot_predict_example + '\n' +
+                      '\n'.join(_results_notes.split('\n')[:3])
+                      + ("""
         This is hard-coded to only allow plotting of the forecasts in levels.
-""") +
-                              '\n'.join(_results_notes.split('\n')[3:]))
-                      }
+""") + '\n'.join(_results_notes.split('\n')[3:]))
+}
 
 
 def cumsum_n(x, n):
@@ -286,9 +286,9 @@ def _get_predict_out_of_sample(endog, p, q, k_trend, k_exog, start, errors,
     if q:
         resid = np.zeros(q)
         if start and 'mle' in method or (start == p and not start == 0):
-            resid[:q] = errors[start-q:start]
+            resid[:q] = errors[start - q:start]
         elif start:
-            resid[:q] = errors[start-q-p:start-p]
+            resid[:q] = errors[start - q - p:start - p]
         else:
             resid[:q] = errors[-q:]
     else:
@@ -298,9 +298,9 @@ def _get_predict_out_of_sample(endog, p, q, k_trend, k_exog, start, errors,
     if k_trend == 1:
         # use expectation not constant
         if k_exog > 0:
-            #TODO: technically should only hold for MLE not
-            # conditional model. See #274.
-            # ensure 2-d for conformability
+            # TODO: technically should only hold for MLE not
+            #  conditional model. See #274.
+            #  ensure 2-d for conformability
             if np.ndim(exog) == 1 and k_exog == 1:
                 # have a 1d series of observations -> 2d
                 exog = exog[:, None]
@@ -315,10 +315,9 @@ def _get_predict_out_of_sample(endog, p, q, k_trend, k_exog, start, errors,
             mu = mu + (np.r_[1, -arparams[::-1]] * X).sum(1)[:, None]
         else:
             mu = trendparam * (1 - arparams.sum())
-            mu = np.array([mu]*steps)
+            mu = np.array([mu] * steps)
     elif k_exog > 0:
         X = np.dot(exog, exparams)
-        #NOTE: you should not have to give in-sample exog!
         X = lagmat(X, p, original='in', trim='both')
         mu = (np.r_[1, -arparams[::-1]] * X).sum(1)[:, None]
     else:
@@ -327,7 +326,7 @@ def _get_predict_out_of_sample(endog, p, q, k_trend, k_exog, start, errors,
     endog = np.zeros(p + steps - 1)
 
     if p and start:
-        endog[:p] = y[start-p:start]
+        endog[:p] = y[start - p:start]
     elif p:
         endog[:p] = y[-p:]
 
@@ -362,14 +361,14 @@ def _arma_predict_out_of_sample(params, steps, errors, p, q, k_trend, k_exog,
         fcast = (mu[i] + np.dot(arparams, endog[i:i + p]) +
                  np.dot(maparams[:q - i], resid[i:i + q]))
         forecast[i] = fcast
-        endog[i+p] = fcast
+        endog[i + p] = fcast
 
     for i in range(i + 1, steps - 1):
-        fcast = mu[i] + np.dot(arparams, endog[i:i+p])
+        fcast = mu[i] + np.dot(arparams, endog[i:i + p])
         forecast[i] = fcast
-        endog[i+p] = fcast
+        endog[i + p] = fcast
 
-    #need to do one more without updating endog
+    # need to do one more without updating endog
     forecast[steps - 1] = mu[steps - 1] + np.dot(arparams, endog[steps - 1:])
     return forecast
 
@@ -393,8 +392,8 @@ def _arma_predict_in_sample(start, end, endog, resid, k_ar, method):
 def _unpack_params(params, order, k_trend, k_exog, reverse=False):
     p, q = order
     k = k_trend + k_exog
-    maparams = params[k+p:]
-    arparams = params[k:k+p]
+    maparams = params[k + p:]
+    arparams = params[k:k + p]
     trend = params[:k_trend]
     exparams = params[k_trend:k]
     if reverse:
@@ -402,12 +401,6 @@ def _unpack_params(params, order, k_trend, k_exog, reverse=False):
     return trend, exparams, arparams, maparams
 
 
-def _unpack_order(order):
-    k_ar, k_ma, k = order
-    k_lags = max(k_ar, k_ma+1)
-    return k_ar, k_ma, order, k_lags
-
-
 def _make_arma_names(data, k_trend, order, exog_names):
     k_ar, k_ma = order
     exog_names = exog_names or []
@@ -423,7 +416,7 @@ def _make_arma_names(data, k_trend, order, exog_names):
 
 def _make_arma_exog(endog, exog, trend):
     k_trend = 1  # overwritten if no constant
-    if exog is None and trend == 'c':   # constant only
+    if exog is None and trend == 'c':  # constant only
         exog = np.ones((len(endog), 1))
     elif exog is not None and trend == 'c':  # constant plus exogenous
         exog = add_trend(exog, trend='c', prepend=True, has_constant='raise')
@@ -442,31 +435,30 @@ def _check_estimable(nobs, n_params):
         raise ValueError("Insufficient degrees of freedom to estimate")
 
 
-class ARMA(tsbase.TimeSeriesModel):
-
-    __doc__ = tsbase._tsa_doc % {"model" : _arma_model,
-                                 "params" : _arma_params, "extra_params" : "",
-                                 "extra_sections" : _armax_notes %
-                                 {"Model" : "ARMA"}}
+class ARMA(tsa_model.TimeSeriesModel):
+    __doc__ = tsa_model._tsa_doc % {"model": _arma_model,
+                                    "params": _arma_params,
+                                    "extra_params": "",
+                                    "extra_sections":
+                                        _armax_notes % {"Model": "ARMA"}}
 
     def __init__(self, endog, order, exog=None, dates=None, freq=None,
                  missing='none'):
         super(ARMA, self).__init__(endog, exog, dates, freq, missing=missing)
         # GH 2575
         array_like(endog, 'endog')
-        exog = self.data.exog  # get it after it's gone through processing
+        exog = array_like(self.data.exog, 'exog', ndim=2, optional=True)
         _check_estimable(len(self.endog), sum(order))
         self.k_ar = k_ar = order[0]
         self.k_ma = k_ma = order[1]
-        self.k_lags = max(k_ar, k_ma+1)
+        self.k_lags = max(k_ar, k_ma + 1)
         if exog is not None:
-            if exog.ndim == 1:
-                exog = exog[:, None]
             k_exog = exog.shape[1]  # number of exog. variables excl. const
         else:
             k_exog = 0
         self.k_exog = k_exog
         self._orig_exog_names = self.exog_names
+        self._fit_params = None
 
     def _fit_start_params_hr(self, order, start_ar_lags=None):
         """
@@ -504,7 +496,7 @@ def _fit_start_params_hr(self, order, start_ar_lags=None):
         `Review of the International Statistical Institute`. Vol. 28, No. 3
         """
         p, q, k = order
-        start_params = zeros((p+q+k))
+        start_params = zeros((p + q + k))
         # make copy of endog because overwritten
         endog = np.array(self.endog, np.float64)
         exog = self.exog
@@ -517,7 +509,7 @@ def _fit_start_params_hr(self, order, start_ar_lags=None):
                 # make sure we do not run into small data problems in AR fit
                 nobs = len(endog)
                 if start_ar_lags is None:
-                    maxlag = int(round(12*(nobs/100.)**(1/4.)))
+                    maxlag = int(round(12 * (nobs / 100.) ** (1 / 4.)))
                     if maxlag >= nobs:
                         maxlag = nobs - 1
                     armod = AR(endog).fit(ic='bic', trend='nc', maxlag=maxlag)
@@ -550,12 +542,12 @@ def _fit_start_params_hr(self, order, start_ar_lags=None):
                 # stack ar lags and resids
                 X = np.column_stack((lag_endog, lag_resid))
                 coefs = OLS(endog[max(p_tmp + q, p):], X).fit().params
-                start_params[k:k+p+q] = coefs
+                start_params[k:k + p + q] = coefs
             else:
-                start_params[k+p:k+p+q] = yule_walker(endog, order=q)[0]
+                start_params[k + p:k + p + q] = yule_walker(endog, order=q)[0]
         if q == 0 and p != 0:
             arcoefs = yule_walker(endog, order=p)[0]
-            start_params[k:k+p] = arcoefs
+            start_params[k:k + p] = arcoefs
 
         # check AR coefficients
         if p and not np.all(np.abs(np.roots(np.r_[1, -start_params[k:k + p]]
@@ -579,12 +571,13 @@ def _fit_start_params(self, order, method, start_ar_lags=None):
         if method != 'css-mle':  # use Hannan-Rissanen to get start params
             start_params = self._fit_start_params_hr(order, start_ar_lags)
         else:  # use CSS to get start params
-            func = lambda params: -self.loglike_css(params)
-            #start_params = [.1]*(k_ar+k_ma+k_exog) # different one for k?
+            def func(params):
+                return -self.loglike_css(params)
+
             start_params = self._fit_start_params_hr(order, start_ar_lags)
             if self.transparams:
                 start_params = self._invtransparams(start_params)
-            bounds = [(None,)*2]*sum(order)
+            bounds = [(None,) * 2] * sum(order)
             mlefit = optimize.fmin_l_bfgs_b(func, start_params,
                                             approx_grad=True, m=12,
                                             pgtol=1e-7, factr=1e3,
@@ -632,11 +625,11 @@ def _transparams(self, params):
 
         # AR Coeffs
         if k_ar != 0:
-            newparams[k:k+k_ar] = _ar_transparams(params[k:k+k_ar].copy())
+            newparams[k:k + k_ar] = _ar_transparams(params[k:k + k_ar].copy())
 
         # MA Coeffs
         if k_ma != 0:
-            newparams[k+k_ar:] = _ma_transparams(params[k+k_ar:].copy())
+            newparams[k + k_ar:] = _ma_transparams(params[k + k_ar:].copy())
         return newparams
 
     def _invtransparams(self, start_params):
@@ -646,15 +639,15 @@ def _invtransparams(self, start_params):
         k_ar, k_ma = self.k_ar, self.k_ma
         k = self.k_exog + self.k_trend
         newparams = start_params.copy()
-        arcoefs = newparams[k:k+k_ar]
-        macoefs = newparams[k+k_ar:]
+        arcoefs = newparams[k:k + k_ar]
+        macoefs = newparams[k + k_ar:]
         # AR coeffs
         if k_ar != 0:
-            newparams[k:k+k_ar] = _ar_invtransparams(arcoefs)
+            newparams[k:k + k_ar] = _ar_invtransparams(arcoefs)
 
         # MA coeffs
         if k_ma != 0:
-            newparams[k+k_ar:k+k_ar+k_ma] = _ma_invtransparams(macoefs)
+            newparams[k + k_ar:k + k_ar + k_ma] = _ma_invtransparams(macoefs)
         return newparams
 
     def _get_prediction_index(self, start, end, dynamic, index=None):
@@ -709,8 +702,6 @@ def geterrors(self, params):
             errors = KalmanFilter.geterrors(y, k, k_ar, k_ma, k_lags, nobs,
                                             Z_mat, m, R_mat, T_mat,
                                             paramsdtype)
-            if isinstance(errors, tuple):
-                errors = errors[0]  # non-cython version returns a tuple
         else:  # use scipy.signal.lfilter
             y = self.endog.copy()
             k = self.k_exog + self.k_trend
@@ -727,7 +718,7 @@ def geterrors(self, params):
             b, a = np.r_[1, -arparams], np.r_[1, maparams]
             zi = zeros((max(k_ar, k_ma)))
             for i in range(k_ar):
-                zi[i] = sum(-b[:i+1][::-1]*y[:i+1])
+                zi[i] = sum(-b[:i + 1][::-1] * y[:i + 1])
             e = lfilter(b, a, y, zi=zi)
             errors = e[0][k_ar:]
         return errors.squeeze()
@@ -736,9 +727,10 @@ def predict(self, params, start=None, end=None, exog=None, dynamic=False,
                 **kwargs):
         if kwargs and 'typ' not in kwargs:
             raise TypeError('Unknown extra arguments')
+        if not (hasattr(self, 'k_ar') and hasattr(self, 'k_trend')):
+            raise RuntimeError('Model must be fit before calling predict')
+        params = array_like(params, 'params')
         method = getattr(self, 'method', 'mle')  # do not assume fit
-        # params = np.asarray(params)
-
         # will return an index of a date
         start, end, out_of_sample, _ = (
             self._get_prediction_index(start, end, dynamic))
@@ -767,9 +759,9 @@ def predict(self, params, start=None, end=None, exog=None, dynamic=False,
                     exog = np.vstack((exog_insample, exog))
                 else:
                     exog = exog_insample
-            #TODO: now that predict does dynamic in-sample it should
-            # also return error estimates and confidence intervals
-            # but how? len(endog) is not tot_obs
+            # TODO: now that predict does dynamic in-sample it should
+            #  also return error estimates and confidence intervals
+            #  but how? len(endog) is not tot_obs
             out_of_sample += end - start + 1
             return _arma_predict_out_of_sample(params, out_of_sample, resid,
                                                k_ar, self.k_ma, self.k_trend,
@@ -788,7 +780,6 @@ def predict(self, params, start=None, end=None, exog=None, dynamic=False,
                                                          method=method)
             if (exog is not None and
                     (exog.shape[0] - k_ar) != forecastvalues.shape[0]):
-
                 import warnings
                 msg = """
 The number of observations in exog does not match the number of out-of-sample
@@ -804,6 +795,7 @@ def predict(self, params, start=None, end=None, exog=None, dynamic=False,
                 warnings.warn(msg, SpecificationWarning)
             predictedvalues = np.r_[predictedvalues, forecastvalues]
         return predictedvalues
+
     predict.__doc__ = _arma_predict
 
     def loglike(self, params, set_sigma2=True):
@@ -852,10 +844,10 @@ def loglike_css(self, params, set_sigma2=True):
         errors = lfilter(b, a, y, zi=zi)[0][k_ar:]
 
         ssr = np.dot(errors, errors)
-        sigma2 = ssr/nobs
+        sigma2 = ssr / nobs
         if set_sigma2:
             self.sigma2 = sigma2
-        llf = -nobs/2.*(log(2*pi) + log(sigma2)) - ssr/(2*sigma2)
+        llf = -nobs / 2. * (log(2 * pi) + log(sigma2)) - ssr / (2 * sigma2)
         return llf
 
     def fit(self, start_params=None, trend='c', method="css-mle",
@@ -936,6 +928,11 @@ def fit(self, start_params=None, trend='c', method="css-mle",
         r, order = 'F')
 
         """
+        if self._fit_params is not None:
+            fp = (trend, method)
+            if self._fit_params != fp:
+                raise RuntimeError(REPEATED_FIT_ERROR.format(*fp, mod='ARMA'))
+
         k_ar = self.k_ar
         k_ma = self.k_ma
 
@@ -948,19 +945,25 @@ def fit(self, start_params=None, trend='c', method="css-mle",
 
         # (re)set trend and handle exogenous variables
         # always pass original exog
-        k_trend, exog = _make_arma_exog(endog, self.exog, trend)
+
+        if hasattr(self, 'k_trend'):
+            k_trend = self.k_trend
+            exog = self.exog
+        else:
+            # Ensures only call once per ARMA instance
+            k_trend, exog = _make_arma_exog(endog, self.exog, trend)
 
         # Check has something to estimate
         if k_ar == 0 and k_ma == 0 and k_trend == 0 and k_exog == 0:
             raise ValueError("Estimation requires the inclusion of least one "
-                         "AR term, MA term, a constant or an exogenous "
-                         "variable.")
+                             "AR term, MA term, a constant or an exogenous "
+                             "variable.")
 
         # check again now that we know the trend
         _check_estimable(len(endog), k_ar + k_ma + k_exog + k_trend)
 
         self.k_trend = k_trend
-        self.exog = exog    # overwrites original exog from __init__
+        self.exog = exog  # overwrites original exog from __init__
 
         # (re)set names for this model
         self.exog_names = _make_arma_names(self.data, k_trend,
@@ -1006,23 +1009,27 @@ def fit(self, start_params=None, trend='c', method="css-mle",
         armafit = ARMAResults(self, params, normalized_cov_params)
         armafit.mle_retvals = mlefit.mle_retvals
         armafit.mle_settings = mlefit.mle_settings
+        # Save core fit parameters for future checks
+        self._fit_params = (trend, method)
+
         return ARMAResultsWrapper(armafit)
 
-    # base class of "from_formula" is "class Model(object)"
     @classmethod
-    def from_formula(cls, formula, data, subset=None, drop_cols=None, *args, **kwargs):
+    def from_formula(cls, formula, data, subset=None, drop_cols=None, *args,
+                     **kwargs):
         raise NotImplementedError("from_formula is not supported"
                                   " for ARMA models.")
 
 
-#NOTE: the length of endog changes when we give a difference to fit
-#so model methods are not the same on unfit models as fit ones
-#starting to think that order of model should be put in instantiation...
+# TODO: the length of endog changes when we give a difference to fit
+#  so model methods are not the same on unfit models as fit ones
+#  starting to think that order of model should be put in instantiation...
 class ARIMA(ARMA):
-    __doc__ = tsbase._tsa_doc % {"model" : _arima_model,
-                                 "params" : _arima_params, "extra_params" : "",
-                                 "extra_sections" : _armax_notes %
-                                 {"Model" : "ARIMA"}}
+    __doc__ = tsa_model._tsa_doc % {"model": _arima_model,
+                                    "params": _arima_params,
+                                    "extra_params": "",
+                                    "extra_sections":
+                                        _armax_notes % {"Model": "ARIMA"}}
 
     def __new__(cls, endog, order, exog=None, dates=None, freq=None,
                 missing='none'):
@@ -1047,15 +1054,15 @@ def __init__(self, endog, order, exog=None, dates=None, freq=None,
                  missing='none'):
         p, d, q = order
         if d > 2:
-            #NOTE: to make more general, need to address the d == 2 stuff
-            # in the predict method
+            # TODO: to make more general, need to address the d == 2 stuff
+            #  in the predict method
             raise ValueError("d > 2 is not supported")
         super(ARIMA, self).__init__(endog, (p, q), exog, dates, freq, missing)
         self.k_diff = d
         self._first_unintegrate = unintegrate_levels(self.endog[:d], d)
         self.endog = np.diff(self.endog, n=d)
-        #NOTE: will check in ARMA but check again since differenced now
-        _check_estimable(len(self.endog), p+q)
+        # NOTE: will check in ARMA but check again since differenced now
+        _check_estimable(len(self.endog), p + q)
         if exog is not None:
             self.exog = self.exog[d:]
         if d == 1:
@@ -1190,9 +1197,9 @@ def fit(self, start_params=None, trend='c', method="css-mle",
 
         """
         mlefit = super(ARIMA, self).fit(start_params, trend,
-                                           method, transparams, solver,
-                                           maxiter, full_output, disp,
-                                           callback, start_ar_lags, **kwargs)
+                                        method, transparams, solver,
+                                        maxiter, full_output, disp,
+                                        callback, start_ar_lags, **kwargs)
         normalized_cov_params = None  # TODO: fix this?
         arima_fit = ARIMAResults(self, mlefit._results.params,
                                  normalized_cov_params)
@@ -1205,9 +1212,10 @@ def fit(self, start_params=None, trend='c', method="css-mle",
 
     def predict(self, params, start=None, end=None, exog=None, typ='linear',
                 dynamic=False):
+        if not (hasattr(self, 'k_ar') and hasattr(self, 'k_trend')):
+            raise RuntimeError('Model must be fit before calling predict')
         # go ahead and convert to an index for easier checking
         if isinstance(start, (str, datetime)):
-            # start = _index_date(start, self.data.dates)
             start, _, _ = self._get_index_label_loc(start)
             if isinstance(start, slice):
                 start = start.start
@@ -1244,8 +1252,8 @@ def predict(self, params, start=None, end=None, exog=None, typ='linear',
                     end += d - 1
                     # add each predicted diff to lagged endog
                     if out_of_sample:
-                        fv = predict[:-out_of_sample] + endog[start:end+1]
-                        if d == 2:  #TODO: make a general solution to this
+                        fv = predict[:-out_of_sample] + endog[start:end + 1]
+                        if d == 2:  # TODO: make a general solution to this
                             fv += np.diff(endog[start - 1:end + 1])
                         levels = unintegrate_levels(endog[-d:], d)
                         fv = np.r_[fv,
@@ -1259,7 +1267,7 @@ def predict(self, params, start=None, end=None, exog=None, typ='linear',
                     k_ar = self.k_ar
                     if out_of_sample:
                         fv = (predict[:-out_of_sample] +
-                              endog[max(start, self.k_ar-1):end+k_ar+1])
+                              endog[max(start, self.k_ar - 1):end + k_ar + 1])
                         if d == 2:
                             fv += np.diff(endog[start - 1:end + 1])
                         levels = unintegrate_levels(endog[-d:], d)
@@ -1267,11 +1275,11 @@ def predict(self, params, start=None, end=None, exog=None, typ='linear',
                                    unintegrate(predict[-out_of_sample:],
                                                levels)[d:]]
                     else:
-                        fv = predict + endog[max(start, k_ar):end+k_ar+1]
+                        fv = predict + endog[max(start, k_ar):end + k_ar + 1]
                         if d == 2:
                             fv += np.diff(endog[start - 1:end + 1])
             else:
-                #IFF we need to use pre-sample values assume pre-sample
+                # IFF we need to use pre-sample values assume pre-sample
                 # residuals are zero, do this by a hack
                 if start == self.k_ar + self.k_diff or start is None:
                     # do the first k_diff+1 separately
@@ -1295,11 +1303,11 @@ def predict(self, params, start=None, end=None, exog=None, typ='linear',
                             start, end, dynamic)
                         start += k_diff
                     self.k_ma = q
-                    return endog[start-1] + np.cumsum(predict)
+                    return endog[start - 1] + np.cumsum(predict)
                 else:
                     predict = super(ARIMA, self).predict(params, start, end,
                                                          exog, dynamic)
-                    return endog[start-1] + np.cumsum(predict)
+                    return endog[start - 1] + np.cumsum(predict)
             return fv
 
         else:  # pragma : no cover
@@ -1308,7 +1316,7 @@ def predict(self, params, start=None, end=None, exog=None, typ='linear',
     predict.__doc__ = _arima_predict
 
 
-class ARMAResults(tsbase.TimeSeriesModelResults):
+class ARMAResults(tsa_model.TimeSeriesModelResults):
     """
     Class to hold results from fitting an ARMA model.
 
@@ -1410,8 +1418,6 @@ class ARMAResults(tsbase.TimeSeriesModelResults):
     """
     _cache = {}
 
-    #TODO: use this for docstring when we fix nobs issue
-
     def __init__(self, model, params, normalized_cov_params=None, scale=1.):
         super(ARMAResults, self).__init__(model, params, normalized_cov_params,
                                           scale)
@@ -1435,11 +1441,11 @@ def __init__(self, model, params, normalized_cov_params=None, scale=1.):
 
     @cache_readonly
     def arroots(self):
-        return np.roots(np.r_[1, -self.arparams])**-1
+        return np.roots(np.r_[1, -self.arparams]) ** -1
 
     @cache_readonly
     def maroots(self):
-        return np.roots(np.r_[1, self.maparams])**-1
+        return np.roots(np.r_[1, self.maparams]) ** -1
 
     @cache_readonly
     def arfreq(self):
@@ -1450,7 +1456,7 @@ def arfreq(self):
         roots.
         """
         z = self.arroots
-        return np.arctan2(z.imag, z.real) / (2*pi)
+        return np.arctan2(z.imag, z.real) / (2 * pi)
 
     @cache_readonly
     def mafreq(self):
@@ -1461,18 +1467,18 @@ def mafreq(self):
         roots.
         """
         z = self.maroots
-        return np.arctan2(z.imag, z.real) / (2*pi)
+        return np.arctan2(z.imag, z.real) / (2 * pi)
 
     @cache_readonly
     def arparams(self):
         k = self.k_exog + self.k_trend
-        return self.params[k:k+self.k_ar]
+        return self.params[k:k + self.k_ar]
 
     @cache_readonly
     def maparams(self):
         k = self.k_exog + self.k_trend
         k_ar = self.k_ar
-        return self.params[k+k_ar:]
+        return self.params[k + k_ar:]
 
     @cache_readonly
     def llf(self):
@@ -1483,7 +1489,7 @@ def bse(self):
         params = self.params
         hess = self.model.hessian(params)
         if len(params) == 1:  # cannot take an inverse, ensure 1d
-            return np.sqrt(-1./hess[0])
+            return np.sqrt(-1. / hess[0])
         return np.sqrt(np.diag(-inv(hess)))
 
     def cov_params(self):  # add scale argument?
@@ -1517,11 +1523,7 @@ def fittedvalues(self):
         if model.method == "css" and k_ar > 0:
             endog = endog[k_ar:]
         fv = endog - self.resid
-        # add deterministic part back in
-        #k = self.k_exog + self.k_trend
-        #TODO: this needs to be commented out for MLE with constant
-        #if k != 0:
-        #    fv += dot(exog, self.params[:k])
+
         return fv
 
     @cache_readonly
@@ -1530,7 +1532,7 @@ def resid(self):
 
     @cache_readonly
     def pvalues(self):
-    #TODO: same for conditional and unconditional?
+        # TODO: same for conditional and unconditional?
         df_resid = self.df_resid
         return t.sf(np.abs(self.tvalues), df_resid) * 2
 
@@ -1538,6 +1540,7 @@ def predict(self, start=None, end=None, exog=None, dynamic=False,
                 **kwargs):
         return self.model.predict(self.params, start, end, exog, dynamic,
                                   **kwargs)
+
     predict.__doc__ = _arma_results_predict
 
     def _forecast_error(self, steps):
@@ -1545,7 +1548,7 @@ def _forecast_error(self, steps):
         ma_rep = arma2ma(np.r_[1, -self.arparams],
                          np.r_[1, self.maparams], lags=steps)
 
-        fcasterr = np.sqrt(sigma2 * np.cumsum(ma_rep**2))
+        fcasterr = np.sqrt(sigma2 * np.cumsum(ma_rep ** 2))
         return fcasterr
 
     def _forecast_conf_int(self, forecast, fcasterr, alpha):
@@ -1603,8 +1606,6 @@ def forecast(self, steps=1, exog=None, alpha=.05):
                 raise ValueError('Forecast values for exog are required when '
                                  'the model contains exogenous regressors.')
 
-
-
         forecast = _arma_predict_out_of_sample(self.params,
                                                steps, self.resid, self.k_ar,
                                                self.k_ma, self.k_trend,
@@ -1667,12 +1668,12 @@ def summary(self, alpha=.05):
                     ]
 
         top_right = [
-                     ('No. Observations:', [str(len(self.model.endog))]),
-                     ('Log Likelihood', ["%#5.3f" % self.llf]),
-                     ('S.D. of innovations', ["%#5.3f" % self.sigma2**.5]),
-                     ('AIC', ["%#5.3f" % self.aic]),
-                     ('BIC', ["%#5.3f" % self.bic]),
-                     ('HQIC', ["%#5.3f" % self.hqic])]
+            ('No. Observations:', [str(len(self.model.endog))]),
+            ('Log Likelihood', ["%#5.3f" % self.llf]),
+            ('S.D. of innovations', ["%#5.3f" % self.sigma2 ** .5]),
+            ('AIC', ["%#5.3f" % self.aic]),
+            ('BIC', ["%#5.3f" % self.bic]),
+            ('HQIC', ["%#5.3f" % self.hqic])]
 
         smry = Summary()
         smry.add_table_2cols(self, gleft=top_left, gright=top_right,
@@ -1795,7 +1796,7 @@ def summary2(self, title=None, alpha=.05, float_format="%.4f"):
         model_info['Method:'] = self.model.method
         model_info['Sample:'] = sample[0]
         model_info['   '] = sample[-1]
-        model_info['S.D. of innovations:'] = "%#5.3f" % self.sigma2**.5
+        model_info['S.D. of innovations:'] = "%#5.3f" % self.sigma2 ** .5
         model_info['HQIC:'] = "%#5.3f" % self.hqic
         model_info['No. Observations:'] = str(len(self.model.endog))
 
@@ -1841,22 +1842,25 @@ def plot_predict(self, start=None, end=None, exog=None, dynamic=False,
                             color='gray', alpha=.5, label=label)
 
         if plot_insample:
-            ax.plot(x[:end + 1 - start], self.model.endog[start:end+1],
+            ax.plot(x[:end + 1 - start], self.model.endog[start:end + 1],
                     label=self.model.endog_names)
 
         ax.legend(loc='best')
 
         return fig
+
     plot_predict.__doc__ = _plot_predict
 
 
 class ARMAResultsWrapper(wrap.ResultsWrapper):
     _attrs = {}
-    _wrap_attrs = wrap.union_dicts(tsbase.TimeSeriesResultsWrapper._wrap_attrs,
-                                   _attrs)
+    _wrap_attrs = wrap.union_dicts(
+        tsa_model.TimeSeriesResultsWrapper._wrap_attrs, _attrs)
     _methods = {}
-    _wrap_methods = wrap.union_dicts(tsbase.TimeSeriesResultsWrapper._wrap_methods,
-                                     _methods)
+    _wrap_methods = wrap.union_dicts(
+        tsa_model.TimeSeriesResultsWrapper._wrap_methods, _methods)
+
+
 wrap.populate_wrapper(ARMAResultsWrapper, ARMAResults)  # noqa:E305
 
 
@@ -1864,6 +1868,7 @@ class ARIMAResults(ARMAResults):
     def predict(self, start=None, end=None, exog=None, typ='linear',
                 dynamic=False):
         return self.model.predict(self.params, start, end, exog, typ, dynamic)
+
     predict.__doc__ = _arima_results_predict
 
     def _forecast_error(self, steps):
@@ -1871,12 +1876,12 @@ def _forecast_error(self, steps):
         ma_rep = arma2ma(np.r_[1, -self.arparams],
                          np.r_[1, self.maparams], lags=steps)
 
-        fcerr = np.sqrt(np.cumsum(cumsum_n(ma_rep, self.k_diff)**2)*sigma2)
+        fcerr = np.sqrt(np.cumsum(cumsum_n(ma_rep, self.k_diff) ** 2) * sigma2)
         return fcerr
 
     def _forecast_conf_int(self, forecast, fcerr, alpha):
-        const = norm.ppf(1 - alpha/2.)
-        conf_int = np.c_[forecast - const*fcerr, forecast + const*fcerr]
+        const = norm.ppf(1 - alpha / 2.)
+        conf_int = np.c_[forecast - const * fcerr, forecast + const * fcerr]
         return conf_int
 
     def forecast(self, steps=1, exog=None, alpha=.05):
@@ -1888,7 +1893,7 @@ def forecast(self, steps=1, exog=None, alpha=.05):
         steps : int
             The number of out of sample forecasts from the end of the
             sample.
-        exog : array
+        exog : ndarray
             If the model is an ARIMAX, you must provide out of sample
             values for the exogenous variables. This should not include
             the constant. The number of observation in exog must match the
@@ -1990,58 +1995,6 @@ def plot_predict(self, start=None, end=None, exog=None, dynamic=False,
 
 class ARIMAResultsWrapper(ARMAResultsWrapper):
     pass
-wrap.populate_wrapper(ARIMAResultsWrapper, ARIMAResults)  # noqa:E305
-
-
-if __name__ == "__main__":
-    import statsmodels.api as sm
-
-    # simulate arma process
-    from statsmodels.tsa.arima_process import arma_generate_sample
-    y = arma_generate_sample([1., -.75], [1., .25], nsample=1000)
-    arma = ARMA(y)
-    res = arma.fit(trend='nc', order=(1, 1))
-
-    np.random.seed(12345)
-    y_arma22 = arma_generate_sample([1., -.85, .35], [1, .25, -.9],
-                                    nsample=1000)
-    arma22 = ARMA(y_arma22)
-    res22 = arma22.fit(trend='nc', order=(2, 2))
 
-    # test CSS
-    arma22_css = ARMA(y_arma22)
-    res22css = arma22_css.fit(trend='nc', order=(2, 2), method='css')
 
-    data = sm.datasets.sunspots.load(as_pandas=False)
-    ar = ARMA(data.endog)
-    resar = ar.fit(trend='nc', order=(9, 0))
-
-    y_arma31 = arma_generate_sample([1, -.75, -.35, .25], [.1],
-                                    nsample=1000)
-
-    arma31css = ARMA(y_arma31)
-    res31css = arma31css.fit(order=(3, 1), method="css", trend="nc",
-                             transparams=True)
-
-    y_arma13 = arma_generate_sample([1., -.75], [1, .25, -.5, .8],
-                                    nsample=1000)
-    arma13css = ARMA(y_arma13)
-    res13css = arma13css.fit(order=(1, 3), method='css', trend='nc')
-
-# check css for p < q and q < p
-    y_arma41 = arma_generate_sample([1., -.75, .35, .25, -.3], [1, -.35],
-                                    nsample=1000)
-    arma41css = ARMA(y_arma41)
-    res41css = arma41css.fit(order=(4, 1), trend='nc', method='css')
-
-    y_arma14 = arma_generate_sample([1, -.25], [1., -.75, .35, .25, -.3],
-                                    nsample=1000)
-    arma14css = ARMA(y_arma14)
-    res14css = arma14css.fit(order=(4, 1), trend='nc', method='css')
-
-    # ARIMA Model
-    from statsmodels.datasets import webuse
-    dta = webuse('wpi1')
-    wpi = dta['wpi']
-
-    mod = ARIMA(wpi, (1, 1, 1)).fit()
+wrap.populate_wrapper(ARIMAResultsWrapper, ARIMAResults)  # noqa:E305


Test patch:
diff --git a/statsmodels/tsa/tests/test_ar.py b/statsmodels/tsa/tests/test_ar.py
--- a/statsmodels/tsa/tests/test_ar.py
+++ b/statsmodels/tsa/tests/test_ar.py
@@ -4,7 +4,7 @@
 import numpy as np
 import numpy.testing as npt
 import pytest
-from numpy.testing import (assert_almost_equal, assert_allclose, assert_)
+from numpy.testing import assert_almost_equal, assert_allclose
 from pandas import Series, Index, date_range, period_range
 
 import statsmodels.api as sm
@@ -17,6 +17,8 @@
 DECIMAL_5 = 5
 DECIMAL_4 = 4
 
+# TODO: test likelihood for ARX model?
+
 
 class CheckARMixin(object):
     def test_params(self):
@@ -38,9 +40,9 @@ def test_fpe(self):
     def test_pickle(self):
         from io import BytesIO
         fh = BytesIO()
-        #test wrapped results load save pickle
+        # test wrapped results load save pickle
         self.res1.save(fh)
-        fh.seek(0,0)
+        fh.seek(0, 0)
         res_unpickled = self.res1.__class__.load(fh)
         assert type(res_unpickled) is type(self.res1)  # noqa: E721
 
@@ -48,11 +50,16 @@ def test_pickle(self):
     def test_summary(self):
         assert isinstance(self.res1.summary().as_text(), str)
 
+    @pytest.mark.smoke
+    def test_pvalues(self):
+        assert isinstance(self.res1.pvalues, np.ndarray)
+
 
 class TestAROLSConstant(CheckARMixin):
     """
     Test AR fit by OLS with a constant.
     """
+
     @classmethod
     def setup_class(cls):
         data = sm.datasets.sunspots.load(as_pandas=False)
@@ -62,34 +69,33 @@ def setup_class(cls):
     def test_predict(self):
         model = self.res1.model
         params = self.res1.params
-        assert_almost_equal(model.predict(params),self.res2.FVOLSnneg1start0,
-                DECIMAL_4)
-        assert_almost_equal(model.predict(params),self.res2.FVOLSnneg1start9,
-                DECIMAL_4)
+        assert_almost_equal(model.predict(params), self.res2.FVOLSnneg1start0,
+                            DECIMAL_4)
+        assert_almost_equal(model.predict(params), self.res2.FVOLSnneg1start9,
+                            DECIMAL_4)
         assert_almost_equal(model.predict(params, start=100),
-                self.res2.FVOLSnneg1start100, DECIMAL_4)
+                            self.res2.FVOLSnneg1start100, DECIMAL_4)
         assert_almost_equal(model.predict(params, start=9, end=200),
-                self.res2.FVOLSn200start0, DECIMAL_4)
+                            self.res2.FVOLSn200start0, DECIMAL_4)
         assert_almost_equal(model.predict(params, start=200, end=400),
-                self.res2.FVOLSn200start200, DECIMAL_4)
-        #assert_almost_equal(model.predict(params, n=200,start=-109),
-        #        self.res2.FVOLSn200startneg109, DECIMAL_4)
+                            self.res2.FVOLSn200start200, DECIMAL_4)
         assert_almost_equal(model.predict(params, start=308, end=424),
-                self.res2.FVOLSn100start325, DECIMAL_4)
+                            self.res2.FVOLSn100start325, DECIMAL_4)
         assert_almost_equal(model.predict(params, start=9, end=310),
-                self.res2.FVOLSn301start9, DECIMAL_4)
+                            self.res2.FVOLSn301start9, DECIMAL_4)
         assert_almost_equal(model.predict(params),
-                self.res2.FVOLSdefault, DECIMAL_4)
+                            self.res2.FVOLSdefault, DECIMAL_4)
         assert_almost_equal(model.predict(params, start=308, end=316),
-                self.res2.FVOLSn4start312, DECIMAL_4)
+                            self.res2.FVOLSn4start312, DECIMAL_4)
         assert_almost_equal(model.predict(params, start=308, end=327),
-                self.res2.FVOLSn15start312, DECIMAL_4)
+                            self.res2.FVOLSn15start312, DECIMAL_4)
 
 
 class TestAROLSNoConstant(CheckARMixin):
     """f
     Test AR fit by OLS without a constant.
     """
+
     @classmethod
     def setup_class(cls):
         data = sm.datasets.sunspots.load(as_pandas=False)
@@ -99,28 +105,26 @@ def setup_class(cls):
     def test_predict(self):
         model = self.res1.model
         params = self.res1.params
-        assert_almost_equal(model.predict(params),self.res2.FVOLSnneg1start0,
-                DECIMAL_4)
-        assert_almost_equal(model.predict(params),self.res2.FVOLSnneg1start9,
-                DECIMAL_4)
+        assert_almost_equal(model.predict(params), self.res2.FVOLSnneg1start0,
+                            DECIMAL_4)
+        assert_almost_equal(model.predict(params), self.res2.FVOLSnneg1start9,
+                            DECIMAL_4)
         assert_almost_equal(model.predict(params, start=100),
-                self.res2.FVOLSnneg1start100, DECIMAL_4)
+                            self.res2.FVOLSnneg1start100, DECIMAL_4)
         assert_almost_equal(model.predict(params, start=9, end=200),
-                self.res2.FVOLSn200start0, DECIMAL_4)
+                            self.res2.FVOLSn200start0, DECIMAL_4)
         assert_almost_equal(model.predict(params, start=200, end=400),
-                self.res2.FVOLSn200start200, DECIMAL_4)
-        #assert_almost_equal(model.predict(params, n=200,start=-109),
-        #        self.res2.FVOLSn200startneg109, DECIMAL_4)
-        assert_almost_equal(model.predict(params, start=308,end=424),
-                self.res2.FVOLSn100start325, DECIMAL_4)
+                            self.res2.FVOLSn200start200, DECIMAL_4)
+        assert_almost_equal(model.predict(params, start=308, end=424),
+                            self.res2.FVOLSn100start325, DECIMAL_4)
         assert_almost_equal(model.predict(params, start=9, end=310),
-                self.res2.FVOLSn301start9, DECIMAL_4)
+                            self.res2.FVOLSn301start9, DECIMAL_4)
         assert_almost_equal(model.predict(params),
-                self.res2.FVOLSdefault, DECIMAL_4)
+                            self.res2.FVOLSdefault, DECIMAL_4)
         assert_almost_equal(model.predict(params, start=308, end=316),
-                self.res2.FVOLSn4start312, DECIMAL_4)
+                            self.res2.FVOLSn4start312, DECIMAL_4)
         assert_almost_equal(model.predict(params, start=308, end=327),
-                self.res2.FVOLSn15start312, DECIMAL_4)
+                            self.res2.FVOLSn15start312, DECIMAL_4)
 
     def test_mle(self):
         # check predict with no constant, #3945
@@ -140,47 +144,47 @@ class TestARMLEConstant(object):
     @classmethod
     def setup_class(cls):
         data = sm.datasets.sunspots.load(as_pandas=False)
-        cls.res1 = AR(data.endog).fit(maxlag=9,method="mle", disp=-1)
+        cls.res1 = AR(data.endog).fit(maxlag=9, method="mle", disp=-1)
         cls.res2 = results_ar.ARResultsMLE(constant=True)
 
     def test_predict(self):
         model = self.res1.model
         # for some reason convergence is off in 1 out of 10 runs on
         # some platforms. i've never been able to replicate. see #910
-        params = np.array([ 5.66817602,  1.16071069, -0.39538222,
-                           -0.16634055,  0.15044614, -0.09439266,
-                           0.00906289,  0.05205291, -0.08584362,
+        params = np.array([5.66817602, 1.16071069, -0.39538222,
+                           -0.16634055, 0.15044614, -0.09439266,
+                           0.00906289, 0.05205291, -0.08584362,
                            0.25239198])
         assert_almost_equal(model.predict(params), self.res2.FVMLEdefault,
-                DECIMAL_4)
+                            DECIMAL_4)
         assert_almost_equal(model.predict(params, start=9, end=308),
-                self.res2.FVMLEstart9end308, DECIMAL_4)
+                            self.res2.FVMLEstart9end308, DECIMAL_4)
         assert_almost_equal(model.predict(params, start=100, end=308),
-                self.res2.FVMLEstart100end308, DECIMAL_4)
+                            self.res2.FVMLEstart100end308, DECIMAL_4)
         assert_almost_equal(model.predict(params, start=0, end=200),
-                self.res2.FVMLEstart0end200, DECIMAL_4)
+                            self.res2.FVMLEstart0end200, DECIMAL_4)
 
         # Note: factor 0.5 in below two tests needed to meet precision on OS X.
         assert_almost_equal(0.5 * model.predict(params, start=200, end=333),
-                0.5 * self.res2.FVMLEstart200end334, DECIMAL_4)
+                            0.5 * self.res2.FVMLEstart200end334, DECIMAL_4)
         assert_almost_equal(0.5 * model.predict(params, start=308, end=333),
-                0.5 * self.res2.FVMLEstart308end334, DECIMAL_4)
+                            0.5 * self.res2.FVMLEstart308end334, DECIMAL_4)
 
-        assert_almost_equal(model.predict(params, start=9,end=309),
-                self.res2.FVMLEstart9end309, DECIMAL_4)
+        assert_almost_equal(model.predict(params, start=9, end=309),
+                            self.res2.FVMLEstart9end309, DECIMAL_4)
         assert_almost_equal(model.predict(params, end=301),
-                self.res2.FVMLEstart0end301, DECIMAL_4)
+                            self.res2.FVMLEstart0end301, DECIMAL_4)
         assert_almost_equal(model.predict(params, start=4, end=312),
-                self.res2.FVMLEstart4end312, DECIMAL_4)
+                            self.res2.FVMLEstart4end312, DECIMAL_4)
         assert_almost_equal(model.predict(params, start=2, end=7),
-                self.res2.FVMLEstart2end7, DECIMAL_4)
+                            self.res2.FVMLEstart2end7, DECIMAL_4)
 
     def test_dynamic_predict(self):
         # for some reason convergence is off in 1 out of 10 runs on
         # some platforms. i've never been able to replicate. see #910
-        params = np.array([ 5.66817602,  1.16071069, -0.39538222,
-                           -0.16634055,  0.15044614, -0.09439266,
-                           0.00906289,  0.05205291, -0.08584362,
+        params = np.array([5.66817602, 1.16071069, -0.39538222,
+                           -0.16634055, 0.15044614, -0.09439266,
+                           0.00906289, 0.05205291, -0.08584362,
                            0.25239198])
         res1 = self.res1
         res2 = self.res2
@@ -188,53 +192,43 @@ def test_dynamic_predict(self):
         rtol = 8e-6
         # assert_raises pre-sample
 
-        # 9, 51
         start, end = 9, 51
         fv = res1.model.predict(params, start, end, dynamic=True)
-        assert_allclose(fv, res2.fcdyn[start:end+1], rtol=rtol)
+        assert_allclose(fv, res2.fcdyn[start:end + 1], rtol=rtol)
 
-        # 9, 308
         start, end = 9, 308
         fv = res1.model.predict(params, start, end, dynamic=True)
-        assert_allclose(fv, res2.fcdyn[start:end+1], rtol=rtol)
+        assert_allclose(fv, res2.fcdyn[start:end + 1], rtol=rtol)
 
-        # 9, 333
         start, end = 9, 333
         fv = res1.model.predict(params, start, end, dynamic=True)
-        assert_allclose(fv, res2.fcdyn[start:end+1], rtol=rtol)
+        assert_allclose(fv, res2.fcdyn[start:end + 1], rtol=rtol)
 
-        # 100, 151
         start, end = 100, 151
         fv = res1.model.predict(params, start, end, dynamic=True)
-        assert_allclose(fv, res2.fcdyn2[start:end+1], rtol=rtol)
+        assert_allclose(fv, res2.fcdyn2[start:end + 1], rtol=rtol)
 
-        # 100, 308
         start, end = 100, 308
         fv = res1.model.predict(params, start, end, dynamic=True)
-        assert_allclose(fv, res2.fcdyn2[start:end+1], rtol=rtol)
+        assert_allclose(fv, res2.fcdyn2[start:end + 1], rtol=rtol)
 
-        # 100, 333
         start, end = 100, 333
         fv = res1.model.predict(params, start, end, dynamic=True)
-        assert_allclose(fv, res2.fcdyn2[start:end+1], rtol=rtol)
+        assert_allclose(fv, res2.fcdyn2[start:end + 1], rtol=rtol)
 
-        # 308, 308
         start, end = 308, 308
         fv = res1.model.predict(params, start, end, dynamic=True)
-        assert_allclose(fv, res2.fcdyn3[start:end+1], rtol=rtol)
+        assert_allclose(fv, res2.fcdyn3[start:end + 1], rtol=rtol)
 
-        # 308, 333
         start, end = 308, 333
         fv = res1.model.predict(params, start, end, dynamic=True)
-        assert_allclose(fv, res2.fcdyn3[start:end+1], rtol=rtol)
+        assert_allclose(fv, res2.fcdyn3[start:end + 1], rtol=rtol)
 
-        # 309, 333
         start, end = 309, 333
         fv = res1.model.predict(params, start, end, dynamic=True)
-        assert_allclose(fv, res2.fcdyn4[start:end+1], rtol=rtol)
+        assert_allclose(fv, res2.fcdyn4[start:end + 1], rtol=rtol)
 
-        # None, None
-        start, end = None, None
+        # start, end = None, None
         fv = res1.model.predict(params, dynamic=True)
         assert_allclose(fv, res2.fcdyn[9:309], rtol=rtol)
 
@@ -245,8 +239,8 @@ def setup_class(cls):
         data = sm.datasets.sunspots.load(as_pandas=False)
         endog = data.endog
         results = []
-        for lag in range(1,16+1):
-            endog_tmp = endog[16-lag:]
+        for lag in range(1, 16 + 1):
+            endog_tmp = endog[16 - lag:]
             r = AR(endog_tmp).fit(maxlag=lag)
             # See issue #324 for why we're doing these corrections vs. R
             # results
@@ -254,25 +248,24 @@ def setup_class(cls):
             k_trend = r.k_trend
             log_sigma2 = np.log(r.sigma2)
             aic = r.aic
-            aic = (aic - log_sigma2) * (1 + k_ar)/(1 + k_ar + k_trend)
+            aic = (aic - log_sigma2) * (1 + k_ar) / (1 + k_ar + k_trend)
             aic += log_sigma2
 
             hqic = r.hqic
-            hqic = (hqic - log_sigma2) * (1 + k_ar)/(1 + k_ar + k_trend)
+            hqic = (hqic - log_sigma2) * (1 + k_ar) / (1 + k_ar + k_trend)
             hqic += log_sigma2
 
             bic = r.bic
-            bic = (bic - log_sigma2) * (1 + k_ar)/(1 + k_ar + k_trend)
+            bic = (bic - log_sigma2) * (1 + k_ar) / (1 + k_ar + k_trend)
             bic += log_sigma2
 
             results.append([aic, hqic, bic, r.fpe])
-        res1 = np.asarray(results).T.reshape(4,-1, order='C')
+        res1 = np.asarray(results).T.reshape(4, -1, order='C')
         # aic correction to match R
         cls.res1 = res1
         cls.res2 = results_ar.ARLagResults("const").ic
 
     def test_ic(self):
-
         npt.assert_almost_equal(self.res1, self.res2, DECIMAL_6)
 
 
@@ -293,16 +286,16 @@ def test_ar_named_series(reset_randomstate):
     dates = period_range(start="2011-1", periods=72, freq='M')
     y = Series(np.random.randn(72), name="foobar", index=dates)
     results = sm.tsa.AR(y).fit(2)
-    assert_(results.params.index.equals(Index(["const", "L1.foobar",
-                                               "L2.foobar"])))
+    idx = Index(["const", "L1.foobar", "L2.foobar"])
+    assert results.params.index.equals(idx)
 
 
 @pytest.mark.smoke
 def test_ar_start_params():
     # fix GH#236
     data = sm.datasets.sunspots.load(as_pandas=False)
-    res = AR(data.endog).fit(maxlag=9, start_params=0.1*np.ones(10),
-                             method="mle", disp=-1, maxiter=100)
+    AR(data.endog).fit(maxlag=9, start_params=0.1 * np.ones(10),
+                       method="mle", disp=-1, maxiter=100)
 
 
 @pytest.mark.smoke
@@ -323,7 +316,7 @@ def test_ar_select_order():
                                     freq='M'))
     ar = AR(ts)
     res = ar.select_order(maxlag=12, ic='aic')
-    assert_(res == 2)
+    assert res == 2
 
 
 # GH 2658
@@ -381,17 +374,83 @@ def test_summary_corner():
     assert 'AR(0)' in summ
 
 
+def test_at_repeated_fit():
+    data = sm.datasets.sunspots.load_pandas()
+    ar = AR(data.endog)
+    ar.fit()
+    with pytest.raises(RuntimeError):
+        ar.fit(maxlag=1)
+    with pytest.raises(RuntimeError):
+        ar.fit(method='mle')
+    with pytest.raises(RuntimeError):
+        ar.fit(ic='aic')
+    with pytest.raises(RuntimeError):
+        ar.fit(trend='nc')
+
+
+def test_ar_errors(reset_randomstate):
+    with pytest.raises(ValueError, match='Only the univariate case'):
+        AR(np.empty((1000, 2)))
+    ar = AR(np.random.standard_normal(1000))
+    with pytest.raises(ValueError, match='Method yw not'):
+        ar.fit(method='yw')
+    with pytest.raises(ValueError, match='ic option fpic not'):
+        ar.fit(ic='fpic')
+    res = ar.fit()
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res.predict(start=0)
+    with pytest.raises(ValueError, match='Prediction must have `end` after'):
+        res.predict(start=100, end=99)
+    with pytest.raises(ValueError, match='Length of start params'):
+        AR(np.random.standard_normal(1000)).fit(maxlag=2, method='mle',
+                                                start_params=[1, 1])
+
+
+@pytest.mark.smoke
+def test_ar_score():
+    data = sm.datasets.sunspots.load_pandas()
+    ar = AR(np.asarray(data.endog))
+    res = ar.fit(3)
+    score = ar.score(res.params)
+    assert isinstance(score, np.ndarray)
+    assert score.shape == (4,)
+    assert ar.information(res.params) is None
+
+
+@pytest.mark.smoke
+def test_bestlag_stop():
+    data = sm.datasets.sunspots.load_pandas()
+    ar = AR(np.asarray(data.endog))
+    ar.fit(2, ic='t-stat')
+    assert ar.k_ar == 2
+
+
+def test_roots():
+    data = sm.datasets.sunspots.load_pandas()
+    ar = AR(np.asarray(data.endog))
+    res = ar.fit(1)
+    assert_almost_equal(res.roots, np.array([1. / res.params[-1]]))
+
+
+def test_resids_mle():
+    data = sm.datasets.sunspots.load_pandas()
+    ar = AR(np.asarray(data.endog))
+    res = ar.fit(1, method='mle')
+    assert res.resid.shape[0] == data.endog.shape[0]
 
-#TODO: likelihood for ARX model?
-#class TestAutolagARX(object):
-#    def setup(self):
-#        data = sm.datasets.macrodata.load(as_pandas=False)
-#        endog = data.data.realgdp
-#        exog = data.data.realint
-#        results = []
-#        for lag in range(1, 26):
-#            endog_tmp = endog[26-lag:]
-#            exog_tmp = exog[26-lag:]
-#            r = AR(endog_tmp, exog_tmp).fit(maxlag=lag, trend='ct')
-#            results.append([r.aic, r.hqic, r.bic, r.fpe])
-#        self.res1 = np.asarray(results).T.reshape(4,-1, order='C')
+
+def test_ar_repeated_fit():
+    data = sm.datasets.sunspots.load(as_pandas=False)
+    mod = AR(data.endog)
+    res = mod.fit(maxlag=2,  method="cmle")
+    repeat = mod.fit(maxlag=2, method="cmle")
+    assert_allclose(res.params, repeat.params)
+    assert isinstance(res.summary().as_text(), str)
+    assert isinstance(repeat.summary().as_text(), str)
+
+
+def test_ar_predict_no_fit():
+    data = sm.datasets.sunspots.load(as_pandas=False)
+    mod = AR(data.endog)
+    with pytest.raises(RuntimeError, match='Model must be fit'):
+        mod.predict([.1])
diff --git a/statsmodels/tsa/tests/test_arima.py b/statsmodels/tsa/tests/test_arima.py
--- a/statsmodels/tsa/tests/test_arima.py
+++ b/statsmodels/tsa/tests/test_arima.py
@@ -1,28 +1,28 @@
+from statsmodels.compat.platform import (PLATFORM_OSX, PLATFORM_WIN,
+                                         PLATFORM_WIN32)
 from statsmodels.compat.python import lrange
-from statsmodels.compat.platform import PLATFORM_OSX, PLATFORM_WIN
 
-from io import BytesIO
-import pickle
 import os
+import pickle
 import warnings
+from io import BytesIO
 
 import numpy as np
-from numpy.testing import (assert_almost_equal, assert_, assert_allclose,
-                           assert_raises)
 import pandas as pd
-from pandas import DatetimeIndex, date_range, period_range
 import pytest
+from numpy.testing import assert_almost_equal, assert_allclose, assert_raises
+from pandas import DatetimeIndex, date_range, period_range
 
-from statsmodels.datasets.macrodata import load_pandas as load_macrodata_pandas
 import statsmodels.sandbox.tsa.fftarma as fa
-from statsmodels.tools.testing import assert_equal
+from statsmodels.datasets.macrodata import load_pandas as load_macrodata_pandas
+from statsmodels.regression.linear_model import OLS
 from statsmodels.tools.sm_exceptions import (
     ValueWarning, HessianInversionWarning, SpecificationWarning)
-from statsmodels.tsa.arma_mle import Arma
+from statsmodels.tools.testing import assert_equal
 from statsmodels.tsa.arima_model import AR, ARMA, ARIMA
-from statsmodels.regression.linear_model import OLS
-from statsmodels.tsa.tests.results import results_arma, results_arima
 from statsmodels.tsa.arima_process import arma_generate_sample
+from statsmodels.tsa.arma_mle import Arma
+from statsmodels.tsa.tests.results import results_arma, results_arima
 
 DECIMAL_4 = 4
 DECIMAL_3 = 3
@@ -41,40 +41,31 @@
 
 
 def test_compare_arma():
-    #this is a preliminary test to compare arma_kf, arma_cond_ls and arma_cond_mle
-    #the results returned by the fit methods are incomplete
-    #for now without random.seed
+    # this is a preliminary test to compare arma_kf, arma_cond_ls
+    # and arma_cond_mle
+    # the results returned by the fit methods are incomplete
+    # for now without random.seed
 
     np.random.seed(9876565)
     x = fa.ArmaFft([1, -0.5], [1., 0.4], 40).generate_sample(nsample=200,
-            burnin=1000)
-
-    # this used kalman filter through descriptive
-    #d = ARMA(x)
-    #d.fit((1,1), trend='nc')
-    #dres = d.res
+                                                             burnin=1000)
 
-    modkf = ARMA(x, (1,1))
-    ##rkf = mkf.fit((1,1))
-    ##rkf.params
+    modkf = ARMA(x, (1, 1))
     reskf = modkf.fit(trend='nc', disp=-1)
     dres = reskf
 
     modc = Arma(x)
-    resls = modc.fit(order=(1,1))
-    rescm = modc.fit_mle(order=(1,1), start_params=[0.4,0.4, 1.], disp=0)
+    resls = modc.fit(order=(1, 1))
+    rescm = modc.fit_mle(order=(1, 1), start_params=[0.4, 0.4, 1.], disp=0)
 
-    #decimal 1 corresponds to threshold of 5% difference
-    #still different sign  corrcted
-    #assert_almost_equal(np.abs(resls[0] / d.params), np.ones(d.params.shape), decimal=1)
+    # decimal 1 corresponds to threshold of 5% difference
+    # still different sign  corrcted
     assert_almost_equal(resls[0] / dres.params, np.ones(dres.params.shape),
-        decimal=1)
-    #rescm also contains variance estimate as last element of params
+                        decimal=1)
 
-    #assert_almost_equal(np.abs(rescm.params[:-1] / d.params), np.ones(d.params.shape), decimal=1)
+    # rescm also contains variance estimate as last element of params
     assert_almost_equal(rescm.params[:-1] / dres.params,
                         np.ones(dres.params.shape), decimal=1)
-    #return resls[0], d.params, rescm.params
 
 
 class CheckArmaResultsMixin(object):
@@ -86,7 +77,7 @@ class CheckArmaResultsMixin(object):
 
     def test_params(self):
         assert_almost_equal(self.res1.params, self.res2.params,
-                self.decimal_params)
+                            self.decimal_params)
 
     decimal_aic = DECIMAL_4
 
@@ -102,13 +93,13 @@ def test_bic(self):
 
     def test_arroots(self):
         assert_almost_equal(self.res1.arroots, self.res2.arroots,
-                    self.decimal_arroots)
+                            self.decimal_arroots)
 
     decimal_maroots = DECIMAL_4
 
     def test_maroots(self):
         assert_almost_equal(self.res1.maroots, self.res2.maroots,
-                    self.decimal_maroots)
+                            self.decimal_maroots)
 
     decimal_bse = DECIMAL_2
 
@@ -119,7 +110,7 @@ def test_bse(self):
 
     def test_covparams(self):
         assert_almost_equal(self.res1.cov_params(), self.res2.cov_params,
-                self.decimal_cov_params)
+                            self.decimal_cov_params)
 
     decimal_hqic = DECIMAL_4
 
@@ -135,21 +126,21 @@ def test_llf(self):
 
     def test_resid(self):
         assert_almost_equal(self.res1.resid, self.res2.resid,
-                self.decimal_resid)
+                            self.decimal_resid)
 
     decimal_fittedvalues = DECIMAL_4
 
     def test_fittedvalues(self):
         assert_almost_equal(self.res1.fittedvalues, self.res2.fittedvalues,
-                self.decimal_fittedvalues)
+                            self.decimal_fittedvalues)
 
     decimal_pvalues = DECIMAL_2
 
     def test_pvalues(self):
         assert_almost_equal(self.res1.pvalues, self.res2.pvalues,
-                    self.decimal_pvalues)
+                            self.decimal_pvalues)
 
-    decimal_t = DECIMAL_2 # only 2 decimal places in gretl output
+    decimal_t = DECIMAL_2  # only 2 decimal places in gretl output
 
     def test_tvalues(self):
         assert_almost_equal(self.res1.tvalues, self.res2.tvalues,
@@ -159,25 +150,29 @@ def test_tvalues(self):
 
     def test_sigma2(self):
         assert_almost_equal(self.res1.sigma2, self.res2.sigma2,
-                self.decimal_sigma2)
+                            self.decimal_sigma2)
 
     @pytest.mark.smoke
     def test_summary(self):
         self.res1.summary()
 
+    @pytest.mark.smoke
+    def test_summary2(self):
+        self.res1.summary2()
+
 
 class CheckForecastMixin(object):
     decimal_forecast = DECIMAL_4
 
     def test_forecast(self):
         assert_almost_equal(self.res1.forecast_res, self.res2.forecast,
-                self.decimal_forecast)
+                            self.decimal_forecast)
 
     decimal_forecasterr = DECIMAL_4
 
     def test_forecasterr(self):
         assert_almost_equal(self.res1.forecast_err, self.res2.forecasterr,
-                self.decimal_forecasterr)
+                            self.decimal_forecasterr)
 
 
 class CheckDynamicForecastMixin(object):
@@ -203,23 +198,23 @@ def test_order(self):
 
     def test_predict_levels(self):
         assert_almost_equal(self.res1.predict(typ='levels'), self.res2.linear,
-                self.decimal_predict_levels)
+                            self.decimal_predict_levels)
 
 
 class Test_Y_ARMA11_NoConst(CheckArmaResultsMixin, CheckForecastMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,0]
-        cls.res1 = ARMA(endog, order=(1,1)).fit(trend='nc', disp=-1)
+        endog = y_arma[:, 0]
+        cls.res1 = ARMA(endog, order=(1, 1)).fit(trend='nc', disp=-1)
         (cls.res1.forecast_res, cls.res1.forecast_err,
-                confint) = cls.res1.forecast(10)
+         confint) = cls.res1.forecast(10)
         cls.res2 = results_arma.Y_arma11()
 
     def test_pickle(self):
         fh = BytesIO()
-        #test wrapped results load save pickle
+        # test wrapped results load save pickle
         self.res1.save(fh)
-        fh.seek(0,0)
+        fh.seek(0, 0)
         res_unpickled = self.res1.__class__.load(fh)
         assert type(res_unpickled) is type(self.res1)  # noqa: E721
 
@@ -227,8 +222,8 @@ def test_pickle(self):
 class Test_Y_ARMA14_NoConst(CheckArmaResultsMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,1]
-        cls.res1 = ARMA(endog, order=(1,4)).fit(trend='nc', disp=-1)
+        endog = y_arma[:, 1]
+        cls.res1 = ARMA(endog, order=(1, 4)).fit(trend='nc', disp=-1)
         cls.res2 = results_arma.Y_arma14()
 
 
@@ -236,10 +231,10 @@ def setup_class(cls):
 class Test_Y_ARMA41_NoConst(CheckArmaResultsMixin, CheckForecastMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,2]
-        cls.res1 = ARMA(endog, order=(4,1)).fit(trend='nc', disp=-1)
+        endog = y_arma[:, 2]
+        cls.res1 = ARMA(endog, order=(4, 1)).fit(trend='nc', disp=-1)
         (cls.res1.forecast_res, cls.res1.forecast_err,
-                confint) = cls.res1.forecast(10)
+         confint) = cls.res1.forecast(10)
         cls.res2 = results_arma.Y_arma41()
         cls.decimal_maroots = DECIMAL_3
 
@@ -247,56 +242,56 @@ def setup_class(cls):
 class Test_Y_ARMA22_NoConst(CheckArmaResultsMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,3]
-        cls.res1 = ARMA(endog, order=(2,2)).fit(trend='nc', disp=-1)
+        endog = y_arma[:, 3]
+        cls.res1 = ARMA(endog, order=(2, 2)).fit(trend='nc', disp=-1)
         cls.res2 = results_arma.Y_arma22()
 
 
 class Test_Y_ARMA50_NoConst(CheckArmaResultsMixin, CheckForecastMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,4]
-        cls.res1 = ARMA(endog, order=(5,0)).fit(trend='nc', disp=-1)
+        endog = y_arma[:, 4]
+        cls.res1 = ARMA(endog, order=(5, 0)).fit(trend='nc', disp=-1)
         (cls.res1.forecast_res, cls.res1.forecast_err,
-                confint) = cls.res1.forecast(10)
+         confint) = cls.res1.forecast(10)
         cls.res2 = results_arma.Y_arma50()
 
 
 class Test_Y_ARMA02_NoConst(CheckArmaResultsMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,5]
-        cls.res1 = ARMA(endog, order=(0,2)).fit(trend='nc', disp=-1)
+        endog = y_arma[:, 5]
+        cls.res1 = ARMA(endog, order=(0, 2)).fit(trend='nc', disp=-1)
         cls.res2 = results_arma.Y_arma02()
 
 
 class Test_Y_ARMA11_Const(CheckArmaResultsMixin, CheckForecastMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,6]
-        cls.res1 = ARMA(endog, order=(1,1)).fit(trend="c", disp=-1)
+        endog = y_arma[:, 6]
+        cls.res1 = ARMA(endog, order=(1, 1)).fit(trend="c", disp=-1)
         (cls.res1.forecast_res, cls.res1.forecast_err,
-                confint) = cls.res1.forecast(10)
+         confint) = cls.res1.forecast(10)
         cls.res2 = results_arma.Y_arma11c()
 
 
 class Test_Y_ARMA14_Const(CheckArmaResultsMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,7]
-        cls.res1 = ARMA(endog, order=(1,4)).fit(trend="c", disp=-1)
+        endog = y_arma[:, 7]
+        cls.res1 = ARMA(endog, order=(1, 4)).fit(trend="c", disp=-1)
         cls.res2 = results_arma.Y_arma14c()
 
 
 class Test_Y_ARMA41_Const(CheckArmaResultsMixin, CheckForecastMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,8]
+        endog = y_arma[:, 8]
         cls.res2 = results_arma.Y_arma41c()
-        cls.res1 = ARMA(endog, order=(4,1)).fit(trend="c", disp=-1,
-                                                start_params=cls.res2.params)
+        cls.res1 = ARMA(endog, order=(4, 1)).fit(trend="c", disp=-1,
+                                                 start_params=cls.res2.params)
         (cls.res1.forecast_res, cls.res1.forecast_err,
-                confint) = cls.res1.forecast(10)
+         confint) = cls.res1.forecast(10)
         cls.decimal_cov_params = DECIMAL_3
         cls.decimal_fittedvalues = DECIMAL_3
         cls.decimal_resid = DECIMAL_3
@@ -306,8 +301,8 @@ def setup_class(cls):
 class Test_Y_ARMA22_Const(CheckArmaResultsMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,9]
-        cls.res1 = ARMA(endog, order=(2,2)).fit(trend="c", disp=-1)
+        endog = y_arma[:, 9]
+        cls.res1 = ARMA(endog, order=(2, 2)).fit(trend="c", disp=-1)
         cls.res2 = results_arma.Y_arma22c()
 
     def test_summary(self):
@@ -340,18 +335,18 @@ def test_summary(self):
 class Test_Y_ARMA50_Const(CheckArmaResultsMixin, CheckForecastMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,10]
-        cls.res1 = ARMA(endog, order=(5,0)).fit(trend="c", disp=-1)
+        endog = y_arma[:, 10]
+        cls.res1 = ARMA(endog, order=(5, 0)).fit(trend="c", disp=-1)
         (cls.res1.forecast_res, cls.res1.forecast_err,
-                confint) = cls.res1.forecast(10)
+         confint) = cls.res1.forecast(10)
         cls.res2 = results_arma.Y_arma50c()
 
 
 class Test_Y_ARMA02_Const(CheckArmaResultsMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,11]
-        cls.res1 = ARMA(endog, order=(0,2)).fit(trend="c", disp=-1)
+        endog = y_arma[:, 11]
+        cls.res1 = ARMA(endog, order=(0, 2)).fit(trend="c", disp=-1)
         cls.res2 = results_arma.Y_arma02c()
 
 
@@ -359,9 +354,9 @@ def setup_class(cls):
 class Test_Y_ARMA11_NoConst_CSS(CheckArmaResultsMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,0]
-        cls.res1 = ARMA(endog, order=(1,1)).fit(method="css", trend='nc',
-                            disp=-1)
+        endog = y_arma[:, 0]
+        cls.res1 = ARMA(endog, order=(1, 1)).fit(method="css", trend='nc',
+                                                 disp=-1)
         cls.res2 = results_arma.Y_arma11("css")
         cls.decimal_t = DECIMAL_1
 
@@ -370,9 +365,9 @@ def setup_class(cls):
 class Test_Y_ARMA14_NoConst_CSS(CheckArmaResultsMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,1]
-        cls.res1 = ARMA(endog, order=(1,4)).fit(method="css", trend='nc',
-                            disp=-1)
+        endog = y_arma[:, 1]
+        cls.res1 = ARMA(endog, order=(1, 4)).fit(method="css", trend='nc',
+                                                 disp=-1)
         cls.res2 = results_arma.Y_arma14("css")
         cls.decimal_fittedvalues = DECIMAL_3
         cls.decimal_resid = DECIMAL_3
@@ -384,9 +379,9 @@ def setup_class(cls):
 class Test_Y_ARMA41_NoConst_CSS(CheckArmaResultsMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,2]
-        cls.res1 = ARMA(endog, order=(4,1)).fit(method="css", trend='nc',
-                        disp=-1)
+        endog = y_arma[:, 2]
+        cls.res1 = ARMA(endog, order=(4, 1)).fit(method="css", trend='nc',
+                                                 disp=-1)
         cls.res2 = results_arma.Y_arma41("css")
         cls.decimal_t = DECIMAL_1
         cls.decimal_pvalues = 0
@@ -394,13 +389,13 @@ def setup_class(cls):
         cls.decimal_maroots = DECIMAL_1
 
 
-#same notes as above
+# same notes as above
 class Test_Y_ARMA22_NoConst_CSS(CheckArmaResultsMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,3]
-        cls.res1 = ARMA(endog, order=(2,2)).fit(method="css", trend='nc',
-                            disp=-1)
+        endog = y_arma[:, 3]
+        cls.res1 = ARMA(endog, order=(2, 2)).fit(method="css", trend='nc',
+                                                 disp=-1)
         cls.res2 = results_arma.Y_arma22("css")
         cls.decimal_t = DECIMAL_1
         cls.decimal_resid = DECIMAL_3
@@ -408,39 +403,39 @@ def setup_class(cls):
         cls.decimal_fittedvalues = DECIMAL_3
 
 
-#NOTE: gretl just uses least squares for AR CSS
+# NOTE: gretl just uses least squares for AR CSS
 # so BIC, etc. is
 # -2*res1.llf + np.log(nobs)*(res1.q+res1.p+res1.k)
 # with no adjustment for p and no extra sigma estimate
-#NOTE: so our tests use x-12 arima results which agree with us and are
+# NOTE: so our tests use x-12 arima results which agree with us and are
 # consistent with the rest of the models
 class Test_Y_ARMA50_NoConst_CSS(CheckArmaResultsMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,4]
-        cls.res1 = ARMA(endog, order=(5,0)).fit(method="css", trend='nc',
-                            disp=-1)
+        endog = y_arma[:, 4]
+        cls.res1 = ARMA(endog, order=(5, 0)).fit(method="css", trend='nc',
+                                                 disp=-1)
         cls.res2 = results_arma.Y_arma50("css")
         cls.decimal_t = 0
-        cls.decimal_llf = DECIMAL_1 # looks like rounding error?
+        cls.decimal_llf = DECIMAL_1  # looks like rounding error?
 
 
 class Test_Y_ARMA02_NoConst_CSS(CheckArmaResultsMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,5]
-        cls.res1 = ARMA(endog, order=(0,2)).fit(method="css", trend='nc',
-                            disp=-1)
+        endog = y_arma[:, 5]
+        cls.res1 = ARMA(endog, order=(0, 2)).fit(method="css", trend='nc',
+                                                 disp=-1)
         cls.res2 = results_arma.Y_arma02("css")
 
 
-#NOTE: our results are close to --x-12-arima option and R
+# NOTE: our results are close to --x-12-arima option and R
 class Test_Y_ARMA11_Const_CSS(CheckArmaResultsMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,6]
-        cls.res1 = ARMA(endog, order=(1,1)).fit(trend="c", method="css",
-                        disp=-1)
+        endog = y_arma[:, 6]
+        cls.res1 = ARMA(endog, order=(1, 1)).fit(trend="c", method="css",
+                                                 disp=-1)
         cls.res2 = results_arma.Y_arma11c("css")
         cls.decimal_params = DECIMAL_3
         cls.decimal_cov_params = DECIMAL_3
@@ -450,9 +445,9 @@ def setup_class(cls):
 class Test_Y_ARMA14_Const_CSS(CheckArmaResultsMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,7]
-        cls.res1 = ARMA(endog, order=(1,4)).fit(trend="c", method="css",
-                        disp=-1)
+        endog = y_arma[:, 7]
+        cls.res1 = ARMA(endog, order=(1, 4)).fit(trend="c", method="css",
+                                                 disp=-1)
         cls.res2 = results_arma.Y_arma14c("css")
         cls.decimal_t = DECIMAL_1
         cls.decimal_pvalues = DECIMAL_1
@@ -461,9 +456,9 @@ def setup_class(cls):
 class Test_Y_ARMA41_Const_CSS(CheckArmaResultsMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,8]
-        cls.res1 = ARMA(endog, order=(4,1)).fit(trend="c", method="css",
-                        disp=-1)
+        endog = y_arma[:, 8]
+        cls.res1 = ARMA(endog, order=(4, 1)).fit(trend="c", method="css",
+                                                 disp=-1)
         cls.res2 = results_arma.Y_arma41c("css")
         cls.decimal_t = DECIMAL_1
         cls.decimal_cov_params = DECIMAL_1
@@ -474,9 +469,9 @@ def setup_class(cls):
 class Test_Y_ARMA22_Const_CSS(CheckArmaResultsMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,9]
-        cls.res1 = ARMA(endog, order=(2,2)).fit(trend="c", method="css",
-                        disp=-1)
+        endog = y_arma[:, 9]
+        cls.res1 = ARMA(endog, order=(2, 2)).fit(trend="c", method="css",
+                                                 disp=-1)
         cls.res2 = results_arma.Y_arma22c("css")
         cls.decimal_t = 0
         cls.decimal_pvalues = DECIMAL_1
@@ -485,9 +480,9 @@ def setup_class(cls):
 class Test_Y_ARMA50_Const_CSS(CheckArmaResultsMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,10]
-        cls.res1 = ARMA(endog, order=(5,0)).fit(trend="c", method="css",
-                        disp=-1)
+        endog = y_arma[:, 10]
+        cls.res1 = ARMA(endog, order=(5, 0)).fit(trend="c", method="css",
+                                                 disp=-1)
         cls.res2 = results_arma.Y_arma50c("css")
         cls.decimal_t = DECIMAL_1
         cls.decimal_params = DECIMAL_3
@@ -497,95 +492,152 @@ def setup_class(cls):
 class Test_Y_ARMA02_Const_CSS(CheckArmaResultsMixin):
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,11]
-        cls.res1 = ARMA(endog, order=(0,2)).fit(trend="c", method="css",
-                        disp=-1)
+        endog = y_arma[:, 11]
+        cls.res1 = ARMA(endog, order=(0, 2)).fit(trend="c", method="css",
+                                                 disp=-1)
         cls.res2 = results_arma.Y_arma02c("css")
 
 
-def test_reset_trend():
-    endog = y_arma[:,0]
-    mod = ARMA(endog, order=(1,1))
-    res1 = mod.fit(trend="c", disp=-1)
-    res2 = mod.fit(trend="nc", disp=-1)
-    assert_equal(len(res1.params), len(res2.params)+1)
+def test_reset_trend_error():
+    endog = y_arma[:, 0]
+    mod = ARMA(endog, order=(1, 1))
+    mod.fit(trend="c", disp=-1)
+    with pytest.raises(RuntimeError):
+        mod.fit(trend="nc", disp=-1)
 
 
 @pytest.mark.slow
 def test_start_params_bug():
     data = np.array([1368., 1187, 1090, 1439, 2362, 2783, 2869, 2512, 1804,
-    1544, 1028, 869, 1737, 2055, 1947, 1618, 1196, 867, 997, 1862, 2525,
-    3250, 4023, 4018, 3585, 3004, 2500, 2441, 2749, 2466, 2157, 1847, 1463,
-    1146, 851, 993, 1448, 1719, 1709, 1455, 1950, 1763, 2075, 2343, 3570,
-    4690, 3700, 2339, 1679, 1466, 998, 853, 835, 922, 851, 1125, 1299, 1105,
-    860, 701, 689, 774, 582, 419, 846, 1132, 902, 1058, 1341, 1551, 1167,
-    975, 786, 759, 751, 649, 876, 720, 498, 553, 459, 543, 447, 415, 377,
-    373, 324, 320, 306, 259, 220, 342, 558, 825, 994, 1267, 1473, 1601,
-    1896, 1890, 2012, 2198, 2393, 2825, 3411, 3406, 2464, 2891, 3685, 3638,
-    3746, 3373, 3190, 2681, 2846, 4129, 5054, 5002, 4801, 4934, 4903, 4713,
-    4745, 4736, 4622, 4642, 4478, 4510, 4758, 4457, 4356, 4170, 4658, 4546,
-    4402, 4183, 3574, 2586, 3326, 3948, 3983, 3997, 4422, 4496, 4276, 3467,
-    2753, 2582, 2921, 2768, 2789, 2824, 2482, 2773, 3005, 3641, 3699, 3774,
-    3698, 3628, 3180, 3306, 2841, 2014, 1910, 2560, 2980, 3012, 3210, 3457,
-    3158, 3344, 3609, 3327, 2913, 2264, 2326, 2596, 2225, 1767, 1190, 792,
-    669, 589, 496, 354, 246, 250, 323, 495, 924, 1536, 2081, 2660, 2814, 2992,
-    3115, 2962, 2272, 2151, 1889, 1481, 955, 631, 288, 103, 60, 82, 107, 185,
-    618, 1526, 2046, 2348, 2584, 2600, 2515, 2345, 2351, 2355, 2409, 2449,
-    2645, 2918, 3187, 2888, 2610, 2740, 2526, 2383, 2936, 2968, 2635, 2617,
-    2790, 3906, 4018, 4797, 4919, 4942, 4656, 4444, 3898, 3908, 3678, 3605,
-    3186, 2139, 2002, 1559, 1235, 1183, 1096, 673, 389, 223, 352, 308, 365,
-    525, 779, 894, 901, 1025, 1047, 981, 902, 759, 569, 519, 408, 263, 156,
-    72, 49, 31, 41, 192, 423, 492, 552, 564, 723, 921, 1525, 2768, 3531, 3824,
-    3835, 4294, 4533, 4173, 4221, 4064, 4641, 4685, 4026, 4323, 4585, 4836,
-    4822, 4631, 4614, 4326, 4790, 4736, 4104, 5099, 5154, 5121, 5384, 5274,
-    5225, 4899, 5382, 5295, 5349, 4977, 4597, 4069, 3733, 3439, 3052, 2626,
-    1939, 1064, 713, 916, 832, 658, 817, 921, 772, 764, 824, 967, 1127, 1153,
-    824, 912, 957, 990, 1218, 1684, 2030, 2119, 2233, 2657, 2652, 2682, 2498,
-    2429, 2346, 2298, 2129, 1829, 1816, 1225, 1010, 748, 627, 469, 576, 532,
-    475, 582, 641, 605, 699, 680, 714, 670, 666, 636, 672, 679, 446, 248, 134,
-    160, 178, 286, 413, 676, 1025, 1159, 952, 1398, 1833, 2045, 2072, 1798,
-    1799, 1358, 727, 353, 347, 844, 1377, 1829, 2118, 2272, 2745, 4263, 4314,
-    4530, 4354, 4645, 4547, 5391, 4855, 4739, 4520, 4573, 4305, 4196, 3773,
-    3368, 2596, 2596, 2305, 2756, 3747, 4078, 3415, 2369, 2210, 2316, 2263,
-    2672, 3571, 4131, 4167, 4077, 3924, 3738, 3712, 3510, 3182, 3179, 2951,
-    2453, 2078, 1999, 2486, 2581, 1891, 1997, 1366, 1294, 1536, 2794, 3211,
-    3242, 3406, 3121, 2425, 2016, 1787, 1508, 1304, 1060, 1342, 1589, 2361,
-    3452, 2659, 2857, 3255, 3322, 2852, 2964, 3132, 3033, 2931, 2636, 2818,
-    3310, 3396, 3179, 3232, 3543, 3759, 3503, 3758, 3658, 3425, 3053, 2620,
-    1837, 923, 712, 1054, 1376, 1556, 1498, 1523, 1088, 728, 890, 1413, 2524,
-    3295, 4097, 3993, 4116, 3874, 4074, 4142, 3975, 3908, 3907, 3918, 3755,
-    3648, 3778, 4293, 4385, 4360, 4352, 4528, 4365, 3846, 4098, 3860, 3230,
-    2820, 2916, 3201, 3721, 3397, 3055, 2141, 1623, 1825, 1716, 2232, 2939,
-    3735, 4838, 4560, 4307, 4975, 5173, 4859, 5268, 4992, 5100, 5070, 5270,
-    4760, 5135, 5059, 4682, 4492, 4933, 4737, 4611, 4634, 4789, 4811, 4379,
-    4689, 4284, 4191, 3313, 2770, 2543, 3105, 2967, 2420, 1996, 2247, 2564,
-    2726, 3021, 3427, 3509, 3759, 3324, 2988, 2849, 2340, 2443, 2364, 1252,
-    623, 742, 867, 684, 488, 348, 241, 187, 279, 355, 423, 678, 1375, 1497,
-    1434, 2116, 2411, 1929, 1628, 1635, 1609, 1757, 2090, 2085, 1790, 1846,
-    2038, 2360, 2342, 2401, 2920, 3030, 3132, 4385, 5483, 5865, 5595, 5485,
-    5727, 5553, 5560, 5233, 5478, 5159, 5155, 5312, 5079, 4510, 4628, 4535,
-    3656, 3698, 3443, 3146, 2562, 2304, 2181, 2293, 1950, 1930, 2197, 2796,
-    3441, 3649, 3815, 2850, 4005, 5305, 5550, 5641, 4717, 5131, 2831, 3518,
-    3354, 3115, 3515, 3552, 3244, 3658, 4407, 4935, 4299, 3166, 3335, 2728,
-    2488, 2573, 2002, 1717, 1645, 1977, 2049, 2125, 2376, 2551, 2578, 2629,
-    2750, 3150, 3699, 4062, 3959, 3264, 2671, 2205, 2128, 2133, 2095, 1964,
-    2006, 2074, 2201, 2506, 2449, 2465, 2064, 1446, 1382, 983, 898, 489, 319,
-    383, 332, 276, 224, 144, 101, 232, 429, 597, 750, 908, 960, 1076, 951,
-    1062, 1183, 1404, 1391, 1419, 1497, 1267, 963, 682, 777, 906, 1149, 1439,
-    1600, 1876, 1885, 1962, 2280, 2711, 2591, 2411])
+                     1544, 1028, 869, 1737, 2055, 1947, 1618, 1196, 867, 997,
+                     1862, 2525,
+                     3250, 4023, 4018, 3585, 3004, 2500, 2441, 2749, 2466,
+                     2157, 1847, 1463,
+                     1146, 851, 993, 1448, 1719, 1709, 1455, 1950, 1763, 2075,
+                     2343, 3570,
+                     4690, 3700, 2339, 1679, 1466, 998, 853, 835, 922, 851,
+                     1125, 1299, 1105,
+                     860, 701, 689, 774, 582, 419, 846, 1132, 902, 1058, 1341,
+                     1551, 1167,
+                     975, 786, 759, 751, 649, 876, 720, 498, 553, 459, 543,
+                     447, 415, 377,
+                     373, 324, 320, 306, 259, 220, 342, 558, 825, 994, 1267,
+                     1473, 1601,
+                     1896, 1890, 2012, 2198, 2393, 2825, 3411, 3406, 2464,
+                     2891, 3685, 3638,
+                     3746, 3373, 3190, 2681, 2846, 4129, 5054, 5002, 4801,
+                     4934, 4903, 4713,
+                     4745, 4736, 4622, 4642, 4478, 4510, 4758, 4457, 4356,
+                     4170, 4658, 4546,
+                     4402, 4183, 3574, 2586, 3326, 3948, 3983, 3997, 4422,
+                     4496, 4276, 3467,
+                     2753, 2582, 2921, 2768, 2789, 2824, 2482, 2773, 3005,
+                     3641, 3699, 3774,
+                     3698, 3628, 3180, 3306, 2841, 2014, 1910, 2560, 2980,
+                     3012, 3210, 3457,
+                     3158, 3344, 3609, 3327, 2913, 2264, 2326, 2596, 2225,
+                     1767, 1190, 792,
+                     669, 589, 496, 354, 246, 250, 323, 495, 924, 1536, 2081,
+                     2660, 2814, 2992,
+                     3115, 2962, 2272, 2151, 1889, 1481, 955, 631, 288, 103,
+                     60, 82, 107, 185,
+                     618, 1526, 2046, 2348, 2584, 2600, 2515, 2345, 2351, 2355,
+                     2409, 2449,
+                     2645, 2918, 3187, 2888, 2610, 2740, 2526, 2383, 2936,
+                     2968, 2635, 2617,
+                     2790, 3906, 4018, 4797, 4919, 4942, 4656, 4444, 3898,
+                     3908, 3678, 3605,
+                     3186, 2139, 2002, 1559, 1235, 1183, 1096, 673, 389, 223,
+                     352, 308, 365,
+                     525, 779, 894, 901, 1025, 1047, 981, 902, 759, 569, 519,
+                     408, 263, 156,
+                     72, 49, 31, 41, 192, 423, 492, 552, 564, 723, 921, 1525,
+                     2768, 3531, 3824,
+                     3835, 4294, 4533, 4173, 4221, 4064, 4641, 4685, 4026,
+                     4323, 4585, 4836,
+                     4822, 4631, 4614, 4326, 4790, 4736, 4104, 5099, 5154,
+                     5121, 5384, 5274,
+                     5225, 4899, 5382, 5295, 5349, 4977, 4597, 4069, 3733,
+                     3439, 3052, 2626,
+                     1939, 1064, 713, 916, 832, 658, 817, 921, 772, 764, 824,
+                     967, 1127, 1153,
+                     824, 912, 957, 990, 1218, 1684, 2030, 2119, 2233, 2657,
+                     2652, 2682, 2498,
+                     2429, 2346, 2298, 2129, 1829, 1816, 1225, 1010, 748, 627,
+                     469, 576, 532,
+                     475, 582, 641, 605, 699, 680, 714, 670, 666, 636, 672,
+                     679, 446, 248, 134,
+                     160, 178, 286, 413, 676, 1025, 1159, 952, 1398, 1833,
+                     2045, 2072, 1798,
+                     1799, 1358, 727, 353, 347, 844, 1377, 1829, 2118, 2272,
+                     2745, 4263, 4314,
+                     4530, 4354, 4645, 4547, 5391, 4855, 4739, 4520, 4573,
+                     4305, 4196, 3773,
+                     3368, 2596, 2596, 2305, 2756, 3747, 4078, 3415, 2369,
+                     2210, 2316, 2263,
+                     2672, 3571, 4131, 4167, 4077, 3924, 3738, 3712, 3510,
+                     3182, 3179, 2951,
+                     2453, 2078, 1999, 2486, 2581, 1891, 1997, 1366, 1294,
+                     1536, 2794, 3211,
+                     3242, 3406, 3121, 2425, 2016, 1787, 1508, 1304, 1060,
+                     1342, 1589, 2361,
+                     3452, 2659, 2857, 3255, 3322, 2852, 2964, 3132, 3033,
+                     2931, 2636, 2818,
+                     3310, 3396, 3179, 3232, 3543, 3759, 3503, 3758, 3658,
+                     3425, 3053, 2620,
+                     1837, 923, 712, 1054, 1376, 1556, 1498, 1523, 1088, 728,
+                     890, 1413, 2524,
+                     3295, 4097, 3993, 4116, 3874, 4074, 4142, 3975, 3908,
+                     3907, 3918, 3755,
+                     3648, 3778, 4293, 4385, 4360, 4352, 4528, 4365, 3846,
+                     4098, 3860, 3230,
+                     2820, 2916, 3201, 3721, 3397, 3055, 2141, 1623, 1825,
+                     1716, 2232, 2939,
+                     3735, 4838, 4560, 4307, 4975, 5173, 4859, 5268, 4992,
+                     5100, 5070, 5270,
+                     4760, 5135, 5059, 4682, 4492, 4933, 4737, 4611, 4634,
+                     4789, 4811, 4379,
+                     4689, 4284, 4191, 3313, 2770, 2543, 3105, 2967, 2420,
+                     1996, 2247, 2564,
+                     2726, 3021, 3427, 3509, 3759, 3324, 2988, 2849, 2340,
+                     2443, 2364, 1252,
+                     623, 742, 867, 684, 488, 348, 241, 187, 279, 355, 423,
+                     678, 1375, 1497,
+                     1434, 2116, 2411, 1929, 1628, 1635, 1609, 1757, 2090,
+                     2085, 1790, 1846,
+                     2038, 2360, 2342, 2401, 2920, 3030, 3132, 4385, 5483,
+                     5865, 5595, 5485,
+                     5727, 5553, 5560, 5233, 5478, 5159, 5155, 5312, 5079,
+                     4510, 4628, 4535,
+                     3656, 3698, 3443, 3146, 2562, 2304, 2181, 2293, 1950,
+                     1930, 2197, 2796,
+                     3441, 3649, 3815, 2850, 4005, 5305, 5550, 5641, 4717,
+                     5131, 2831, 3518,
+                     3354, 3115, 3515, 3552, 3244, 3658, 4407, 4935, 4299,
+                     3166, 3335, 2728,
+                     2488, 2573, 2002, 1717, 1645, 1977, 2049, 2125, 2376,
+                     2551, 2578, 2629,
+                     2750, 3150, 3699, 4062, 3959, 3264, 2671, 2205, 2128,
+                     2133, 2095, 1964,
+                     2006, 2074, 2201, 2506, 2449, 2465, 2064, 1446, 1382, 983,
+                     898, 489, 319,
+                     383, 332, 276, 224, 144, 101, 232, 429, 597, 750, 908,
+                     960, 1076, 951,
+                     1062, 1183, 1404, 1391, 1419, 1497, 1267, 963, 682, 777,
+                     906, 1149, 1439,
+                     1600, 1876, 1885, 1962, 2280, 2711, 2591, 2411])
     with warnings.catch_warnings():
         warnings.simplefilter("ignore")
-        res = ARMA(data, order=(4,1)).fit(start_ar_lags=5, disp=-1)
+        ARMA(data, order=(4, 1)).fit(start_ar_lags=5, disp=-1)
 
 
 class Test_ARIMA101(CheckArmaResultsMixin):
-    # just make sure this works
     @classmethod
     def setup_class(cls):
-        endog = y_arma[:,6]
-        cls.res1 = ARIMA(endog, (1,0,1)).fit(trend="c", disp=-1)
+        endog = y_arma[:, 6]
+        cls.res1 = ARIMA(endog, (1, 0, 1)).fit(trend="c", disp=-1)
         (cls.res1.forecast_res, cls.res1.forecast_err,
-                confint) = cls.res1.forecast(10)
+         confint) = cls.res1.forecast(10)
         cls.res2 = results_arma.Y_arma11c()
         cls.res2.k_diff = 0
         cls.res2.k_ar = 1
@@ -597,26 +649,27 @@ class Test_ARIMA111(CheckArimaResultsMixin, CheckForecastMixin,
     @classmethod
     def setup_class(cls):
         cpi = load_macrodata_pandas().data['cpi'].values
-        cls.res1 = ARIMA(cpi, (1,1,1)).fit(disp=-1)
+        cls.res1 = ARIMA(cpi, (1, 1, 1)).fit(disp=-1)
         cls.res2 = results_arima.ARIMA111()
         # make sure endog names changes to D.cpi
         cls.decimal_llf = 3
         cls.decimal_aic = 3
         cls.decimal_bic = 3
-        cls.decimal_cov_params = 2 # this used to be better?
+        # TODO: why has dec_cov_params changed, used to be better
+        cls.decimal_cov_params = 2
         cls.decimal_t = 0
         (cls.res1.forecast_res,
          cls.res1.forecast_err,
-         conf_int)              = cls.res1.forecast(25)
-        #cls.res1.forecast_res_dyn = cls.res1.predict(start=164, end=226, typ='levels', dynamic=True)
-        #TODO: fix the indexing for the end here, I do not think this is right
+         conf_int) = cls.res1.forecast(25)
+        # TODO: fix the indexing for the end here, I do not think this is right
         # if we're going to treat it like indexing
         # the forecast from 2005Q1 through 2009Q4 is indices
         # 184 through 227 not 226
         # note that the first one counts in the count so 164 + 64 is 65
         # predictions
-        cls.res1.forecast_res_dyn = cls.res1.predict(start=164, end=164+63,
-                                            typ='levels', dynamic=True)
+        cls.res1.forecast_res_dyn = cls.res1.predict(start=164, end=164 + 63,
+                                                     typ='levels',
+                                                     dynamic=True)
 
     def test_freq(self):
         assert_almost_equal(self.res1.arfreq, [0.0000], 4)
@@ -628,18 +681,19 @@ class Test_ARIMA111CSS(CheckArimaResultsMixin, CheckForecastMixin,
     @classmethod
     def setup_class(cls):
         cpi = load_macrodata_pandas().data['cpi'].values
-        cls.res1 = ARIMA(cpi, (1,1,1)).fit(disp=-1, method='css')
+        cls.res1 = ARIMA(cpi, (1, 1, 1)).fit(disp=-1, method='css')
         cls.res2 = results_arima.ARIMA111(method='css')
         cls.res2.fittedvalues = - cpi[1:-1] + cls.res2.linear
         # make sure endog names changes to D.cpi
         (cls.res1.forecast_res,
          cls.res1.forecast_err,
-         conf_int)              = cls.res1.forecast(25)
+         conf_int) = cls.res1.forecast(25)
         cls.decimal_forecast = 2
         cls.decimal_forecast_dyn = 2
         cls.decimal_forecasterr = 3
-        cls.res1.forecast_res_dyn = cls.res1.predict(start=164, end=164+63,
-                                                 typ='levels', dynamic=True)
+        cls.res1.forecast_res_dyn = cls.res1.predict(start=164, end=164 + 63,
+                                                     typ='levels',
+                                                     dynamic=True)
 
         # precisions
         cls.decimal_arroots = 3
@@ -647,11 +701,8 @@ def setup_class(cls):
         cls.decimal_hqic = 3
         cls.decimal_maroots = 3
         cls.decimal_t = 1
-        cls.decimal_fittedvalues = 2 # because of rounding when copying
+        cls.decimal_fittedvalues = 2  # because of rounding when copying
         cls.decimal_resid = 2
-        #cls.decimal_llf = 3
-        #cls.decimal_aic = 3
-        #cls.decimal_bic = 3
         cls.decimal_predict_levels = DECIMAL_2
 
 
@@ -659,26 +710,23 @@ class Test_ARIMA112CSS(CheckArimaResultsMixin):
     @classmethod
     def setup_class(cls):
         cpi = load_macrodata_pandas().data['cpi'].values
-        cls.res1 = ARIMA(cpi, (1,1,2)).fit(disp=-1, method='css',
-                                start_params = [.905322, -.692425, 1.07366,
-                                                0.172024])
+        cls.res1 = ARIMA(cpi, (1, 1, 2)).fit(disp=-1, method='css',
+                                             start_params=[.905322, -.692425,
+                                                           1.07366,
+                                                           0.172024])
         cls.res2 = results_arima.ARIMA112(method='css')
         cls.res2.fittedvalues = - cpi[1:-1] + cls.res2.linear
         # make sure endog names changes to D.cpi
         cls.decimal_llf = 3
         cls.decimal_aic = 3
         cls.decimal_bic = 3
-        #(cls.res1.forecast_res,
-        # cls.res1.forecast_err,
-        # conf_int)              = cls.res1.forecast(25)
-        #cls.res1.forecast_res_dyn = cls.res1.predict(start=164, end=226, typ='levels', dynamic=True)
-        #TODO: fix the indexing for the end here, I do not think this is right
+        # TODO: fix the indexing for the end here, I do not think this is right
         # if we're going to treat it like indexing
         # the forecast from 2005Q1 through 2009Q4 is indices
         # 184 through 227 not 226
         # note that the first one counts in the count so 164 + 64 is 65
         # predictions
-        #cls.res1.forecast_res_dyn = self.predict(start=164, end=164+63,
+        # cls.res1.forecast_res_dyn = self.predict(start=164, end=164+63,
         #                                         typ='levels', dynamic=True)
         # since we got from gretl do not have linear prediction in differences
         cls.decimal_arroots = 3
@@ -692,258 +740,250 @@ def test_freq(self):
         assert_almost_equal(self.res1.arfreq, [0.5000], 4)
         assert_almost_equal(self.res1.mafreq, [0.5000, 0.5000], 4)
 
-#class Test_ARIMADates(CheckArmaResults, CheckForecast, CheckDynamicForecast):
-#    @classmethod
-#    def setup_class(cls):
-#        cpi = load_macrodata_pandas().data['cpi'].values
-#        dates = pd.date_range('1959', periods=203, freq='Q')
-#        cls.res1 = ARIMA(cpi, dates=dates, freq='Q').fit(order=(1,1,1), disp=-1)
-#        cls.res2 = results_arima.ARIMA111()
-#        # make sure endog names changes to D.cpi
-#        cls.decimal_llf = 3
-#        cls.decimal_aic = 3
-#        cls.decimal_bic = 3
-#        (cls.res1.forecast_res,
-#         cls.res1.forecast_err,
-#         conf_int)              = cls.res1.forecast(25)
-
 
 def test_arima_predict_mle_dates():
     cpi = load_macrodata_pandas().data['cpi'].values
-    res1 = ARIMA(cpi, (4,1,1), dates=cpi_dates, freq='Q').fit(disp=-1)
+    res1 = ARIMA(cpi, (4, 1, 1), dates=cpi_dates, freq='Q').fit(disp=-1)
+    file_path = os.path.join(current_path, 'results',
+                             'results_arima_forecasts_all_mle.csv')
+    with open(file_path, "rb") as test_data:
+        arima_forecasts = np.genfromtxt(test_data, delimiter=",",
+                                        skip_header=1, dtype=float)
 
-    with open(current_path + '/results/results_arima_forecasts_all_mle.csv', "rb") as test_data:
-        arima_forecasts = np.genfromtxt(test_data, delimiter=",", skip_header=1, dtype=float)
-
-    fc = arima_forecasts[:,0]
-    fcdyn = arima_forecasts[:,1]
-    fcdyn2 = arima_forecasts[:,2]
+    fc = arima_forecasts[:, 0]
+    fcdyn = arima_forecasts[:, 1]
+    fcdyn2 = arima_forecasts[:, 2]
 
     start, end = 2, 51
     fv = res1.predict('1959Q3', '1971Q4', typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
-    assert_equal(res1.data.predict_dates, cpi_dates[start:end+1])
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
+    assert_equal(res1.data.predict_dates, cpi_dates[start:end + 1])
 
     start, end = 202, 227
     fv = res1.predict('2009Q3', '2015Q4', typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     assert_equal(res1.data.predict_dates, cpi_predict_dates)
 
     # make sure dynamic works
 
     start, end = '1960q2', '1971q4'
     fv = res1.predict(start, end, dynamic=True, typ='levels')
-    assert_almost_equal(fv, fcdyn[5:51+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn[5:51 + 1], DECIMAL_4)
 
     start, end = '1965q1', '2015q4'
     fv = res1.predict(start, end, dynamic=True, typ='levels')
-    assert_almost_equal(fv, fcdyn2[24:227+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn2[24:227 + 1], DECIMAL_4)
 
 
 def test_arma_predict_mle_dates():
     from statsmodels.datasets.sunspots import load_pandas
     sunspots = load_pandas().data['SUNACTIVITY'].values
-    mod = ARMA(sunspots, (9,0), dates=sun_dates, freq='A')
+    mod = ARMA(sunspots, (9, 0), dates=sun_dates, freq='A')
     mod.method = 'mle'
 
-    assert_raises(ValueError, mod._get_prediction_index, *('1701', '1751', True))
+    assert_raises(ValueError, mod._get_prediction_index, '1701', '1751', True)
 
     start, end = 2, 51
-    _, _, _, _ = mod._get_prediction_index('1702', '1751', False)
-    assert_equal(mod.data.predict_dates, sun_dates[start:end+1])
+    mod._get_prediction_index('1702', '1751', False)
+    assert_equal(mod.data.predict_dates, sun_dates[start:end + 1])
 
     start, end = 308, 333
-    _, _, _, _ = mod._get_prediction_index('2008', '2033', False)
+    mod._get_prediction_index('2008', '2033', False)
     assert_equal(mod.data.predict_dates, sun_predict_dates)
 
 
 def test_arima_predict_css_dates():
     cpi = load_macrodata_pandas().data['cpi'].values
-    res1 = ARIMA(cpi, (4,1,1), dates=cpi_dates, freq='Q').fit(disp=-1,
-            method='css', trend='nc')
+    res1 = ARIMA(cpi, (4, 1, 1), dates=cpi_dates, freq='Q').fit(disp=-1,
+                                                                method='css',
+                                                                trend='nc')
 
-    params = np.array([ 1.231272508473910,
+    params = np.array([1.231272508473910,
                        -0.282516097759915,
-                        0.170052755782440,
+                       0.170052755782440,
                        -0.118203728504945,
                        -0.938783134717947])
+    file_path = os.path.join(current_path, 'results',
+                             'results_arima_forecasts_all_css.csv')
+    with open(file_path, "rb") as test_data:
+        arima_forecasts = np.genfromtxt(test_data, delimiter=",",
+                                        skip_header=1, dtype=float)
 
-    with open(current_path + '/results/results_arima_forecasts_all_css.csv', "rb") as test_data:
-        arima_forecasts = np.genfromtxt(test_data, delimiter=",", skip_header=1, dtype=float)
-
-    fc = arima_forecasts[:,0]
-    fcdyn = arima_forecasts[:,1]
-    fcdyn2 = arima_forecasts[:,2]
+    fc = arima_forecasts[:, 0]
+    fcdyn = arima_forecasts[:, 1]
+    fcdyn2 = arima_forecasts[:, 2]
 
     start, end = 5, 51
     fv = res1.model.predict(params, '1960Q2', '1971Q4', typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
-    assert_equal(res1.data.predict_dates, cpi_dates[start:end+1])
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
+    assert_equal(res1.data.predict_dates, cpi_dates[start:end + 1])
 
     start, end = 202, 227
     fv = res1.model.predict(params, '2009Q3', '2015Q4', typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     assert_equal(res1.data.predict_dates, cpi_predict_dates)
 
     # make sure dynamic works
     start, end = 5, 51
     fv = res1.model.predict(params, '1960Q2', '1971Q4', typ='levels',
-                                                        dynamic=True)
-    assert_almost_equal(fv, fcdyn[start:end+1], DECIMAL_4)
+                            dynamic=True)
+    assert_almost_equal(fv, fcdyn[start:end + 1], DECIMAL_4)
 
     start, end = '1965q1', '2015q4'
     fv = res1.model.predict(params, start, end, dynamic=True, typ='levels')
-    assert_almost_equal(fv, fcdyn2[24:227+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn2[24:227 + 1], DECIMAL_4)
 
 
 def test_arma_predict_css_dates():
     from statsmodels.datasets.sunspots import load_pandas
     sunspots = load_pandas().data['SUNACTIVITY'].values
-    mod = ARMA(sunspots, (9,0), dates=sun_dates, freq='A')
+    mod = ARMA(sunspots, (9, 0), dates=sun_dates, freq='A')
     mod.method = 'css'
-    assert_raises(ValueError, mod._get_prediction_index, *('1701', '1751', False))
+    assert_raises(ValueError, mod._get_prediction_index, '1701', '1751', False)
 
 
 def test_arima_predict_mle():
     cpi = load_macrodata_pandas().data['cpi'].values
-    res1 = ARIMA(cpi, (4,1,1)).fit(disp=-1)
+    res1 = ARIMA(cpi, (4, 1, 1)).fit(disp=-1)
     # fit the model so that we get correct endog length but use
-    with open(current_path + '/results/results_arima_forecasts_all_mle.csv', "rb") as test_data:
-        arima_forecasts = np.genfromtxt(test_data, delimiter=",", skip_header=1, dtype=float)
-    fc = arima_forecasts[:,0]
-    fcdyn = arima_forecasts[:,1]
-    fcdyn2 = arima_forecasts[:,2]
-    fcdyn3 = arima_forecasts[:,3]
-    fcdyn4 = arima_forecasts[:,4]
+    file_path = os.path.join(current_path, 'results',
+                             'results_arima_forecasts_all_mle.csv')
+    with open(file_path, "rb") as test_data:
+        arima_forecasts = np.genfromtxt(test_data, delimiter=",",
+                                        skip_header=1, dtype=float)
+    fc = arima_forecasts[:, 0]
+    fcdyn = arima_forecasts[:, 1]
+    fcdyn2 = arima_forecasts[:, 2]
+    fcdyn3 = arima_forecasts[:, 3]
+    fcdyn4 = arima_forecasts[:, 4]
 
     # 0 indicates the first sample-observation below
     # ie., the index after the pre-sample, these are also differenced once
     # so the indices are moved back once from the cpi in levels
     # start < p, end <p 1959q2 - 1959q4
-    start, end = 1,3
+    start, end = 1, 3
     fv = res1.predict(start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start < p, end 0 1959q3 - 1960q1
     start, end = 2, 4
     fv = res1.predict(start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start < p, end >0 1959q3 - 1971q4
     start, end = 2, 51
     fv = res1.predict(start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start < p, end nobs 1959q3 - 2009q3
     start, end = 2, 202
     fv = res1.predict(start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start < p, end >nobs 1959q3 - 2015q4
     start, end = 2, 227
     fv = res1.predict(start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start 0, end >0 1960q1 - 1971q4
     start, end = 4, 51
     fv = res1.predict(start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start 0, end nobs 1960q1 - 2009q3
     start, end = 4, 202
     fv = res1.predict(start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start 0, end >nobs 1960q1 - 2015q4
     start, end = 4, 227
     fv = res1.predict(start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start >p, end >0 1965q1 - 1971q4
     start, end = 24, 51
     fv = res1.predict(start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start >p, end nobs 1965q1 - 2009q3
     start, end = 24, 202
     fv = res1.predict(start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start >p, end >nobs 1965q1 - 2015q4
     start, end = 24, 227
     fv = res1.predict(start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start nobs, end nobs 2009q3 - 2009q3
-    #NOTE: raises
-    #start, end = 202, 202
-    #fv = res1.predict(start, end, typ='levels')
-    #assert_almost_equal(fv, [])
+    start, end = 202, 202
+    fv = res1.predict(start, end, typ='levels')
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_3)
     # start nobs, end >nobs 2009q3 - 2015q4
     start, end = 202, 227
     fv = res1.predict(start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_3)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_3)
     # start >nobs, end >nobs 2009q4 - 2015q4
-    #NOTE: this raises but should not, dynamic forecasts could start
-    #one period out
     start, end = 203, 227
     fv = res1.predict(start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # defaults
     start, end = None, None
     fv = res1.predict(start, end, typ='levels')
     assert_almost_equal(fv, fc[1:203], DECIMAL_4)
 
-    #### Dynamic #####
+    # Dynamic
 
     # start < p, end <p 1959q2 - 1959q4
-    #NOTE: should raise
-    #start, end = 1,3
-    #fv = res1.predict(start, end, dynamic=True, typ='levels')
-    #assert_almost_equal(fv, arima_forecasts[:,15])
+    start, end = 1, 3
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        fv = res1.predict(start, end, dynamic=True, typ='levels')
+
     # start < p, end 0 1959q3 - 1960q1
+    start, end = 2, 4
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.predict(start, end, dynamic=True, typ='levels')
 
-    #NOTE: below should raise an error
-    #start, end = 2, 4
-    #fv = res1.predict(start, end, dynamic=True, typ='levels')
-    #assert_almost_equal(fv, fcdyn[5:end+1], DECIMAL_4)
     # start < p, end >0 1959q3 - 1971q4
-    #start, end = 2, 51
-    #fv = res1.predict(start, end, dynamic=True, typ='levels')
-    #assert_almost_equal(fv, fcdyn[5:end+1], DECIMAL_4)
-    ## start < p, end nobs 1959q3 - 2009q3
-    #start, end = 2, 202
-    #fv = res1.predict(start, end, dynamic=True, typ='levels')
-    #assert_almost_equal(fv, fcdyn[5:end+1], DECIMAL_4)
-    ## start < p, end >nobs 1959q3 - 2015q4
-    #start, end = 2, 227
-    #fv = res1.predict(start, end, dynamic=True, typ='levels')
-    #assert_almost_equal(fv, fcdyn[5:end+1], DECIMAL_4)
+    start, end = 2, 51
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.predict(start, end, dynamic=True, typ='levels')
+
+    # start < p, end nobs 1959q3 - 2009q3
+    start, end = 2, 202
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.predict(start, end, dynamic=True, typ='levels')
+
+    # start < p, end >nobs 1959q3 - 2015q4
+    start, end = 2, 227
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.predict(start, end, dynamic=True, typ='levels')
+
     # start 0, end >0 1960q1 - 1971q4
     start, end = 5, 51
     fv = res1.predict(start, end, dynamic=True, typ='levels')
-    assert_almost_equal(fv, fcdyn[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn[start:end + 1], DECIMAL_4)
     # start 0, end nobs 1960q1 - 2009q3
     start, end = 5, 202
     fv = res1.predict(start, end, dynamic=True, typ='levels')
-    assert_almost_equal(fv, fcdyn[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn[start:end + 1], DECIMAL_4)
     # start 0, end >nobs 1960q1 - 2015q4
     start, end = 5, 227
     fv = res1.predict(start, end, dynamic=True, typ='levels')
-    assert_almost_equal(fv, fcdyn[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn[start:end + 1], DECIMAL_4)
     # start >p, end >0 1965q1 - 1971q4
     start, end = 24, 51
     fv = res1.predict(start, end, dynamic=True, typ='levels')
-    assert_almost_equal(fv, fcdyn2[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn2[start:end + 1], DECIMAL_4)
     # start >p, end nobs 1965q1 - 2009q3
     start, end = 24, 202
     fv = res1.predict(start, end, dynamic=True, typ='levels')
-    assert_almost_equal(fv, fcdyn2[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn2[start:end + 1], DECIMAL_4)
     # start >p, end >nobs 1965q1 - 2015q4
     start, end = 24, 227
     fv = res1.predict(start, end, dynamic=True, typ='levels')
-    assert_almost_equal(fv, fcdyn2[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn2[start:end + 1], DECIMAL_4)
     # start nobs, end nobs 2009q3 - 2009q3
     start, end = 202, 202
     fv = res1.predict(start, end, dynamic=True, typ='levels')
-    assert_almost_equal(fv, fcdyn3[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn3[start:end + 1], DECIMAL_4)
     # start nobs, end >nobs 2009q3 - 2015q4
     start, end = 202, 227
     fv = res1.predict(start, end, dynamic=True, typ='levels')
-    assert_almost_equal(fv, fcdyn3[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn3[start:end + 1], DECIMAL_4)
     # start >nobs, end >nobs 2009q4 - 2015q4
     start, end = 203, 227
     fv = res1.predict(start, end, dynamic=True, typ='levels')
-    assert_almost_equal(fv, fcdyn4[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn4[start:end + 1], DECIMAL_4)
     # defaults
     start, end = None, None
     fv = res1.predict(start, end, dynamic=True, typ='levels')
@@ -963,49 +1003,48 @@ def _check_end(model, given, end_expect, out_of_sample_expect):
 def test_arma_predict_indices():
     from statsmodels.datasets.sunspots import load_pandas
     sunspots = load_pandas().data['SUNACTIVITY'].values
-    model = ARMA(sunspots, (9,0), dates=sun_dates, freq='A')
+    model = ARMA(sunspots, (9, 0), dates=sun_dates, freq='A')
     model.method = 'mle'
 
     # raises - pre-sample + dynamic
-    assert_raises(ValueError, model._get_prediction_index, *(0, None, True))
-    assert_raises(ValueError, model._get_prediction_index, *(8, None, True))
-    assert_raises(ValueError, model._get_prediction_index, *('1700', None, True))
-    assert_raises(ValueError, model._get_prediction_index, *('1708', None, True))
+    with pytest.raises(ValueError):
+        model._get_prediction_index(0, None, True)
+    with pytest.raises(ValueError):
+        model._get_prediction_index(8, None, True)
+    with pytest.raises(ValueError):
+        model._get_prediction_index('1700', None, True)
+    with pytest.raises(ValueError):
+        model._get_prediction_index('1708', None, True)
 
     # raises - start out of sample
-    # TODO: remove these, start out of sample now allowed
-    # assert_raises(ValueError, model._get_prediction_index, *(311, None, True))
-    # assert_raises(ValueError, model._get_prediction_index, *(311, None, False))
-    # assert_raises(ValueError, model._get_prediction_index, *('2010', None, True))
-    # assert_raises(ValueError, model._get_prediction_index, *('2010', None, False))
 
     # works - in-sample
     # None
     start_test_cases = [
-                  # given, expected, dynamic
-                  (None, 9, True),
-                  # all start get moved back by k_diff
-                  (9, 9, True),
-                  (10, 10, True),
-                  # what about end of sample start - last value is first
-                  # forecast
-                  (309, 309, True),
-                  (308, 308, True),
-                  (0, 0, False),
-                  (1, 1, False),
-                  (4, 4, False),
-
-                  # all start get moved back by k_diff
-                  ('1709', 9, True),
-                  ('1710', 10, True),
-                  # what about end of sample start - last value is first
-                  # forecast
-                  ('2008', 308, True),
-                  ('2009', 309, True),
-                  ('1700', 0, False),
-                  ('1708', 8, False),
-                  ('1709', 9, False),
-                  ]
+        # given, expected, dynamic
+        (None, 9, True),
+        # all start get moved back by k_diff
+        (9, 9, True),
+        (10, 10, True),
+        # what about end of sample start - last value is first
+        # forecast
+        (309, 309, True),
+        (308, 308, True),
+        (0, 0, False),
+        (1, 1, False),
+        (4, 4, False),
+
+        # all start get moved back by k_diff
+        ('1709', 9, True),
+        ('1710', 10, True),
+        # what about end of sample start - last value is first
+        # forecast
+        ('2008', 308, True),
+        ('2009', 309, True),
+        ('1700', 0, False),
+        ('1708', 8, False),
+        ('1709', 9, False),
+    ]
 
     for case in start_test_cases:
         _check_start(*((model,) + case))
@@ -1028,64 +1067,63 @@ def test_arma_predict_indices():
                       ]
 
     for case in end_test_cases:
-        _check_end(*((model,)+case))
+        _check_end(*((model,) + case))
 
 
 def test_arima_predict_indices():
     cpi = load_macrodata_pandas().data['cpi'].values
-    model = ARIMA(cpi, (4,1,1), dates=cpi_dates, freq='Q')
+    model = ARIMA(cpi, (4, 1, 1), dates=cpi_dates, freq='Q')
     model.method = 'mle'
 
     # starting indices
 
     # raises - pre-sample + dynamic
-    assert_raises(ValueError, model._get_prediction_index, *(0, None, True))
-    assert_raises(ValueError, model._get_prediction_index, *(4, None, True))
-    assert_raises(KeyError, model._get_prediction_index, *('1959Q1', None, True))
-    assert_raises(ValueError, model._get_prediction_index, *('1960Q1', None, True))
+    with pytest.raises(ValueError):
+        model._get_prediction_index(0, None, True)
+    with pytest.raises(ValueError):
+        model._get_prediction_index(4, None, True)
+    with pytest.raises(KeyError):
+        model._get_prediction_index('1959Q1', None, True)
+    with pytest.raises(ValueError):
+        model._get_prediction_index('1960Q1', None, True)
 
     # raises - index differenced away
-    assert_raises(ValueError, model._get_prediction_index, *(0, None, False))
-    assert_raises(KeyError, model._get_prediction_index, *('1959Q1', None, False))
+    with pytest.raises(ValueError):
+        model._get_prediction_index(0, None, False)
+    with pytest.raises(KeyError):
+        model._get_prediction_index('1959Q1', None, False)
 
     # raises - start out of sample
-    # TODO: start out of sample is now allowed; remove this code
-    # assert_raises(ValueError, model._get_prediction_index, *(204, None, True))
-    # assert_raises(ValueError, model._get_prediction_index, *(204, None, False))
-    # assert_raises(ValueError, model._get_prediction_index, *('2010Q1', None, True))
-    # assert_raises(ValueError, model._get_prediction_index, *('2010Q1', None, False))
 
     # works - in-sample
     # None
     start_test_cases = [
-                  # given, expected, dynamic
-                  (None, 4, True),
-                  # all start get moved back by k_diff
-                  (5, 4, True),
-                  (6, 5, True),
-                  # what about end of sample start - last value is first
-                  # forecast
-                  (203, 202, True),
-                  (1, 0, False),
-                  (4, 3, False),
-                  (5, 4, False),
-                  # all start get moved back by k_diff
-                  ('1960Q2', 4, True),
-                  ('1960Q3', 5, True),
-                  # what about end of sample start - last value is first
-                  # forecast
-                  ('2009Q4', 202, True),
-                  ('1959Q2', 0, False),
-                  ('1960Q1', 3, False),
-                  ('1960Q2', 4, False),
-                  ]
+        # given, expected, dynamic
+        (None, 4, True),
+        # all start get moved back by k_diff
+        (5, 4, True),
+        (6, 5, True),
+        # what about end of sample start - last value is first
+        # forecast
+        (203, 202, True),
+        (1, 0, False),
+        (4, 3, False),
+        (5, 4, False),
+        # all start get moved back by k_diff
+        ('1960Q2', 4, True),
+        ('1960Q3', 5, True),
+        # what about end of sample start - last value is first
+        # forecast
+        ('2009Q4', 202, True),
+        ('1959Q2', 0, False),
+        ('1960Q1', 3, False),
+        ('1960Q2', 4, False),
+    ]
 
     for case in start_test_cases:
         _check_start(*((model,) + case))
 
-    # check raises
-    #TODO: make sure dates are passing through unmolested
-    #assert_raises(ValueError, model._get_predict_end, ("2001-1-1",))
+    # TODO: make sure dates are passing through unmolested
 
     # the length of diff(cpi) is 202, so last index is 201
     end_test_cases = [(None, 201, 0),
@@ -1094,7 +1132,7 @@ def test_arima_predict_indices():
                       (203, 201, 1),
                       (204, 201, 2),
                       (51, 50, 0),
-                      (164+63, 201, 25),
+                      (164 + 63, 201, 25),
 
                       ('2009Q2', 200, 0),
                       ('2009Q3', 201, 0),
@@ -1105,44 +1143,47 @@ def test_arima_predict_indices():
                       ]
 
     for case in end_test_cases:
-        _check_end(*((model,)+case))
+        _check_end(*((model,) + case))
 
     # check higher k_diff
     # model.k_diff = 2
-    model = ARIMA(cpi, (4,2,1), dates=cpi_dates, freq='Q')
+    model = ARIMA(cpi, (4, 2, 1), dates=cpi_dates, freq='Q')
     model.method = 'mle'
 
     # raises - pre-sample + dynamic
-    assert_raises(ValueError, model._get_prediction_index, *(0, None, True))
-    assert_raises(ValueError, model._get_prediction_index, *(5, None, True))
-    assert_raises(KeyError, model._get_prediction_index, *('1959Q1', None, True))
-    assert_raises(ValueError, model._get_prediction_index, *('1960Q1', None, True))
+    assert_raises(ValueError, model._get_prediction_index, 0, None, True)
+    assert_raises(ValueError, model._get_prediction_index, 5, None, True)
+    assert_raises(KeyError, model._get_prediction_index,
+                  '1959Q1', None, True)
+    assert_raises(ValueError, model._get_prediction_index,
+                  '1960Q1', None, True)
 
     # raises - index differenced away
-    assert_raises(ValueError, model._get_prediction_index, *(1, None, False))
-    assert_raises(KeyError, model._get_prediction_index, *('1959Q2', None, False))
+    assert_raises(ValueError, model._get_prediction_index, 1, None, False)
+    assert_raises(KeyError, model._get_prediction_index,
+                  '1959Q2', None, False)
 
     start_test_cases = [(None, 4, True),
-                  # all start get moved back by k_diff
-                  (6, 4, True),
-                  # what about end of sample start - last value is first
-                  # forecast
-                  (203, 201, True),
-                  (2, 0, False),
-                  (4, 2, False),
-                  (5, 3, False),
-                  ('1960Q3', 4, True),
-                  # what about end of sample start - last value is first
-                  # forecast
-                  ('2009Q4', 201, True),
-                  ('2009Q4', 201, True),
-                  ('1959Q3', 0, False),
-                  ('1960Q1', 2, False),
-                  ('1960Q2', 3, False),
-                  ]
+                        # all start get moved back by k_diff
+                        (6, 4, True),
+                        # what about end of sample start - last value is first
+                        # forecast
+                        (203, 201, True),
+                        (2, 0, False),
+                        (4, 2, False),
+                        (5, 3, False),
+                        ('1960Q3', 4, True),
+                        # what about end of sample start - last value is first
+                        # forecast
+                        ('2009Q4', 201, True),
+                        ('2009Q4', 201, True),
+                        ('1959Q3', 0, False),
+                        ('1960Q1', 2, False),
+                        ('1960Q2', 3, False),
+                        ]
 
     for case in start_test_cases:
-        _check_start(*((model,)+case))
+        _check_start(*((model,) + case))
 
     end_test_cases = [(None, 200, 0),
                       (201, 199, 0),
@@ -1150,7 +1191,7 @@ def test_arima_predict_indices():
                       (203, 200, 1),
                       (204, 200, 2),
                       (51, 49, 0),
-                      (164+63, 200, 25),
+                      (164 + 63, 200, 25),
 
                       ('2009Q2', 199, 0),
                       ('2009Q3', 200, 0),
@@ -1161,154 +1202,164 @@ def test_arima_predict_indices():
                       ]
 
     for case in end_test_cases:
-        _check_end(*((model,)+case))
+        _check_end(*((model,) + case))
 
 
 def test_arima_predict_indices_css():
     cpi = load_macrodata_pandas().data['cpi'].values
-    #NOTE: Doing no-constant for now to kick the conditional exogenous
-    #issue 274 down the road
+    # NOTE: Doing no-constant for now to kick the conditional exogenous
+    # issue 274 down the road
     # go ahead and git the model to set up necessary variables
-    model = ARIMA(cpi, (4,1,1))
+    model = ARIMA(cpi, (4, 1, 1))
     model.method = 'css'
 
-    assert_raises(ValueError, model._get_prediction_index, *(0, None, False))
-    assert_raises(ValueError, model._get_prediction_index, *(0, None, True))
-    assert_raises(ValueError, model._get_prediction_index, *(2, None, False))
-    assert_raises(ValueError, model._get_prediction_index, *(2, None, True))
+    assert_raises(ValueError, model._get_prediction_index, 0, None, False)
+    assert_raises(ValueError, model._get_prediction_index, 0, None, True)
+    assert_raises(ValueError, model._get_prediction_index, 2, None, False)
+    assert_raises(ValueError, model._get_prediction_index, 2, None, True)
 
 
 def test_arima_predict_css():
     cpi = load_macrodata_pandas().data['cpi'].values
-    #NOTE: Doing no-constant for now to kick the conditional exogenous
-    #issue 274 down the road
+    # NOTE: Doing no-constant for now to kick the conditional exogenous
+    # issue 274 down the road
     # go ahead and git the model to set up necessary variables
-    res1 = ARIMA(cpi, (4,1,1)).fit(disp=-1, method="css",
-                            trend="nc")
+    res1 = ARIMA(cpi, (4, 1, 1)).fit(disp=-1, method="css",
+                                     trend="nc")
     # but use gretl parameters to predict to avoid precision problems
-    params = np.array([ 1.231272508473910,
+    params = np.array([1.231272508473910,
                        -0.282516097759915,
                        0.170052755782440,
-                      -0.118203728504945,
-                      -0.938783134717947])
-
-    with open(current_path + '/results/results_arima_forecasts_all_css.csv', "rb") as test_data:
-        arima_forecasts = np.genfromtxt(test_data, delimiter=",", skip_header=1, dtype=float)
-    fc = arima_forecasts[:,0]
-    fcdyn = arima_forecasts[:,1]
-    fcdyn2 = arima_forecasts[:,2]
-    fcdyn3 = arima_forecasts[:,3]
-    fcdyn4 = arima_forecasts[:,4]
-
-    #NOTE: should raise
-    #start, end = 1,3
-    #fv = res1.model.predict(params, start, end)
-    ## start < p, end 0 1959q3 - 1960q1
-    #start, end = 2, 4
-    #fv = res1.model.predict(params, start, end)
-    ## start < p, end >0 1959q3 - 1971q4
-    #start, end = 2, 51
-    #fv = res1.model.predict(params, start, end)
-    ## start < p, end nobs 1959q3 - 2009q3
-    #start, end = 2, 202
-    #fv = res1.model.predict(params, start, end)
-    ## start < p, end >nobs 1959q3 - 2015q4
-    #start, end = 2, 227
-    #fv = res1.model.predict(params, start, end)
+                       -0.118203728504945,
+                       -0.938783134717947])
+    file_path = os.path.join(current_path, 'results',
+                             'results_arima_forecasts_all_css.csv')
+    with open(file_path, "rb") as test_data:
+        arima_forecasts = np.genfromtxt(test_data, delimiter=",",
+                                        skip_header=1, dtype=float)
+    fc = arima_forecasts[:, 0]
+    fcdyn = arima_forecasts[:, 1]
+    fcdyn2 = arima_forecasts[:, 2]
+    fcdyn3 = arima_forecasts[:, 3]
+    fcdyn4 = arima_forecasts[:, 4]
+
+    start, end = 1, 3
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.model.predict(params, start, end)
+    #  start < p, end 0 1959q3 - 1960q1
+    start, end = 2, 4
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.model.predict(params, start, end)
+    #  start < p, end >0 1959q3 - 1971q4
+    start, end = 2, 51
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.model.predict(params, start, end)
+    #  start < p, end nobs 1959q3 - 2009q3
+    start, end = 2, 202
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.model.predict(params, start, end)
+    #  start < p, end >nobs 1959q3 - 2015q4
+    start, end = 2, 227
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.model.predict(params, start, end)
     # start 0, end >0 1960q1 - 1971q4
     start, end = 5, 51
     fv = res1.model.predict(params, start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start 0, end nobs 1960q1 - 2009q3
     start, end = 5, 202
     fv = res1.model.predict(params, start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start 0, end >nobs 1960q1 - 2015q4
-    #TODO: why detoriating precision?
+    # TODO: why detoriating precision?
     fv = res1.model.predict(params, start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start >p, end >0 1965q1 - 1971q4
     start, end = 24, 51
     fv = res1.model.predict(params, start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start >p, end nobs 1965q1 - 2009q3
     start, end = 24, 202
     fv = res1.model.predict(params, start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start >p, end >nobs 1965q1 - 2015q4
     start, end = 24, 227
     fv = res1.model.predict(params, start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start nobs, end nobs 2009q3 - 2009q3
     start, end = 202, 202
     fv = res1.model.predict(params, start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start nobs, end >nobs 2009q3 - 2015q4
     start, end = 202, 227
     fv = res1.model.predict(params, start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start >nobs, end >nobs 2009q4 - 2015q4
     start, end = 203, 227
     fv = res1.model.predict(params, start, end, typ='levels')
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # defaults
     start, end = None, None
     fv = res1.model.predict(params, start, end, typ='levels')
     assert_almost_equal(fv, fc[5:203], DECIMAL_4)
 
-    #### Dynamic #####
+    # Dynamic
 
-    #NOTE: should raise
     # start < p, end <p 1959q2 - 1959q4
-    #start, end = 1,3
-    #fv = res1.predict(start, end, dynamic=True)
+    start, end = 1, 3
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.predict(start, end, dynamic=True)
     # start < p, end 0 1959q3 - 1960q1
-    #start, end = 2, 4
-    #fv = res1.predict(start, end, dynamic=True)
-    ## start < p, end >0 1959q3 - 1971q4
-    #start, end = 2, 51
-    #fv = res1.predict(start, end, dynamic=True)
-    ## start < p, end nobs 1959q3 - 2009q3
-    #start, end = 2, 202
-    #fv = res1.predict(start, end, dynamic=True)
-    ## start < p, end >nobs 1959q3 - 2015q4
-    #start, end = 2, 227
-    #fv = res1.predict(start, end, dynamic=True)
+    start, end = 2, 4
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.predict(start, end, dynamic=True)
+    #  start < p, end >0 1959q3 - 1971q4
+    start, end = 2, 51
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.predict(start, end, dynamic=True)
+    #  start < p, end nobs 1959q3 - 2009q3
+    start, end = 2, 202
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.predict(start, end, dynamic=True)
+    #  start < p, end >nobs 1959q3 - 2015q4
+    start, end = 2, 227
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.predict(start, end, dynamic=True)
     # start 0, end >0 1960q1 - 1971q4
     start, end = 5, 51
     fv = res1.model.predict(params, start, end, dynamic=True, typ='levels')
-    assert_almost_equal(fv, fcdyn[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn[start:end + 1], DECIMAL_4)
     # start 0, end nobs 1960q1 - 2009q3
     start, end = 5, 202
     fv = res1.model.predict(params, start, end, dynamic=True, typ='levels')
-    assert_almost_equal(fv, fcdyn[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn[start:end + 1], DECIMAL_4)
     # start 0, end >nobs 1960q1 - 2015q4
     start, end = 5, 227
     fv = res1.model.predict(params, start, end, dynamic=True, typ='levels')
-    assert_almost_equal(fv, fcdyn[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn[start:end + 1], DECIMAL_4)
     # start >p, end >0 1965q1 - 1971q4
     start, end = 24, 51
     fv = res1.model.predict(params, start, end, dynamic=True, typ='levels')
-    assert_almost_equal(fv, fcdyn2[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn2[start:end + 1], DECIMAL_4)
     # start >p, end nobs 1965q1 - 2009q3
     start, end = 24, 202
     fv = res1.model.predict(params, start, end, dynamic=True, typ='levels')
-    assert_almost_equal(fv, fcdyn2[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn2[start:end + 1], DECIMAL_4)
     # start >p, end >nobs 1965q1 - 2015q4
     start, end = 24, 227
     fv = res1.model.predict(params, start, end, dynamic=True, typ='levels')
-    assert_almost_equal(fv, fcdyn2[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn2[start:end + 1], DECIMAL_4)
     # start nobs, end nobs 2009q3 - 2009q3
     start, end = 202, 202
     fv = res1.model.predict(params, start, end, dynamic=True, typ='levels')
-    assert_almost_equal(fv, fcdyn3[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn3[start:end + 1], DECIMAL_4)
     # start nobs, end >nobs 2009q3 - 2015q4
     start, end = 202, 227
     fv = res1.model.predict(params, start, end, dynamic=True, typ='levels')
     # start >nobs, end >nobs 2009q4 - 2015q4
     start, end = 203, 227
     fv = res1.model.predict(params, start, end, dynamic=True, typ='levels')
-    assert_almost_equal(fv, fcdyn4[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn4[start:end + 1], DECIMAL_4)
     # defaults
     start, end = None, None
     fv = res1.model.predict(params, start, end, dynamic=True, typ='levels')
@@ -1316,140 +1367,149 @@ def test_arima_predict_css():
 
 
 def test_arima_predict_css_diffs():
-
     cpi = load_macrodata_pandas().data['cpi'].values
-    #NOTE: Doing no-constant for now to kick the conditional exogenous
-    #issue 274 down the road
+    # NOTE: Doing no-constant for now to kick the conditional exogenous
+    # issue 274 down the road
     # go ahead and git the model to set up necessary variables
-    res1 = ARIMA(cpi, (4,1,1)).fit(disp=-1, method="css",
-                            trend="c")
+    res1 = ARIMA(cpi, (4, 1, 1)).fit(disp=-1, method="css",
+                                     trend="c")
     # but use gretl parameters to predict to avoid precision problems
     params = np.array([0.78349893861244,
-                      -0.533444105973324,
+                       -0.533444105973324,
                        0.321103691668809,
                        0.264012463189186,
                        0.107888256920655,
                        0.920132542916995])
     # we report mean, should we report constant?
     params[0] = params[0] / (1 - params[1:5].sum())
-
-    with open(current_path + '/results/results_arima_forecasts_all_css_diff.csv', "rb") as test_data:
-        arima_forecasts = np.genfromtxt(test_data, delimiter=",", skip_header=1, dtype=float)
-    fc = arima_forecasts[:,0]
-    fcdyn = arima_forecasts[:,1]
-    fcdyn2 = arima_forecasts[:,2]
-    fcdyn3 = arima_forecasts[:,3]
-    fcdyn4 = arima_forecasts[:,4]
-
-    #NOTE: should raise
-    #start, end = 1,3
-    #fv = res1.model.predict(params, start, end)
-    ## start < p, end 0 1959q3 - 1960q1
-    #start, end = 2, 4
-    #fv = res1.model.predict(params, start, end)
-    ## start < p, end >0 1959q3 - 1971q4
-    #start, end = 2, 51
-    #fv = res1.model.predict(params, start, end)
-    ## start < p, end nobs 1959q3 - 2009q3
-    #start, end = 2, 202
-    #fv = res1.model.predict(params, start, end)
-    ## start < p, end >nobs 1959q3 - 2015q4
-    #start, end = 2, 227
-    #fv = res1.model.predict(params, start, end)
+    file_path = os.path.join(current_path, 'results',
+                             'results_arima_forecasts_all_css_diff.csv')
+    with open(file_path, "rb") as test_data:
+        arima_forecasts = np.genfromtxt(test_data, delimiter=",",
+                                        skip_header=1, dtype=float)
+    fc = arima_forecasts[:, 0]
+    fcdyn = arima_forecasts[:, 1]
+    fcdyn2 = arima_forecasts[:, 2]
+    fcdyn3 = arima_forecasts[:, 3]
+    fcdyn4 = arima_forecasts[:, 4]
+
+    start, end = 1, 3
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.model.predict(params, start, end)
+    #  start < p, end 0 1959q3 - 1960q1
+    start, end = 2, 4
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.model.predict(params, start, end)
+    #  start < p, end >0 1959q3 - 1971q4
+    start, end = 2, 51
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.model.predict(params, start, end)
+    #  start < p, end nobs 1959q3 - 2009q3
+    start, end = 2, 202
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.model.predict(params, start, end)
+    #  start < p, end >nobs 1959q3 - 2015q4
+    start, end = 2, 227
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.model.predict(params, start, end)
     # start 0, end >0 1960q1 - 1971q4
     start, end = 5, 51
     fv = res1.model.predict(params, start, end)
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start 0, end nobs 1960q1 - 2009q3
     start, end = 5, 202
     fv = res1.model.predict(params, start, end)
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start 0, end >nobs 1960q1 - 2015q4
-    #TODO: why detoriating precision?
+    # TODO: why detoriating precision?
     fv = res1.model.predict(params, start, end)
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start >p, end >0 1965q1 - 1971q4
     start, end = 24, 51
     fv = res1.model.predict(params, start, end)
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start >p, end nobs 1965q1 - 2009q3
     start, end = 24, 202
     fv = res1.model.predict(params, start, end)
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start >p, end >nobs 1965q1 - 2015q4
     start, end = 24, 227
     fv = res1.model.predict(params, start, end)
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start nobs, end nobs 2009q3 - 2009q3
     start, end = 202, 202
     fv = res1.model.predict(params, start, end)
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start nobs, end >nobs 2009q3 - 2015q4
     start, end = 202, 227
     fv = res1.model.predict(params, start, end)
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start >nobs, end >nobs 2009q4 - 2015q4
     start, end = 203, 227
     fv = res1.model.predict(params, start, end)
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # defaults
     start, end = None, None
     fv = res1.model.predict(params, start, end)
     assert_almost_equal(fv, fc[5:203], DECIMAL_4)
 
-    #### Dynamic #####
+    # Dynamic
 
-    #NOTE: should raise
     # start < p, end <p 1959q2 - 1959q4
-    #start, end = 1,3
-    #fv = res1.predict(start, end, dynamic=True)
+    start, end = 1, 3
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.predict(start, end, dynamic=True)
     # start < p, end 0 1959q3 - 1960q1
-    #start, end = 2, 4
-    #fv = res1.predict(start, end, dynamic=True)
-    ## start < p, end >0 1959q3 - 1971q4
-    #start, end = 2, 51
-    #fv = res1.predict(start, end, dynamic=True)
-    ## start < p, end nobs 1959q3 - 2009q3
-    #start, end = 2, 202
-    #fv = res1.predict(start, end, dynamic=True)
-    ## start < p, end >nobs 1959q3 - 2015q4
-    #start, end = 2, 227
-    #fv = res1.predict(start, end, dynamic=True)
+    start, end = 2, 4
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.predict(start, end, dynamic=True)
+    #  start < p, end >0 1959q3 - 1971q4
+    start, end = 2, 51
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.predict(start, end, dynamic=True)
+    #  start < p, end nobs 1959q3 - 2009q3
+    start, end = 2, 202
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.predict(start, end, dynamic=True)
+    #  start < p, end >nobs 1959q3 - 2015q4
+    start, end = 2, 227
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.predict(start, end, dynamic=True)
     # start 0, end >0 1960q1 - 1971q4
     start, end = 5, 51
     fv = res1.model.predict(params, start, end, dynamic=True)
-    assert_almost_equal(fv, fcdyn[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn[start:end + 1], DECIMAL_4)
     # start 0, end nobs 1960q1 - 2009q3
     start, end = 5, 202
     fv = res1.model.predict(params, start, end, dynamic=True)
-    assert_almost_equal(fv, fcdyn[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn[start:end + 1], DECIMAL_4)
     # start 0, end >nobs 1960q1 - 2015q4
     start, end = 5, 227
     fv = res1.model.predict(params, start, end, dynamic=True)
-    assert_almost_equal(fv, fcdyn[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn[start:end + 1], DECIMAL_4)
     # start >p, end >0 1965q1 - 1971q4
     start, end = 24, 51
     fv = res1.model.predict(params, start, end, dynamic=True)
-    assert_almost_equal(fv, fcdyn2[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn2[start:end + 1], DECIMAL_4)
     # start >p, end nobs 1965q1 - 2009q3
     start, end = 24, 202
     fv = res1.model.predict(params, start, end, dynamic=True)
-    assert_almost_equal(fv, fcdyn2[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn2[start:end + 1], DECIMAL_4)
     # start >p, end >nobs 1965q1 - 2015q4
     start, end = 24, 227
     fv = res1.model.predict(params, start, end, dynamic=True)
-    assert_almost_equal(fv, fcdyn2[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn2[start:end + 1], DECIMAL_4)
     # start nobs, end nobs 2009q3 - 2009q3
     start, end = 202, 202
     fv = res1.model.predict(params, start, end, dynamic=True)
-    assert_almost_equal(fv, fcdyn3[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn3[start:end + 1], DECIMAL_4)
     # start nobs, end >nobs 2009q3 - 2015q4
     start, end = 202, 227
     fv = res1.model.predict(params, start, end, dynamic=True)
     # start >nobs, end >nobs 2009q4 - 2015q4
     start, end = 203, 227
     fv = res1.model.predict(params, start, end, dynamic=True)
-    assert_almost_equal(fv, fcdyn4[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn4[start:end + 1], DECIMAL_4)
     # defaults
     start, end = None, None
     fv = res1.model.predict(params, start, end, dynamic=True)
@@ -1457,137 +1517,142 @@ def test_arima_predict_css_diffs():
 
 
 def test_arima_predict_mle_diffs():
-
     cpi = load_macrodata_pandas().data['cpi'].values
-    #NOTE: Doing no-constant for now to kick the conditional exogenous
-    #issue 274 down the road
+    # NOTE: Doing no-constant for now to kick the conditional exogenous
+    # issue 274 down the road
     # go ahead and git the model to set up necessary variables
-    res1 = ARIMA(cpi, (4,1,1)).fit(disp=-1, trend="c")
+    res1 = ARIMA(cpi, (4, 1, 1)).fit(disp=-1, trend="c")
     # but use gretl parameters to predict to avoid precision problems
     params = np.array([0.926875951549299,
-        -0.555862621524846,
-        0.320865492764400,
-        0.252253019082800,
-        0.113624958031799,
-        0.939144026934634])
-
-    with open(current_path + '/results/results_arima_forecasts_all_mle_diff.csv', "rb") as test_data:
-        arima_forecasts = np.genfromtxt(test_data, delimiter=",", skip_header=1, dtype=float)
-    fc = arima_forecasts[:,0]
-    fcdyn = arima_forecasts[:,1]
-    fcdyn2 = arima_forecasts[:,2]
-    fcdyn3 = arima_forecasts[:,3]
-    fcdyn4 = arima_forecasts[:,4]
-
-    #NOTE: should raise
-    start, end = 1,3
-    fv = res1.model.predict(params, start, end)
-    ## start < p, end 0 1959q3 - 1960q1
+                       -0.555862621524846,
+                       0.320865492764400,
+                       0.252253019082800,
+                       0.113624958031799,
+                       0.939144026934634])
+    file_path = os.path.join(current_path, 'results',
+                             'results_arima_forecasts_all_mle_diff.csv')
+    with open(file_path, "rb") as test_data:
+        arima_forecasts = np.genfromtxt(test_data, delimiter=",",
+                                        skip_header=1, dtype=float)
+    fc = arima_forecasts[:, 0]
+    fcdyn = arima_forecasts[:, 1]
+    fcdyn2 = arima_forecasts[:, 2]
+    fcdyn3 = arima_forecasts[:, 3]
+    fcdyn4 = arima_forecasts[:, 4]
+
+    start, end = 1, 3
+    res1.model.predict(params, start, end)
+    #  start < p, end 0 1959q3 - 1960q1
     start, end = 2, 4
-    fv = res1.model.predict(params, start, end)
-    ## start < p, end >0 1959q3 - 1971q4
+    res1.model.predict(params, start, end)
+    #  start < p, end >0 1959q3 - 1971q4
     start, end = 2, 51
-    fv = res1.model.predict(params, start, end)
-    ## start < p, end nobs 1959q3 - 2009q3
+    res1.model.predict(params, start, end)
+    #  start < p, end nobs 1959q3 - 2009q3
     start, end = 2, 202
-    fv = res1.model.predict(params, start, end)
-    ## start < p, end >nobs 1959q3 - 2015q4
+    res1.model.predict(params, start, end)
+    #  start < p, end >nobs 1959q3 - 2015q4
     start, end = 2, 227
-    fv = res1.model.predict(params, start, end)
+    res1.model.predict(params, start, end)
     # start 0, end >0 1960q1 - 1971q4
     start, end = 5, 51
     fv = res1.model.predict(params, start, end)
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start 0, end nobs 1960q1 - 2009q3
     start, end = 5, 202
     fv = res1.model.predict(params, start, end)
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start 0, end >nobs 1960q1 - 2015q4
-    #TODO: why detoriating precision?
+    # TODO: why detoriating precision?
     fv = res1.model.predict(params, start, end)
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start >p, end >0 1965q1 - 1971q4
     start, end = 24, 51
     fv = res1.model.predict(params, start, end)
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start >p, end nobs 1965q1 - 2009q3
     start, end = 24, 202
     fv = res1.model.predict(params, start, end)
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start >p, end >nobs 1965q1 - 2015q4
     start, end = 24, 227
     fv = res1.model.predict(params, start, end)
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start nobs, end nobs 2009q3 - 2009q3
     start, end = 202, 202
     fv = res1.model.predict(params, start, end)
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start nobs, end >nobs 2009q3 - 2015q4
     start, end = 202, 227
     fv = res1.model.predict(params, start, end)
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # start >nobs, end >nobs 2009q4 - 2015q4
     start, end = 203, 227
     fv = res1.model.predict(params, start, end)
-    assert_almost_equal(fv, fc[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fc[start:end + 1], DECIMAL_4)
     # defaults
     start, end = None, None
     fv = res1.model.predict(params, start, end)
     assert_almost_equal(fv, fc[1:203], DECIMAL_4)
 
-    #### Dynamic #####
+    # Dynamic
 
-    #NOTE: should raise
+    # NOTE: should raise
     # start < p, end <p 1959q2 - 1959q4
-    #start, end = 1,3
-    #fv = res1.predict(start, end, dynamic=True)
+    start, end = 1, 3
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.predict(start, end, dynamic=True)
     # start < p, end 0 1959q3 - 1960q1
-    #start, end = 2, 4
-    #fv = res1.predict(start, end, dynamic=True)
-    ## start < p, end >0 1959q3 - 1971q4
-    #start, end = 2, 51
-    #fv = res1.predict(start, end, dynamic=True)
-    ## start < p, end nobs 1959q3 - 2009q3
-    #start, end = 2, 202
-    #fv = res1.predict(start, end, dynamic=True)
-    ## start < p, end >nobs 1959q3 - 2015q4
-    #start, end = 2, 227
-    #fv = res1.predict(start, end, dynamic=True)
+    start, end = 2, 4
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.predict(start, end, dynamic=True)
+    #  start < p, end >0 1959q3 - 1971q4
+    start, end = 2, 51
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.predict(start, end, dynamic=True)
+    #  start < p, end nobs 1959q3 - 2009q3
+    start, end = 2, 202
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.predict(start, end, dynamic=True)
+    #  start < p, end >nobs 1959q3 - 2015q4
+    start, end = 2, 227
+    with pytest.raises(ValueError, match='Start must be >= k_ar'):
+        res1.predict(start, end, dynamic=True)
     # start 0, end >0 1960q1 - 1971q4
     start, end = 5, 51
     fv = res1.model.predict(params, start, end, dynamic=True)
-    assert_almost_equal(fv, fcdyn[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn[start:end + 1], DECIMAL_4)
     # start 0, end nobs 1960q1 - 2009q3
     start, end = 5, 202
     fv = res1.model.predict(params, start, end, dynamic=True)
-    assert_almost_equal(fv, fcdyn[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn[start:end + 1], DECIMAL_4)
     # start 0, end >nobs 1960q1 - 2015q4
     start, end = 5, 227
     fv = res1.model.predict(params, start, end, dynamic=True)
-    assert_almost_equal(fv, fcdyn[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn[start:end + 1], DECIMAL_4)
     # start >p, end >0 1965q1 - 1971q4
     start, end = 24, 51
     fv = res1.model.predict(params, start, end, dynamic=True)
-    assert_almost_equal(fv, fcdyn2[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn2[start:end + 1], DECIMAL_4)
     # start >p, end nobs 1965q1 - 2009q3
     start, end = 24, 202
     fv = res1.model.predict(params, start, end, dynamic=True)
-    assert_almost_equal(fv, fcdyn2[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn2[start:end + 1], DECIMAL_4)
     # start >p, end >nobs 1965q1 - 2015q4
     start, end = 24, 227
     fv = res1.model.predict(params, start, end, dynamic=True)
-    assert_almost_equal(fv, fcdyn2[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn2[start:end + 1], DECIMAL_4)
     # start nobs, end nobs 2009q3 - 2009q3
     start, end = 202, 202
     fv = res1.model.predict(params, start, end, dynamic=True)
-    assert_almost_equal(fv, fcdyn3[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn3[start:end + 1], DECIMAL_4)
     # start nobs, end >nobs 2009q3 - 2015q4
     start, end = 202, 227
     fv = res1.model.predict(params, start, end, dynamic=True)
     # start >nobs, end >nobs 2009q4 - 2015q4
     start, end = 203, 227
     fv = res1.model.predict(params, start, end, dynamic=True)
-    assert_almost_equal(fv, fcdyn4[start:end+1], DECIMAL_4)
+    assert_almost_equal(fv, fcdyn4[start:end + 1], DECIMAL_4)
     # defaults
     start, end = None, None
     fv = res1.model.predict(params, start, end, dynamic=True)
@@ -1597,10 +1662,11 @@ def test_arima_predict_mle_diffs():
 def test_arima_wrapper():
     cpi = load_macrodata_pandas().data['cpi']
     cpi.index = pd.Index(cpi_dates)
-    res = ARIMA(cpi, (4,1,1), freq='Q').fit(disp=-1)
-    assert_equal(res.params.index, pd.Index(['const', 'ar.L1.D.cpi', 'ar.L2.D.cpi',
-                                    'ar.L3.D.cpi', 'ar.L4.D.cpi',
-                                    'ma.L1.D.cpi']))
+    res = ARIMA(cpi, (4, 1, 1), freq='Q').fit(disp=-1)
+    assert_equal(res.params.index,
+                 pd.Index(['const', 'ar.L1.D.cpi', 'ar.L2.D.cpi',
+                           'ar.L3.D.cpi', 'ar.L4.D.cpi',
+                           'ma.L1.D.cpi']))
     assert_equal(res.model.endog_names, 'D.cpi')
 
 
@@ -1612,44 +1678,46 @@ def test_1dexog():
     exog = dta['m1'].values.squeeze()
     with warnings.catch_warnings():
         warnings.simplefilter("ignore")
-        mod = ARMA(endog, (1,1), exog).fit(disp=-1)
+        mod = ARMA(endog, (1, 1), exog).fit(disp=-1)
         mod.predict(193, 203, exog[-10:])
 
         # check for dynamic is true and pandas Series  see #2589
         mod.predict(193, 202, exog[-10:], dynamic=True)
 
         dta.index = pd.Index(cpi_dates)
-        mod = ARMA(dta['realcons'], (1,1), dta['m1']).fit(disp=-1)
-        mod.predict(dta.index[-10], dta.index[-1], exog=dta['m1'][-10:], dynamic=True)
+        mod = ARMA(dta['realcons'], (1, 1), dta['m1']).fit(disp=-1)
+        mod.predict(dta.index[-10], dta.index[-1], exog=dta['m1'][-10:],
+                    dynamic=True)
 
-        mod = ARMA(dta['realcons'], (1,1), dta['m1']).fit(trend='nc', disp=-1)
-        mod.predict(dta.index[-10], dta.index[-1], exog=dta['m1'][-10:], dynamic=True)
+        mod = ARMA(dta['realcons'], (1, 1), dta['m1']).fit(trend='nc', disp=-1)
+        mod.predict(dta.index[-10], dta.index[-1], exog=dta['m1'][-10:],
+                    dynamic=True)
 
 
 def test_arima_predict_bug():
-    #predict_start_date was not getting set on start = None
+    # predict_start_date was not getting set on start = None
     from statsmodels.datasets import sunspots
     dta = sunspots.load_pandas().data.SUNACTIVITY
     dta.index = pd.date_range(start='1700', end='2009', freq='A')[:309]
-    arma_mod20 = ARMA(dta, (2,0)).fit(disp=-1)
+    arma_mod20 = ARMA(dta, (2, 0)).fit(disp=-1)
     arma_mod20.predict(None, None)
 
     # test prediction with time stamp, see #2587
     predict = arma_mod20.predict(dta.index[-20], dta.index[-1])
-    assert_(predict.index.equals(dta.index[-20:]))
+    assert predict.index.equals(dta.index[-20:])
     predict = arma_mod20.predict(dta.index[-20], dta.index[-1], dynamic=True)
-    assert_(predict.index.equals(dta.index[-20:]))
+    assert predict.index.equals(dta.index[-20:])
     # partially out of sample
     predict_dates = pd.date_range(start='2000', end='2015', freq='A')
     predict = arma_mod20.predict(predict_dates[0], predict_dates[-1])
-    assert_(predict.index.equals(predict_dates))
-    #assert_(1 == 0)
+    assert predict.index.equals(predict_dates)
 
 
 def test_arima_predict_q2():
     # bug with q > 1 for arima predict
     inv = load_macrodata_pandas().data['realinv'].values
-    arima_mod = ARIMA(np.log(inv), (1,1,2)).fit(start_params=[0,0,0,0], disp=-1)
+    arima_mod = ARIMA(np.log(inv), (1, 1, 2)).fit(start_params=[0, 0, 0, 0],
+                                                  disp=-1)
     fc, stderr, conf_int = arima_mod.forecast(5)
     # values copy-pasted from gretl
     assert_almost_equal(fc,
@@ -1663,7 +1731,7 @@ def test_arima_predict_pandas_nofreq():
              "2010-01-08", "2010-01-11", "2010-01-12", "2010-01-11",
              "2010-01-12", "2010-01-13", "2010-01-17"]
     close = [626.75, 623.99, 608.26, 594.1, 602.02, 601.11, 590.48, 587.09,
-             589.85, 580.0,587.62]
+             589.85, 580.0, 587.62]
     data = pd.DataFrame(close, index=DatetimeIndex(dates), columns=["close"])
 
     # TODO: fix this names bug for non-string names names
@@ -1673,7 +1741,7 @@ def test_arima_predict_pandas_nofreq():
     # first check that in-sample prediction works
     predict = arma.predict()
 
-    assert_(predict.index.equals(data.index))
+    assert predict.index.equals(data.index)
 
     # check that this raises an exception when date not on index
     assert_raises(KeyError, arma.predict, start="2010-1-9", end=10)
@@ -1684,50 +1752,50 @@ def test_arima_predict_pandas_nofreq():
     # raise because end not on index
     assert_raises(KeyError, arma.predict, start=3, end="2010-1-10")
 
-    predict = arma.predict(start="2010-1-7", end=10) # should be of length 10
-    assert_(len(predict) == 8)
-    assert_(predict.index.equals(data.index[3:10+1]))
+    predict = arma.predict(start="2010-1-7", end=10)  # should be of length 10
+    assert len(predict) == 8
+    assert predict.index.equals(data.index[3:10 + 1])
 
     with pytest.warns(ValueWarning, match="No supported index is available"):
         predict = arma.predict(start="2010-1-7", end=14)
 
-    assert_(predict.index.equals(pd.Index(lrange(3, 15))))
+    assert predict.index.equals(pd.Index(lrange(3, 15)))
 
     with pytest.warns(ValueWarning, match="No supported index is available"):
         predict = arma.predict(start=3, end=14)
 
-    assert_(predict.index.equals(pd.Index(lrange(3, 15))))
+    assert predict.index.equals(pd.Index(lrange(3, 15)))
 
     # end can be a date if it's in the sample and on the index
     # predict dates is just a slice of the dates index then
     predict = arma.predict(start="2010-1-6", end="2010-1-13")
-    assert_(predict.index.equals(data.index[2:10]))
+    assert predict.index.equals(data.index[2:10])
     predict = arma.predict(start=2, end="2010-1-13")
-    assert_(predict.index.equals(data.index[2:10]))
+    assert predict.index.equals(data.index[2:10])
 
 
 def test_arima_predict_exog():
     # check 625 and 626
-    #from statsmodels.tsa.arima_process import arma_generate_sample
-    #arparams = np.array([1, -.45, .25])
-    #maparams = np.array([1, .15])
-    #nobs = 100
-    #np.random.seed(123)
-    #y = arma_generate_sample(arparams, maparams, nobs, burnin=100)
-
-    ## make an exogenous trend
-    #X = np.array(lrange(nobs)) / 20.0
-    ## add a constant
-    #y += 2.5
+    # from statsmodels.tsa.arima_process import arma_generate_sample
+    # arparams = np.array([1, -.45, .25])
+    # maparams = np.array([1, .15])
+    # nobs = 100
+    # np.random.seed(123)
+    # y = arma_generate_sample(arparams, maparams, nobs, burnin=100)
+
+    #  make an exogenous trend
+    # X = np.array(lrange(nobs)) / 20.0
+    #  add a constant
+    # y += 2.5
 
     from pandas import read_csv
-    arima_forecasts = read_csv(current_path + "/results/"
-                            "results_arima_exog_forecasts_mle.csv")
+    file_name = "/results/results_arima_exog_forecasts_mle.csv"
+    arima_forecasts = read_csv(current_path + file_name)
     y = arima_forecasts["y"].dropna()
-    X = np.arange(len(y) + 25)/20.
+    X = np.arange(len(y) + 25) / 20.
     predict_expected = arima_forecasts["predict"]
-    arma_res = ARMA(y.values, order=(2,1), exog=X[:100]).fit(trend="c",
-                                                             disp=-1)
+    arma_res = ARMA(y.values, order=(2, 1), exog=X[:100]).fit(trend="c",
+                                                              disp=-1)
     # params from gretl
     params = np.array([2.786912485145725, -0.122650190196475,
                        0.533223846028938, -0.319344321763337,
@@ -1738,30 +1806,30 @@ def test_arima_predict_exog():
     assert_almost_equal(predict, predict_expected.values[:100], 5)
 
     # check 626
-    assert_(len(arma_res.model.exog_names) == 5)
+    assert len(arma_res.model.exog_names) == 5
 
     # exog for out-of-sample and in-sample dynamic
     predict = arma_res.model.predict(params, end=124, exog=X[100:])
     assert_almost_equal(predict, predict_expected.values, 6)
 
     # conditional sum of squares
-    #arima_forecasts = read_csv(current_path + "/results/"
+    # arima_forecasts = read_csv(current_path + "/results/"
     #                        "results_arima_exog_forecasts_css.csv")
-    #predict_expected = arima_forecasts["predict"].dropna()
-    #arma_res = ARMA(y.values, order=(2,1), exog=X[:100]).fit(trend="c",
+    # predict_expected = arima_forecasts["predict"].dropna()
+    # arma_res = ARMA(y.values, order=(2,1), exog=X[:100]).fit(trend="c",
     #                                                         method="css",
     #                                                         disp=-1)
 
-    #params = np.array([2.152350033809826, -0.103602399018814,
+    # params = np.array([2.152350033809826, -0.103602399018814,
     #                   0.566716580421188, -0.326208009247944,
     #                   0.102142932143421])
-    #predict = arma_res.model.predict(params)
-    ## in-sample
-    #assert_almost_equal(predict, predict_expected.values[:98], 6)
+    # predict = arma_res.model.predict(params)
+    #  in-sample
+    # assert_almost_equal(predict, predict_expected.values[:98], 6)
 
-    #predict = arma_res.model.predict(params, end=124, exog=X[100:])
-    ## exog for out-of-sample and in-sample dynamic
-    #assert_almost_equal(predict, predict_expected.values, 3)
+    # predict = arma_res.model.predict(params, end=124, exog=X[100:])
+    #  exog for out-of-sample and in-sample dynamic
+    # assert_almost_equal(predict, predict_expected.values, 3)
 
 
 @pytest.mark.smoke
@@ -1774,7 +1842,7 @@ def test_arima_no_diff():
     np.random.seed(12345)
     y = arma_generate_sample(ar, ma, 100)
     mod = ARIMA(y, (3, 0, 2))
-    assert_(type(mod) is ARMA)
+    assert type(mod) is ARMA
     res = mod.fit(disp=-1)
     # smoke test just to be sure
     res.predict()
@@ -1787,32 +1855,31 @@ def test_arima_predict_noma():
     ma = [1]
     np.random.seed(12345)
     data = arma_generate_sample(ar, ma, 100)
-    arma = ARMA(data, order=(0,1))
+    arma = ARMA(data, order=(0, 1))
     arma_res = arma.fit(disp=-1)
     arma_res.forecast(1)
 
 
 def test_arimax():
     dta = load_macrodata_pandas().data
-    dates = pd.date_range("1959", periods=len(dta), freq='Q')
     dta.index = cpi_dates
     dta = dta[["realdpi", "m1", "realgdp"]]
     y = dta.pop("realdpi")
 
     # 1 exog
-    #X = dta.iloc[1:]["m1"]
-    #res = ARIMA(y, (2, 1, 1), X).fit(disp=-1)
-    #params = [23.902305009084373, 0.024650911502790, -0.162140641341602,
+    # X = dta.iloc[1:]["m1"]
+    # res = ARIMA(y, (2, 1, 1), X).fit(disp=-1)
+    # params = [23.902305009084373, 0.024650911502790, -0.162140641341602,
     #          0.165262136028113, -0.066667022903974]
-    #assert_almost_equal(res.params.values, params, 6)
+    # assert_almost_equal(res.params.values, params, 6)
 
     # 2 exog
     X = dta
     res = ARIMA(y, (2, 1, 1), X).fit(disp=False, solver="nm", maxiter=1000,
-                ftol=1e-12, xtol=1e-12)
+                                     ftol=1e-12, xtol=1e-12)
 
     # from gretl
-    #params = [13.113976653926638, -0.003792125069387,  0.004123504809217,
+    # params = [13.113976653926638, -0.003792125069387,  0.004123504809217,
     #          -0.199213760940898,  0.151563643588008, -0.033088661096699]
     # from stata using double
     stata_llf = -1076.108614859121
@@ -1840,18 +1907,18 @@ def test_arimax():
 
 def test_bad_start_params():
     endog = np.array([
-        820.69093,      781.0103028,    785.8786988,    767.64282267,
-        778.9837648,    824.6595702,    813.01877867,   751.65598567,
-        753.431091,     746.920813,     795.6201904,    772.65732833,
-        793.4486454,    868.8457766,    823.07226547,   783.09067747,
-        791.50723847,   770.93086347,   835.34157333,   810.64147947,
-        738.36071367,   776.49038513,   822.93272333,   815.26461227,
-        773.70552987,   777.3726522,    811.83444853,   840.95489133,
-        777.51031933,   745.90077307,   806.95113093,   805.77521973,
-        756.70927733,   749.89091773,  1694.2266924,   2398.4802244,
-        1434.6728516,   909.73940427,   929.01291907,   769.07561453,
-        801.1112548,    796.16163313,   817.2496376,    857.73046447,
-        838.849345,     761.92338873,   731.7842242,    770.4641844])
+        820.69093, 781.0103028, 785.8786988, 767.64282267,
+        778.9837648, 824.6595702, 813.01877867, 751.65598567,
+        753.431091, 746.920813, 795.6201904, 772.65732833,
+        793.4486454, 868.8457766, 823.07226547, 783.09067747,
+        791.50723847, 770.93086347, 835.34157333, 810.64147947,
+        738.36071367, 776.49038513, 822.93272333, 815.26461227,
+        773.70552987, 777.3726522, 811.83444853, 840.95489133,
+        777.51031933, 745.90077307, 806.95113093, 805.77521973,
+        756.70927733, 749.89091773, 1694.2266924, 2398.4802244,
+        1434.6728516, 909.73940427, 929.01291907, 769.07561453,
+        801.1112548, 796.16163313, 817.2496376, 857.73046447,
+        838.849345, 761.92338873, 731.7842242, 770.4641844])
 
     mod = ARMA(endog, (15, 0))
     with pytest.raises(ValueError, match="pass your own start_params"):
@@ -1889,7 +1956,7 @@ def test_arima_dataframe_integer_name():
     dr = pd.date_range("1990", periods=len(vals), freq='Q')
     ts = pd.Series(vals, index=dr)
     df = pd.DataFrame(ts)
-    mod = sm.tsa.ARIMA(df, (2, 0, 2))
+    sm.tsa.ARIMA(df, (2, 0, 2))
 
 
 def test_arima_exog_predict_1d():
@@ -1919,37 +1986,31 @@ def test_arima_1123():
     arparams = np.array([.75, -.25])
     maparams = np.array([.65, .35])
 
-    arparam = np.r_[1, -arparams]
-    maparam = np.r_[1, maparams]
-
     nobs = 20
-
-    dates = pd.date_range(start='1980', periods=nobs, freq='A')
-
     np.random.seed(12345)
     y = arma_generate_sample(arparams, maparams, nobs)
 
     X = np.random.randn(nobs)
-    y += 5*X
-    mod = ARMA(y[:-1], order=(1,0), exog=X[:-1])
+    y += 5 * X
+    mod = ARMA(y[:-1], order=(1, 0), exog=X[:-1])
     res = mod.fit(trend='nc', disp=False)
     fc = res.forecast(exog=X[-1:])
     # results from gretl
     assert_almost_equal(fc[0], 2.200393, 6)
     assert_almost_equal(fc[1], 1.030743, 6)
-    assert_almost_equal(fc[2][0,0], 0.180175, 6)
-    assert_almost_equal(fc[2][0,1], 4.220611, 6)
+    assert_almost_equal(fc[2][0, 0], 0.180175, 6)
+    assert_almost_equal(fc[2][0, 1], 4.220611, 6)
 
-    mod = ARMA(y[:-1], order=(1,1), exog=X[:-1])
+    mod = ARMA(y[:-1], order=(1, 1), exog=X[:-1])
     res = mod.fit(trend='nc', disp=False)
     fc = res.forecast(exog=X[-1:])
     assert_almost_equal(fc[0], 2.765688, 6)
     assert_almost_equal(fc[1], 0.835048, 6)
-    assert_almost_equal(fc[2][0,0], 1.129023, 6)
-    assert_almost_equal(fc[2][0,1], 4.402353, 6)
+    assert_almost_equal(fc[2][0, 0], 1.129023, 6)
+    assert_almost_equal(fc[2][0, 1], 4.402353, 6)
 
     # make sure this works to. code looked fishy.
-    mod = ARMA(y[:-1], order=(1,0), exog=X[:-1])
+    mod = ARMA(y[:-1], order=(1, 0), exog=X[:-1])
     res = mod.fit(trend='c', disp=False)
     fc = res.forecast(exog=X[-1:])
     assert_almost_equal(fc[0], 2.481219, 6)
@@ -1971,12 +2032,12 @@ def test_small_data():
     # and be clear, these are garbage parameters.
     # X-12 arima will estimate, gretl refuses to estimate likely a problem
     # in start params regression.
-    res = mod.fit(trend="nc", disp=0, start_params=[.1,.1,.1,.1])
+    mod.fit(trend="nc", disp=0, start_params=[.1, .1, .1, .1])
     mod = ARIMA(y, (1, 0, 2))
     import warnings
     with warnings.catch_warnings():
         warnings.simplefilter("ignore")
-        res = mod.fit(disp=0, start_params=[np.mean(y), .1, .1, .1])
+        mod.fit(disp=0, start_params=[np.mean(y), .1, .1, .1])
 
 
 class TestARMA00(object):
@@ -1996,7 +2057,8 @@ def test_parameters(self):
 
     def test_predictions(self):
         predictions = self.arma_00_res.predict()
-        assert_almost_equal(self.y.mean() * np.ones_like(predictions), predictions)
+        assert_almost_equal(self.y.mean() * np.ones_like(predictions),
+                            predictions)
 
     def test_arroots(self):
         # regression test; older implementation of arroots returned None
@@ -2028,7 +2090,8 @@ def test_css(self):
         arma = ARMA(self.y, order=(0, 0))
         fit = arma.fit(method='css', disp=-1)
         predictions = fit.predict()
-        assert_almost_equal(self.y.mean() * np.ones_like(predictions), predictions)
+        assert_almost_equal(self.y.mean() * np.ones_like(predictions),
+                            predictions)
 
     def test_arima(self):
         yi = np.cumsum(self.y)
@@ -2041,18 +2104,20 @@ def test_arma_ols(self):
         y_lead = y[1:]
         y_lag = y[:-1]
         T = y_lag.shape[0]
-        X = np.hstack((np.ones((T,1)), y_lag[:,None]))
+        X = np.hstack((np.ones((T, 1)), y_lag[:, None]))
         ols_res = OLS(y_lead, X).fit()
-        arma_res = ARMA(y_lead,order=(0,0),exog=y_lag).fit(trend='c', disp=-1)
+        arma_res = ARMA(y_lead, order=(0, 0), exog=y_lag).fit(trend='c',
+                                                              disp=-1)
         assert_almost_equal(ols_res.params, arma_res.params)
 
     def test_arma_exog_no_constant(self):
         y = self.y
         y_lead = y[1:]
         y_lag = y[:-1]
-        X = y_lag[:,None]
+        X = y_lag[:, None]
         ols_res = OLS(y_lead, X).fit()
-        arma_res = ARMA(y_lead,order=(0,0),exog=y_lag).fit(trend='nc', disp=-1)
+        arma_res = ARMA(y_lead, order=(0, 0), exog=y_lag).fit(trend='nc',
+                                                              disp=-1)
         assert_almost_equal(ols_res.params, arma_res.params)
 
 
@@ -2064,7 +2129,7 @@ def test_arima_dates_startatend():
                                       periods=36, freq='M'))
     res = ARIMA(x, (1, 0, 0)).fit(disp=0)
     pred = res.predict(start=len(x), end=len(x))
-    assert_(pred.index[0] == x.index.shift(1)[-1])
+    assert pred.index[0] == x.index.shift(1)[-1]
     fc = res.forecast()[0]
     assert_almost_equal(pred.values[0], fc)
 
@@ -2084,33 +2149,34 @@ def test_plot_predict(close_figures):
     dta = load_pandas().data[['SUNACTIVITY']]
     dta.index = date_range(start='1700', end='2009', freq='A')[:309]
     res = ARMA(dta, (3, 0)).fit(disp=-1)
-    fig = res.plot_predict('1990', '2012', dynamic=True, plot_insample=False)
+    res.plot_predict('1990', '2012', dynamic=True, plot_insample=False)
+    res.plot_predict('1990', '2012', dynamic=True, plot_insample=True)
 
     res = ARIMA(dta, (3, 1, 0)).fit(disp=-1)
-    fig = res.plot_predict('1990', '2012', dynamic=True, plot_insample=False)
+    res.plot_predict('1990', '2012', dynamic=True, plot_insample=False)
+    res.plot_predict('1990', '2012', dynamic=True, plot_insample=True)
 
 
 def test_arima_diff2():
     dta = load_macrodata_pandas().data['cpi']
-    dates = pd.date_range("1959", periods=len(dta), freq='Q')
     dta.index = cpi_dates
     mod = ARIMA(dta, (3, 2, 1)).fit(disp=-1)
     fc, fcerr, conf_int = mod.forecast(10)
     # forecasts from gretl
-    conf_int_res = [ (216.139,  219.231),
-                     (216.472,  221.520),
-                     (217.064,  223.649),
-                     (217.586,  225.727),
-                     (218.119,  227.770),
-                     (218.703,  229.784),
-                     (219.306,  231.777),
-                     (219.924,  233.759),
-                     (220.559,  235.735),
-                     (221.206,  237.709)]
+    conf_int_res = [(216.139, 219.231),
+                    (216.472, 221.520),
+                    (217.064, 223.649),
+                    (217.586, 225.727),
+                    (218.119, 227.770),
+                    (218.703, 229.784),
+                    (219.306, 231.777),
+                    (219.924, 233.759),
+                    (220.559, 235.735),
+                    (221.206, 237.709)]
 
     fc_res = [217.685, 218.996, 220.356, 221.656, 222.945, 224.243, 225.541,
-          226.841, 228.147, 229.457]
-    fcerr_res = [0.7888, 1.2878, 1.6798, 2.0768,  2.4620, 2.8269, 3.1816,
+              226.841, 228.147, 229.457]
+    fcerr_res = [0.7888, 1.2878, 1.6798, 2.0768, 2.4620, 2.8269, 3.1816,
                  3.52950, 3.8715, 4.2099]
 
     assert_almost_equal(fc, fc_res, 3)
@@ -2120,8 +2186,8 @@ def test_arima_diff2():
     predicted = mod.predict('2008Q1', '2012Q1', typ='levels')
 
     predicted_res = [214.464, 215.478, 221.277, 217.453, 212.419, 213.530,
-                     215.087, 217.685 , 218.996 , 220.356 , 221.656 ,
-                     222.945 , 224.243 , 225.541 , 226.841 , 228.147 ,
+                     215.087, 217.685, 218.996, 220.356, 221.656,
+                     222.945, 224.243, 225.541, 226.841, 228.147,
                      229.457]
     assert_almost_equal(predicted, predicted_res, 3)
 
@@ -2189,7 +2255,6 @@ def test_arima_exog_predict():
     # test forecasting and dynamic prediction with exog against Stata
 
     dta = load_macrodata_pandas().data
-    dates = pd.date_range("1959", periods=len(dta), freq='Q')
     cpi_dates = period_range(start='1959Q1', end='2009Q3', freq='Q')
     dta.index = cpi_dates
 
@@ -2233,7 +2298,8 @@ def test_arima_exog_predict():
     ex_scale = 1000
     # ARIMA(1, 1, 1)
     ex = ex_scale * np.asarray(data_sample[['loggdp', 'logcons']].diff())
-    # The first obsevation is not (supposed to be) used, but I get a Lapack problem
+    # The first observation is not (supposed to be) used,
+    # but I get a Lapack problem
     # Intel MKL ERROR: Parameter 5 was incorrect on entry to DLASCL.
     ex[0] = 0
     mod111 = ARIMA(100 * np.asarray(data_sample['loginv']), (1, 1, 1),
@@ -2348,28 +2414,24 @@ def test_arima_fit_multiple_calls():
     # Make multiple calls to fit
     with pytest.warns(HessianInversionWarning, match="no bse or cov"):
         mod.fit(disp=0, start_params=[np.mean(y), .1, .1, .1])
-    assert_equal(mod.exog_names,  ['const', 'ar.L1.y', 'ma.L1.y', 'ma.L2.y'])
+    assert_equal(mod.exog_names, ['const', 'ar.L1.y', 'ma.L1.y', 'ma.L2.y'])
 
-    mod.exog = None  # FIXME: this should not be necessary
     with pytest.warns(HessianInversionWarning, match="no bse or cov"):
         res = mod.fit(disp=0, start_params=[np.mean(y), .1, .1, .1])
-    assert_equal(mod.exog_names,  ['const', 'ar.L1.y', 'ma.L1.y', 'ma.L2.y'])
+    assert_equal(mod.exog_names, ['const', 'ar.L1.y', 'ma.L1.y', 'ma.L2.y'])
 
     # ensure summary() works  # TODO: separate and pytest.mark.smoke
     res.summary()
+    res.summary2()
 
     # test multiple calls when there is only a constant term
     mod = ARIMA(y, (0, 0, 0))
     # Make multiple calls to fit
     mod.fit(disp=0, start_params=[np.mean(y)])
-    assert_equal(mod.exog_names,  ['const'])
+    assert_equal(mod.exog_names, ['const'])
 
-    mod.exog = None  # FIXME: this should not be necessary
-    res = mod.fit(disp=0, start_params=[np.mean(y)])
-    assert_equal(mod.exog_names,  ['const'])
-
-    # ensure summary() works  # TODO: separate and pytest.mark.smoke
-    res.summary()
+    with pytest.raises(RuntimeError):
+        mod.fit(disp=0, start_params=[np.mean(y)])
 
 
 def test_long_ar_start_params():
@@ -2384,14 +2446,31 @@ def test_long_ar_start_params():
 
     model = ARMA(y, order=(2, 2))
 
-    model.fit(method='css',start_ar_lags=10, disp=0)
+    model.fit(method='css', start_ar_lags=10, disp=0)
+
+    with pytest.raises(RuntimeError):
+        model.fit(method='css-mle', start_ar_lags=10, disp=0)
+
+    with pytest.raises(RuntimeError):
+        model.fit(method='mle', start_ar_lags=10, disp=0)
+
+    with pytest.raises(RuntimeError):
+        model.fit(ValueError, start_ar_lags=nobs + 5, disp=0)
+
+
+def test_start_params_too_large():
+    np.random.seed(12345)
+    arparams = np.array([1, -.75, .25])
+    maparams = np.array([1, .65, .35])
+
+    nobs = 30
 
-    model.exog = None  # FIXME: should not be necessary
-    model.fit(method='css-mle',start_ar_lags=10, disp=0)
+    np.random.seed(12345)
+    y = arma_generate_sample(arparams, maparams, nobs)
 
-    model.exog = None  # FIXME: should not be necessary
-    model.fit(method='mle',start_ar_lags=10, disp=0)
-    assert_raises(ValueError, model.fit, start_ar_lags=nobs+5, disp=0)
+    model = ARMA(y, order=(2, 2))
+    with pytest.raises(ValueError):
+        model.fit(start_ar_lags=nobs + 5, disp=0)
 
 
 def test_arma_pickle():
@@ -2494,7 +2573,7 @@ def test_constant_column_trend():
     #  silently drop a column and return an inconsistenct k_trend value.
 
     exog = np.array([0.5, 0.5, 0.5, 0.5, 0.5])
-    endog =  np.array([-0.011866, 0.003380, 0.015357, 0.004451, -0.020889])
+    endog = np.array([-0.011866, 0.003380, 0.015357, 0.004451, -0.020889])
 
     model = ARIMA(endog=endog, order=(1, 1, 0), exog=exog)
 
@@ -2542,3 +2621,81 @@ def test_predict_wrong_exog_len(reset_randomstate):
     res = mod.fit(disp=-1)
     with pytest.warns(SpecificationWarning, match='of observations in exog'):
         res.predict(end=df.index[-1], exog=df.x.iloc[500:])
+
+
+def test_invalid_method(reset_randomstate):
+    ar, ma = [1, -0.5], [1., 0.4]
+    x = fa.ArmaFft(ar, ma, 40).generate_sample(nsample=1000, burnin=1000)
+    mod = ARMA(x, (1, 1))
+    with pytest.raises(ValueError, match='Method unknown not understood'):
+        mod.fit(method='unknown')
+
+
+@pytest.mark.matplotlib
+def test_summary_plots_no_dates(reset_randomstate, close_figures):
+    ar, ma = [1, -0.5], [1., 0.4]
+    x = fa.ArmaFft(ar, ma, 40).generate_sample(nsample=1000, burnin=1000)
+    res = ARMA(x, (1, 1)).fit()
+    res.plot_predict()
+    res.plot_predict(plot_insample=True)
+    assert isinstance(res.summary().as_text(), str)
+    assert isinstance(res.summary2().as_text(), str)
+
+
+def test_predict_exog_missing():
+    dta = load_macrodata_pandas().data
+    res = ARMA(dta['realcons'], (1, 1), dta['m1']).fit(disp=-1)
+    with pytest.raises(ValueError, match='You must provide exog for ARMAX'):
+        res.predict(start=203, end=210)
+
+
+def test_too_few_obs_starting_values(reset_randomstate):
+    ar, ma = [1, -0.5], [1., 0.4]
+    x = fa.ArmaFft(ar, ma, 40).generate_sample(nsample=5, burnin=100)
+    with pytest.raises(ValueError, match='Insufficient degrees of freedom'):
+        ARMA(x, (1, 6)).fit(disp=-1)
+
+
+def test_repeated_fit_error(reset_randomstate):
+    ar, ma = [1, -0.5], [1., 0.4]
+    x = fa.ArmaFft(ar, ma, 40).generate_sample(nsample=1000, burnin=100)
+    arma = ARMA(x, (1, 1))
+    arma.fit(disp=-1)
+    with pytest.raises(RuntimeError):
+        arma.fit(trend='nc')
+    with pytest.raises(RuntimeError):
+        arma.fit(method='css')
+
+
+def test_predict_no_fit():
+    ar, ma = [1, -0.5], [1., 0.4]
+    x = fa.ArmaFft(ar, ma, 40).generate_sample(nsample=1000, burnin=100)
+    arma = ARMA(x, (1, 1))
+    with pytest.raises(RuntimeError, match='Model must be fit'):
+        arma.predict([.1, .1])
+    arima = ARIMA(x, (1, 1, 1))
+    with pytest.raises(RuntimeError, match='Model must be fit'):
+        arima.predict([.1, .1])
+
+
+def test_arma_repeated_fit():
+    ar, ma = [1, -0.5], [1., 0.4]
+    x = fa.ArmaFft(ar, ma, 40).generate_sample(nsample=1000, burnin=100)
+    arma = ARMA(x, (1, 1))
+    res = arma.fit(trend='c', disp=-1)
+    repeat = arma.fit(trend='c', disp=-1)
+    rtol = 1e-5 if PLATFORM_WIN32 else 1e-7
+    assert_allclose(res.params, repeat.params, rtol=rtol)
+    assert isinstance(res.summary().as_text(), str)
+    assert isinstance(repeat.summary().as_text(), str)
+
+
+def test_arima_repeated_fit():
+    ar, ma = [1, -0.5], [1., 0.4]
+    x = fa.ArmaFft(ar, ma, 40).generate_sample(nsample=1000, burnin=100)
+    arma = ARIMA(x, (1, 1, 1))
+    res = arma.fit(trend='c', disp=-1)
+    repeat = arma.fit(trend='c', disp=-1)
+    assert_allclose(res.params, repeat.params)
+    assert isinstance(res.summary().as_text(), str)
+    assert isinstance(repeat.summary().as_text(), str)