Granger Causality
Calculate the Granger causality test, for every ordered pair of tickers in the Toolkit instance, of whether the second helps predict the first.
“Granger causality” is a statement about predictive power, not true causation: one asset is said to Granger-cause another if past values of the first, combined with past values of the second itself, predict the second significantly better than past values of the second alone.
On daily data a significant result can reflect trading hours rather than information: of two markets that close at different times, the one that closes later already contains news the other only prices the next day, so it appears to predict it. The result also depends on max_lag, so it is usually checked at a few lag lengths, and across many pairs some significant results arise by chance alone.
The formula is as follows:
\[\text{Restricted:}\;\; \text{Aₜ} = c + \operatorname{Σ}(i = 1..p) \text{aᵢ} \cdot \text{Aₜ₋ᵢ} + \text{eₜ}\] \[\text{Unrestricted:}\;\; \text{Aₜ} = c + \operatorname{Σ}(i = 1..p) \text{aᵢ} \cdot \text{Aₜ₋ᵢ} + \operatorname{Σ}(i = 1..p) \text{bᵢ} \cdot \text{Bₜ₋ᵢ} + \text{uₜ}\] \[F = ((\text{RSS}_{r} - \text{RSS}_{u}) / p) / (\text{RSS}_{u} / (T - 2p - 1)),\;\; \text{F-distributed with (p, T - 2p - 1) degrees of freedom}\] \[\text{A is the dependent and B the independent ticker's column (Return by default)},\;\; p = \text{max\_lag} (5 \;\text{by default}) \text{and}\; T \;\text{the number of observations after the lags}\]For more information about the method, see the following paper:
- Granger, C.W.J. (1969). “Investigating Causal Relations by Econometric Models and Cross-Spectral Methods.” Econometrica, 37(3), 424-438.
Also known as: Granger causality test, predictive causality, lead-lag test.
Granger Causality in Python or via the MCP
Install the Finance Toolkit with:
pip install financetoolkit -U
Then call get_granger_causality as shown below.
from financetoolkit import Toolkit
toolkit = Toolkit(
["CLUSD", "XLE"],
api_key="FINANCIAL_MODELING_PREP_KEY",
start_date="2021-01-01",
end_date="2025-12-31",
)
toolkit.econometrics.get_granger_causality()
Or, after setting up the Finance Toolkit MCP, ask:
Did the daily returns of WTI crude oil help predict those of the Energy Select Sector SPDR (XLE) from 2021 to 2025, or the other way around?
Which returns:
| F-Statistic | P-Value | Granger-Causes (5%) | |
|---|---|---|---|
| (‘CLUSD’, ‘XLE’) | 4.2749 | 0.0007 | True |
| (‘XLE’, ‘CLUSD’) | 1.5533 | 0.1705 | False |
Using Your Own Data
get_granger_causality runs on any data, not only prices: ratios, economic indicators, yield curves or your own dataset. Pass a DataFrame, a Series or a dictionary of them to Econometrics as data, with the dates in the rows or the columns, and set changes to how its changes are calculated: "percentage", "log", "difference" for rates and ratios, or None when the data are changes already. For example, for the monthly unemployment rates of the United States and Germany:
from financetoolkit import Economics, Econometrics
economics = Economics(start_date="2000-01-01")
unemployment = economics.get_unemployment_rate(
countries=["United States", "Germany"], period="monthly"
)
econometrics = Econometrics(data=unemployment, changes="difference")
econometrics.get_granger_causality()
Parameters
get_granger_causality accepts the following parameters.
| Parameter | Type | Description | Example |
|---|---|---|---|
period | str | The data frequency (daily, weekly, monthly, quarterly, or yearly). Defaults to “daily”. | "weekly" |
column | str | The historical data column to test. Defaults to “Return”, since Granger causality assumes a stationary series (unlike the ADF/Engle-Granger tests, which operate on price levels on purpose). | "Return" |
max_lag | int | The number of lags of both assets to include in the regressions. Defaults to 5. | 10 |
include_benchmark | bool | Whether to include “Benchmark” among the tickers paired up. Defaults to False. | True |
rounding | int | None | The number of decimals to round the results to. Defaults to None. | 2 |