ARIMA Analysis of Stock Returns
Нow to apply ARMA and ARIMA models using the Box-Jenkins methodology to analyze and forecast time series data effectively.
In the dynamic world of financial markets, understanding the complex patterns within time series data is essential. Analysts and investors frequently rely on ARIMA, the Autoregressive Integrated Moving Average model, as a powerful statistical tool. It helps uncover and predict subtle trends in financial time series, serving as a guide for navigating market movements.
Data
To access data using the EODHD APIs service, start by downloading and importing the EOD Python package, then authenticate with your personal API key. It’s advisable to store API keys as environment variables. We’ll utilize the EOD Historical Data API, which is included in our plans, though some plans may limit the time depth to 1–30 years.
pip install eod
import os
# load the key from the environment variables
api_key = os.environ['API_EOD']
import eod
client = EodHistoricalData(api_key)
ARIMA (p, d, q)
ARIMA models are built upon three main components:
Autoregressive (AR) Component:
This captures the relationship between a current observation and its past values. The term “autoregressive” indicates that the model uses previous observations to predict future values.
Integrated (I) Component:
This part involves differencing the time series data to achieve stationarity, which is essential for many time series models, including ARIMA. Differencing stabilizes the mean and variance of the series. For stock prices, arithmetic or log returns can be used instead of the first difference.
Moving Average (MA) Component:
This represents the relationship between an observation and the residual error from a moving average model. It accounts for short-term fluctuations in the data not explained by the autoregressive component.
The ARIMA notation, ARIMA(p, d, q), includes:
- p: the order of the autoregressive component.
- d: the degree of differencing.
- q: the order of the moving average component.
Selecting the right values for p, d, and q involves analyzing the autocorrelation function (ACF) and partial autocorrelation function (PACF) of the time series. These tools identify the presence of autoregressive and moving average components, helping to guide parameter selection for the model.
Application
Step 1 — Checking for Stationarity
Stationarity is a key concept in time series analysis. A stationary time series has statistical properties — such as mean, variance, and autocorrelation — that remain constant over time. In simple terms, it behaves consistently and predictably, making it more suitable for modeling and analysis.
To assess stationarity, various tests can be used, including the Phillips-Perron, KPSS, and Augmented Dickey-Fuller (ADF) tests. These tests check for the presence of a unit root, which indicates a coefficient of 1 for the first lagged term (ϕ1) in the AR process. A unit root implies that the series relies on its past value plus a random term (εt).
The function below can be used to test for stationarity:
def ADF(time_series):
trend_types = ['c', 'ct', 'n']
for trend in trend_types:
print(f"Augmented Dickey-Fuller (ADF) test with trend '{trend}':")
result = sm.tsa.adfuller(time_series, autolag='AIC', regression=trend)
print(f'ADF Statistic: {result[0]}')
print(f'p-value: {result[1]}')
print('Critical Values:')
for key, value in result[4].items():
print(f' {key}: {value}')
if result[1] <= 0.05:
print("Reject the null hypothesis; the time series has no unit root.\n")
else:
print("Fail to reject the null hypothesis; the time series has a unit root.\n")
Step 2 — Analyzing the Auto Correlation and Partial Autocorrelation Functions
Once the series becomes stationary, the next step is to analyze the Autocorrelation Function (ACF) and Partial Autocorrelation Function (PACF) to determine the ARMA structure of the process.
Identifying the values for p (order of AR) and q (order of MA) can often feel more like an art than a science, as the process may not always be straightforward. For this reason, it’s recommended to start with a more complex model and refine it through testing to arrive at a simpler, parsimonious model. Models with fewer parameters are generally preferred for their simplicity and efficiency.
The image below outlines the essentials for determining the order of any ARMA structure, along with examples to help guide the process:
The functions below can be used to plot the ACF and PACF during analysis:
def ACF(variable):
sm.graphics.tsa.plot_acf(variable, lags=20)
plt.title("ACF")
plt.show()
def PACF(variable):
sm.graphics.tsa.plot_pacf(variable, lags=20)
plt.title("PACF")
plt.show()
Step 3 — Modeling ARMA(p, q)
After identifying the values for p and q, the next step is to construct an ARMA(p, q) model. The process can be carried out using the approach described below:
import statsmodels.api as sm
p_order = 1 # AR order
q_order = 1 # MA order
d_order = 0 # differencing order
model = sm.tsa.ARIMA(series, order=(p_order, d_order, q_order))
model_fit = model.fit()
print(model_fit.summary())
Step 4 — Interpreting Summary
In the provided sample summary, the coefficients for the AR and MA processes can be observed, and their effectiveness in describing the series is evaluated based on their respective p-values. For instance, if the p-value for the MA component exceeds the significance level (1%, 5%, or 10%), it may be advisable to exclude the MA part and use a pure AR model instead.
When two models reliably describe the series, it is best to choose the most parsimonious model. Models can be compared using selection criteria such as the Akaike Information Criterion (AIC), Bayesian Information Criterion (BIC), and Hannan-Quinn Information Criterion (HQIC), with the lowest value indicating the better-fitting model.
Example: NVIDIA Stock
To collect the data, the Official Financial Python library is used. The process starts with retrieving data for NVIDIA, going back to March 2014. Stock information is obtained using the get_historical_data
function.
start = "2014-03-01"
prices = api.get_historical_data("NVDA", interval="d", iso8601_start=start,
iso8601_end="2024-03-01")["adjusted_close"].astype(float)
prices.name = "NVDA"
Using the provided code and API, the stock’s closing prices can be retrieved and visualized. A quick inspection reveals that the data is not stationary. To address this, a stationarity test, such as the ADF test, should be conducted to identify the trend type and remove it. Since prices often behave as random walks, reflecting their past value plus a random term, analyzing returns is recommended. This approach helps stabilize the data for further analysis.
Calculating Returns
returns = log(prices/prices.shift(1))[1:]
Look how well-structured it is! Now the data is ready for analysis. While some outliers and clustering remain in the returns, it is sufficient for educational purposes to proceed with further analysis of NVIDIA’s stock return behavior.
Autocorrelation and Partial Autocorrelation Functions
By examining the ACF plot, significant spikes beyond the shaded region indicate the presence of an MA term with a q order of 1. While there are spikes at lag orders 7 and 8, it is possible to construct a degenerate model by excluding lags between 1 and 7. However, for simplicity and to achieve a more parsimonious model, we will proceed with q set to 1.
Using the same approach to determine p for the AR term, a similar pattern emerges, leading to the same result as for q.
Based on these observations, we proceed with modeling an ARMA(1,1) process.
Result Summary
Identifying the best-fitting model for a time series can be challenging, and it’s important to explore multiple possibilities before making a decision. In the initial attempt with the ARMA(1,1) model, both the AR and MA term coefficients were statistically insignificant, indicating that the model would perform better without them.
To refine the analysis, it’s advisable to test two alternative models: one excluding the MA term and another excluding the AR term. As demonstrated earlier, the coefficients in both the AR(1) and MA(1) models were statistically significant, and both models had the same number of parameters.
To finalize the choice, selection criteria were applied. The AR(1) model showed lower values across all three criteria — Akaike Information Criterion (AIC), Bayesian Information Criterion (BIC), and Hannan-Quinn Information Criterion (HQIC) — making it the preferred model.
With the insights from this article, you should be equipped to apply the Box–Jenkins methodology for fitting ARMA or ARIMA models to identify the best time-series model for your data.
We hope you found this article both interesting and useful!
Please note that this article is for informational purposes only and should not be taken as financial advice. We do not bear responsibility for any trading decisions made based on the content of this article. Readers are advised to conduct their own research or consult with a qualified financial professional before making any investment decisions.
For those eager to delve deeper into such insightful articles and broaden their understanding of different strategies in financial markets, we invite you to follow our account and subscribe for email notifications.
Stay tuned for more valuable articles that aim to enhance your data science skills and market analysis capabilities.