Calculate the Breusch-Pagan test for heteroskedasticity of a regression of dependent_ticker on independent_tickers.

OLS standard errors assume that the residual variance is constant (homoskedasticity). The test regresses the squared residuals of the regression on the original independent tickers and checks whether they explain any of the residual variance, by testing whether the R-squared of that auxiliary regression is significantly different from zero.

The formula is as follows:

\[\text{Auxiliary regression:}\;\; e_{t} ^{2} = a_{0} + a' \cdot x_{t} + v_{t},\;\; \text{with e\_t the OLS residuals and x\_t the independent tickers' column (Return by default)}\] \[\text{LM} = n \cdot R ^{\text{2\_auxiliary}} (\text{Koenker's studentized form},\; \text{the statsmodels default})\]

This is the studentized statistic of Koenker (1981), which does not assume normally distributed errors. It is asymptotically chi-squared distributed with k - 1 degrees of freedom under the null hypothesis of homoskedasticity, where k is the number of parameters of the auxiliary regression. A low p-value means the residual variance moves with the independent tickers (for example, errors grow when the market moves more), so the regression’s standard errors, t-statistics and p-values are unreliable even though the coefficients themselves remain unbiased. Remedies are a robust cov_type in get_ols or get_wls. get_white_test is a more general alternative that also catches non-linear forms of heteroskedasticity.

For more information about the method, see the following paper:

  • Breusch, T.S., & Pagan, A.R. (1979). “A Simple Test for Heteroscedasticity and Random Coefficient Variation.” Econometrica, 47(5), 1287-1294.
  • Koenker, R. (1981). “A Note on Studentizing a Test for Heteroscedasticity.” Journal of Econometrics, 17(1), 107-112.

Also known as: BP test, Breusch-Pagan-Godfrey test.

Breusch-Pagan Test in Python or via the MCP

Install the Finance Toolkit with:

pip install financetoolkit -U

Then call get_breusch_pagan_test as shown below.

from financetoolkit import Toolkit

toolkit = Toolkit(
    ["CAT", "DE"],
    api_key="FINANCIAL_MODELING_PREP_KEY",
    start_date="2025-01-01",
    end_date="2025-12-31",
)

# CAT (the first ticker) is dependent; DE is independent
toolkit.econometrics.get_breusch_pagan_test()

Or, after setting up the Finance Toolkit MCP, ask:

Was a regression of Caterpillar's daily returns on Deere's heteroskedastic in 2025, according to the Breusch-Pagan test?

Which returns:

  Value
Breusch-Pagan Statistic 0.0129
P-Value 0.9096
Reject Homoskedasticity (5%) 0

Using Your Own Data

get_breusch_pagan_test 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_breusch_pagan_test()

Parameters

get_breusch_pagan_test accepts the following parameters.

ParameterTypeDescriptionExample
dependent_tickerstr | NoneThe dependent (predicted) asset. Defaults to None, meaning the Toolkit instance’s first ticker."AAPL"
independent_tickersstr | list[str] | NoneThe independent (predictor) asset(s). Defaults to None, meaning every other ticker in the Toolkit instance besides dependent_ticker.["MSFT", "Benchmark"]
include_benchmarkboolWhether to include “Benchmark” in the default independent ticker(s) (has no effect when independent_tickers is given explicitly). Defaults to False.True
periodstrThe data frequency (daily, weekly, monthly, quarterly, or yearly). Defaults to “daily”."weekly"
columnstrThe historical data column to regress on. Defaults to “Return”."Return"
add_constantboolWhether to include an intercept in the underlying regression. Defaults to True.False
roundingint | NoneThe number of decimals to round the results to. Defaults to None.2
Share