Reproducing ARMA Simulations from Their Filter Equation
Summary
The document explains how to reproduce observations from a simulated ARMA process, focusing on why an observation cannot be reconstructed by multiplying earlier returns by moving-average coefficients. The MA terms apply to simulated white-noise innovations, which are generated separately from the process values. The example uses an ARMA(1,1) specification and explains the sign convention used by statsmodels’ AR and MA parameter arrays.
It describes the filter equation implemented by SciPy’s signal.lfilter and shows how to recover the generated series when the same innovation sequence is supplied. The worked recurrence for a later observation combines the current innovation, the lagged innovation, and the previous process value. The answer recommends checking the filter’s initialization behavior to understand the first values. Its example is specific to the stated parameterization and initialization, so reproducing a different simulation also requires matching its random seed, noise draws, coefficient conventions, and starting conditions.
Key ideas
- ARMA moving-average terms multiply white-noise innovations rather than earlier observed returns.
- The AR and MA coefficient conventions must match the filtering equation used by the software.
- A later process value can be computed from current and lagged innovations and lagged observations.
- Using the same innovations with the same filter can reproduce the simulated series.
- Initialization and starting conditions affect the observations at the beginning of the series.
Tags
Full text
# How are the values of the ARMA process linked in python
# How are the values of the ARMA process linked in python
In the code below, you can see that 'ret' is an ARMA process, and I am trying to see how the ret[0], etc... ret3, ret4, etc. are linked to each other, and although I know the formula for the ARMA process (see it below) , I cannot manually reproduce e.g ret[4] from the previous values... Any help?
I tried to reproduce it as below, but it does not give ret[4]
Below you can find the code in text:
```
import pandas as pd
import numpy as np
np.random.seed(200)
ar_params = np.array([1, -0.5])
ma_params = np.array([1, -0.3])
print(ar_params)
print(ma_params)
from statsmodels.tsa.arima_process import ArmaProcess
length = 5 * 252
np.random.seed(200)
ret = ArmaProcess(ar_params, ma_params).generate_sample(nsample=length)
ret = pd.Series(ret)
print('========================')
print("\nret = ", ret) ;
```
## Answer by Pleb (score 3, accepted)
https://quant.stackexchange.com/a/63073
First, note that $\epsilon_t \sim N(0,1)$ is a white noise process and the random variates are simulated from a standard normal distribution. Hence, it does not make sense for you to multiply `ret[2]` and `ret[3]` with the MA-parameters, in order to reproduce `ret[4]`.
#### The source code reveals how to reproduce the simulation values of the ARMA process:
From the source code of the ArmaProcess().generate_sample() function (see here), you will find that it effectively uses the filter algorithm from the scipy package called signal.lfilter(). The signal filter from the scipy package, can be defined as (again, see this link):
\begin{equation} \phi_0 \cdot y_t = \theta_0 \epsilon_t + \theta_{1} \epsilon_{t-1} + \ldots+\theta_{q} \epsilon_{t-q} - \phi_1 y_{t-1} - \ldots - \phi_p y_{t-p} , \end{equation} where $p$ and $q$ refers to the number of lagged terms in the filter algorithm. One way of transforming the above filter algorithm to an ARMA(p,q) process is simply to set $\phi_0 = \theta_0 = 1$ and negate the rest of the phi's. Both of these things are also noted in the documentation of the ArmaProcess().generate_sample() function, which is the reason why your above code contains 1's in the first entry of the `ar_params` and `ma_params`. Now, we can observe that the above code simulates an ARMA(1,1) process and assuming that you have already negated the AR-parameter, $\phi_1$, then `ret[4]` ($y_4$) can be found via: \begin{equation} y_4= \epsilon_4 + (- 0.3) \cdot \epsilon_{3} - y_{3} \cdot (-0.5) = 0.5 \cdot y_3 - 0.3 \cdot \epsilon_3 + \epsilon_4. \end{equation} I have provided some Python code that recovers the ArmaProcess().generate_sample() simulation using the signal.lfilter() method, which can be seen below:
```
import pandas as pd
import numpy as np
import scipy as sc
np.random.seed(200)
whitenoise = np.random.normal(size=length)
test = sc.signal.lfilter(ma_params, ar_params, whitenoise)
test = pd.Series(test)
test
```
From your own code (or you could've used test) and the above described equation, we can manually calculate `ret[4]`:
```
ret4 = ma_params[0] * whitenoise[4] + ma_params[1] * whitenoise[3] - ret[3] * ar_params[1]
ret4
```
I encourage you to read the documentation of the signal.lfilter() function to further understand how the algorithm initializes etc. However, this should be the gist of it. I hope this provide some guidance.Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.