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.

ParameterTypeDescriptionExample
periodstrThe data frequency (daily, weekly, monthly, quarterly, or yearly). Defaults to “daily”."weekly"
columnstrThe 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_lagintThe number of lags of both assets to include in the regressions. Defaults to 5.10
include_benchmarkboolWhether to include “Benchmark” among the tickers paired up. Defaults to False.True
roundingint | NoneThe number of decimals to round the results to. Defaults to None.2
Share