Difference-in-Differences (DiD)
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.
| Parameter | Type | Description | Example |
|---|---|---|---|
treated_tickers | str | list[str] | The asset(s) subject to the event/treatment. | "AAPL" |
treatment_date | str | The 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_tickers | str | list[str] | None | The 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" |
period | str | The data frequency (daily, weekly, monthly, quarterly, or yearly). Defaults to “daily”. | "weekly" |
column | str | The historical data column to use as the outcome. Defaults to “Return”. | "Return" |
add_constant | bool | Whether to include an intercept. Defaults to True. | False |
rounding | int | None | The number of decimals to round the results to. Defaults to None. | 2 |