Estimate a Sharp Regression Discontinuity (RDD): the jump in dependent_ticker exactly where running_variable_ticker crosses cutoff.

Also known as: RDD, sharp RD.

For more information about the method, see causal_inference_model.get_regression_discontinuity.

Treats running_variable_ticker’s value as the running variable that (hypothetically) triggers some discrete change once it crosses cutoff – e.g. testing whether dependent_ticker’s return behaves discontinuously around a round-number/threshold level of another asset or indicator (a psychological price level, an index-inclusion market-cap threshold, a macro indicator’s policy-relevant threshold) fed in as running_variable_ticker. Fits separate local linear regressions of dependent_ticker’s return on the (cutoff-centered) running_variable_ticker value, one on each side of cutoff, and reports the gap between the two fitted lines exactly at the cutoff.

The formula is as follows:

\[\text{x̃ₜ} = \text{xₜ} - \text{cutoff},\;\; \text{keeping the observations with |x̃ₜ| < h},\;\; \text{where} \;\; \text{xₜ} \;\text{is the running ticker's}\; \text{column} (\text{Return by default}) \text{and}\; h = \text{bandwidth},\;\; \text{or half the range of xₜ by default}\] \[\text{Each side} (\text{x̃ₜ} < 0 \;\text{and}\; \text{x̃ₜ} \geq 0) \text{:} \text{yₜ} = a + b \cdot \text{x̃ₜ} + \text{eₜ},\;\; \text{fitted by OLS} (\text{kernel} = \text{"uniform"},\; \text{the default}) \text{or by WLS with weights}\; 1 - | \text{x̃ₜ} | / h (\text{kernel} = \text{"triangular"})\] \[\text{Discontinuity} = a_{\text{right}} - a_{\text{left}},\;\; \text{with SE} = \sqrt{\operatorname{SE}(a_{\text{right}}) ^{2} + \operatorname{SE}(a_{\text{left}}) ^{2}}\] \[t = \text{Discontinuity} / \text{SE},\;\; \text{with a Student-t distribution on the two sides' residual degrees of freedom combined}\]

Regression Discontinuity (RDD) in Python or via the MCP

Install the Finance Toolkit with:

pip install financetoolkit -U

Then call get_regression_discontinuity as shown below.

from financetoolkit import Toolkit

toolkit = Toolkit(
    ["COIN", "BTCUSD"],
    api_key="FINANCIAL_MODELING_PREP_KEY",
    start_date="2022-01-01",
    end_date="2025-12-31",
)

# COIN's return on days Bitcoin rises versus days it falls
toolkit.econometrics.get_regression_discontinuity(
    dependent_ticker="COIN", running_variable_ticker="BTCUSD", cutoff=0
)

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

Did Coinbase's daily return jump at the point where Bitcoin's daily return turned positive, from 2022 to 2025?

Which returns:

  Value
Discontinuity 0.0031
Std. Error 0.0027
t-Statistic 1.1191
P-Value 0.2633
Cutoff 0
Bandwidth 0.1497
N Left 729
N Right 728

Using Your Own Data

get_regression_discontinuity 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, where each country is a column:

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")

Then call econometrics.get_regression_discontinuity with dependent_ticker, running_variable_ticker and cutoff, using the column names of the data as tickers.

Parameters

get_regression_discontinuity accepts the following parameters.

ParameterTypeDescriptionExample
dependent_tickerstrThe outcome asset."AAPL"
running_variable_tickerstrThe asset (or column) whose value determines which side of cutoff an observation falls on."MSFT"
cutofffloatThe threshold value of running_variable_ticker at which the discontinuity is estimated.0.01
periodstrThe data frequency (daily, weekly, monthly, quarterly, or yearly). Defaults to “daily”."weekly"
columnstrThe historical data column to use for both series. Defaults to “Return”."Return"
bandwidthfloat | NoneThe maximum distance from cutoff an observation may be to be included in either local regression. Defaults to None, which uses half of the running variable’s observed range – see causal_inference_model.get_regression_discontinuity for why this is a deliberately naive default.0.02
kernelstrOne of “uniform” or “triangular”. Defaults to “uniform”."triangular"
roundingint | NoneThe number of decimals to round the results to. Defaults to None.2
Share