Fit a Difference-in-Differences (DiD) regression estimating the effect of some event on treatment_date for treated_tickers, relative to control_tickers.

Also known as: DiD, DD, difference-in-differences estimator.

For more information about the method, and why the Treated x Post interaction coefficient IS the DiD treatment-effect estimate, see causal_inference_model.get_difference_in_differences.

Builds a stacked (ticker, date) panel from every ticker in treated_tickers and control_tickers: each observation’s outcome is that ticker’s return on that date, Treated is 1 for every observation belonging to a treated_tickers asset (regardless of date) and 0 for control_tickers assets, and Post is 1 for observations on or after treatment_date (regardless of asset). This answers “did treated_tickers behave differently after treatment_date, beyond both their normal average gap versus control_tickers and the common market-wide move over that same before/after window?” – e.g. isolating the effect of an event (an index-inclusion announcement, a regulatory change affecting only some tickers, an earnings surprise) that hits treated_tickers but not control_tickers, at a known date.

With returns as the outcome, the Treated x Post coefficient is the change in the average return per period after the event, not the price impact around it, which is what get_event_study measures. The panel stacks tickers observed on the same dates, whose returns are correlated, while the standard errors treat every observation as independent, so the p-value tends to be too low for closely related tickers. The estimate rests on parallel trends, so the first check is whether both groups moved alike before the event.

The formula is as follows:

\[\text{yᵢₜ} = \text{beta₀} + \text{beta₁} \cdot \text{Treatedᵢ} + \text{beta₂} \cdot \text{Postₜ} + \text{δ} \cdot (\text{Treatedᵢ} \cdot \text{Postₜ}) + \text{epsilonᵢₜ},\;\; \text{fitted by OLS with classical standard errors on the stacked (ticker, date) panel of column (Return by default)}\] \[\text{Treatedᵢ} = 1 \;\text{for}\; \text{treated\_tickers},\;\; \text{Postₜ} = 1 \;\text{on or after}\; \text{treatment\_date}\] \[\text{δ̂} = (\operatorname{mean}(y_{\text{treated}},\; \text{post}) - \operatorname{mean}(y_{\text{treated}},\; \text{pre})) - (\operatorname{mean}(y_{\text{control}},\; \text{post}) - \operatorname{mean}(y_{\text{control}},\; \text{pre}))\]

Difference-in-Differences (DiD) in Python or via the MCP

Install the Finance Toolkit with:

pip install financetoolkit -U

Then call get_difference_in_differences as shown below.

from financetoolkit import Toolkit

toolkit = Toolkit(
    ["NVDA", "INTC"],
    api_key="FINANCIAL_MODELING_PREP_KEY",
    start_date="2021-01-01",
    end_date="2025-12-31",
)

toolkit.econometrics.get_difference_in_differences(
    treated_tickers="NVDA",
    control_tickers="INTC",
    treatment_date="2023-06-01",
    period="monthly",
)

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

Did Nvidia's monthly returns rise relative to Intel's after 1 June 2023, measured from 2021 to 2025?

Which returns:

  Coefficient Std. Error t-Statistic P-Value
Intercept -0.0126 0.0262 -0.4794 0.6325
Treated 0.0669 0.0371 1.8061 0.0735
Post 0.0291 0.0362 0.8044 0.4229
Treated x Post -0.0246 0.0511 -0.4817 0.6309

Using Your Own Data

get_difference_in_differences 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_difference_in_differences with treated_tickers and treatment_date, using the column names of the data as tickers.

Parameters

get_difference_in_differences accepts the following parameters.

ParameterTypeDescriptionExample
treated_tickersstr | list[str]The asset(s) subject to the event/treatment."AAPL"
treatment_datestrThe date the event/treatment occurs, in the same format accepted by pd.Timestamp. Observations on or after this date are Post = 1."2024-06-10"
control_tickersstr | list[str] | NoneThe untreated comparison asset(s). Defaults to None, which uses every ticker NOT in treated_tickers, excluding “Benchmark” (pass control_tickers="Benchmark" to use the benchmark as the control group)."MSFT"
periodstrThe data frequency (daily, weekly, monthly, quarterly, or yearly). Defaults to “daily”."weekly"
columnstrThe historical data column to use as the outcome. Defaults to “Return”."Return"
add_constantboolWhether to include an intercept. Defaults to True.False
roundingint | NoneThe number of decimals to round the results to. Defaults to None.2
Share