{"id":16510204,"url":"https://github.com/mcaceresb/stata-honestdid","last_synced_at":"2026-01-26T21:51:28.798Z","repository":{"id":62613978,"uuid":"511741721","full_name":"mcaceresb/stata-honestdid","owner":"mcaceresb","description":"Robust inference in difference-in-differences and event study designs (Stata version of the R package of the same name) ","archived":false,"fork":false,"pushed_at":"2025-04-02T01:35:25.000Z","size":4264,"stargazers_count":103,"open_issues_count":6,"forks_count":22,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-11-17T20:34:39.602Z","etag":null,"topics":["difference-in-differences","event-studies","robust-inference"],"latest_commit_sha":null,"homepage":"","language":"Stata","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mcaceresb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-07-08T02:52:51.000Z","updated_at":"2025-10-30T03:28:45.000Z","dependencies_parsed_at":"2024-10-18T13:46:19.090Z","dependency_job_id":"edb67eac-fc4a-4333-abcc-73a597ba6881","html_url":"https://github.com/mcaceresb/stata-honestdid","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mcaceresb/stata-honestdid","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcaceresb%2Fstata-honestdid","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcaceresb%2Fstata-honestdid/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcaceresb%2Fstata-honestdid/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcaceresb%2Fstata-honestdid/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mcaceresb","download_url":"https://codeload.github.com/mcaceresb/stata-honestdid/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcaceresb%2Fstata-honestdid/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28789146,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-26T21:49:50.245Z","status":"ssl_error","status_checked_at":"2026-01-26T21:48:29.455Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["difference-in-differences","event-studies","robust-inference"],"created_at":"2024-10-11T15:54:25.233Z","updated_at":"2026-01-26T21:51:28.792Z","avatar_url":"https://github.com/mcaceresb.png","language":"Stata","funding_links":[],"categories":[],"sub_categories":[],"readme":"HonestDiD\n=========\n\nThe HonestDiD package implements the tools for robust inference and\nsensitivity analysis for differences-in-differences and event study\ndesigns developed in [Rambachan and Roth (2022)](https://asheshrambachan.github.io/assets/files/hpt-draft.pdf).\nThis is the Stata version of the [R package of the same name](https://github.com/asheshrambachan/HonestDiD). There is also a [Shiny app](https://ccfang2.shinyapps.io/HonestDiDSenAnlys/) developed by Chengcheng Fang.\n\n`version 1.3.4 27Feb2025` | [Background](#background) | [Installation](#package-installation) | [Examples](#example-usage----medicaid-expansions) | [Acknowledgements](#acknowledgements)\n\n## Background\n\nThe robust inference approach in Rambachan and Roth formalizes the\nintuition that pre-trends are informative about violations of parallel\ntrends. They provide a few different ways of formalizing what this\nmeans.\n\n**Bounds on relative magnitudes.** One way of formalizing this idea is\nto say that the violations of parallel trends in the post-treatment\nperiod cannot be much bigger than those in the pre-treatment period.\nThis can be formalized by imposing that the post-treatment violation of\nparallel trends is no more than some constant $\\bar{M}$ larger than the\nmaximum violation of parallel trends in the pre-treatment period. The\nvalue of $\\bar{M} = 1$, for instance, imposes that the post-treatment\nviolation of parallel trends is no longer than the worst pre-treatment\nviolation of parallel trends (between consecutive periods). Likewise,\nsetting $\\bar{M} = 2$ implies that the post-treatment violation of\nparallel trends is no more than twice that in the pre-treatment period.\n\n**Smoothness restrictions.** A second way of formalizing this is to say\nthat the post-treatment violations of parallel trends cannot deviate too\nmuch from a linear extrapolation of the pre-trend. In particular, we can\nimpose that the slope of the pre-trend can change by no more than *M*\nacross consecutive periods, as shown in the figure below for an example\nwith three periods.\n\n![diagram-smoothness-restriction](src/assets/deltaSD.png)\n\nThus, imposing a smoothness restriction with $M = 0$ implies that the\ncounterfactual difference in trends is exactly linear, whereas larger\nvalues of $M$ allow for more non-linearity.\n\n**Other restrictions**. The Rambachan and Roth framework allows for a\nvariety of other restrictions on the differences in trends as well.\nHowever, not all these have yet been implemented in this Stata version\nof the package. This functionality is planned for a future release.\n\n**Robust confidence intervals**. Given restrictions of the type\ndescribed above, Rambachan and Roth provide methods for creating robust\nconfidence intervals that are guaranteed to include the true parameter\nat least 95% of the time when the imposed restrictions on satisfied.\nThese confidence intervals account for the fact that there is estimation\nerror both in the treatment effects estimates and our estimates of the\npre-trends.\n\n**Sensitivity analysis**. The approach described above naturally lends\nitself to sensitivity analysis. That is, the researcher can report\nconfidence intervals under different assumptions about how bad the\npost-treatment violation of parallel trends can be (e.g., different\nvalues of $\\bar{M}$ or $M$.) They can also report the \"breakdown value\"\nof $\\bar{M}$ (or $M$) for a particular conclusion---e.g. the largest\nvalue of $\\bar{M}$ for which the effect is still significant.\n\n## Package installation\n\nThe package may be installed by using `net install` for the latest version:\n\n```stata\nlocal github https://raw.githubusercontent.com\nnet install honestdid, from(`github'/mcaceresb/stata-honestdid/main) replace\nhonestdid _plugin_check\n```\n\nVersion `1.3.0` (`25Jan2024`) of the package is currently available via SSC:\n\n```stata\nssc install honestdid\nhonestdid _plugin_check\n```\n\n## Compiling\n\n`honestdid` uses compiled C code internally; if you receive an error\nmessage saying \"Failed to load OSQP/ECOS plugin\" then you will need\nto compile the plugin in order to use `honestdid`. While we provide\npre-compiled binaries, they may not work on every system. If you are\nusing OSX or Linux, compiling is relatively straightforward. From a\nterminal, run:\n\n```bash\ngit clone https://github.com/mcaceresb/stata-honestdid\ncd stata-honestdid\nbash src/compile.sh\n```\n\nYou're required to have `make`, `cmake`, and `clang` (OSX) or `gcc`\n(Linux) installed; all three should be readily available on any OSX or\nLinux system. On Windows:\n\n1. Install [Cygwin](https://www.cygwin.com).\n2. Install `binutils`, `make`, `cmake`, `gcc-core`, `gcc-g++`, `mingw64-x86_64-gcc-core`, `mingw64-x86_64-gcc-g++`, `mingw64-x86_64-dlfcn`\n3. Open the Cygwin terminal and run\n\n```bash\ngit clone https://github.com/mcaceresb/stata-honestdid\ncd stata-honestdid\nsed -i 's/\\r$//' src/compile.sh\nbash src/compile.sh\n```\n\nOnce the plugin is compiled, from a Stata session run\n\n```stata\ncd /path/to/stata-honestdid/\ndo src/install.do\n```\n\n(On Windows, the repo will likely be somewhere in `C:\\cygwin64\\home\\..`,\ndepending on where you installed Cygwin.) If compiling the plugin yourself does\nnot fix it, please open an issue.\n\n## Example usage -- Medicaid expansions\n\nAs an illustration of the package, we will examine the effects of\nMedicaid expansions on insurance coverage using publicly-available data\nderived from the ACS. We first load the data and packages relevant for\nthe analysis.\n\n```stata\n* Install here coefplot, ftools, reghdfe, plot scheme\nlocal github https://raw.githubusercontent.com\nssc install coefplot,      replace\nssc install ftools,        replace\nssc install reghdfe,       replace\nnet install scheme-modern, replace from(`github'/mdroste/stata-scheme-modern/master)\nset scheme modern\n\n* Load data\nlocal mixtape https://raw.githubusercontent.com/Mixtape-Sessions\nuse `mixtape'/Advanced-DID/main/Exercises/Data/ehec_data.dta, clear\nl in 1/5\n```\n\n```\n     +--------------------------------------------+\n     |  stfips   year       dins   yexp2        W |\n     |--------------------------------------------|\n  1. | alabama   2008   .6814122       .   613156 |\n  2. | alabama   2009   .6580621       .   613156 |\n  3. | alabama   2010   .6313651       .   613156 |\n  4. | alabama   2011   .6563886       .   613156 |\n  5. | alabama   2012   .6708115       .   613156 |\n     +--------------------------------------------+\n```\n\nThe data is a state-level panel with information on health insurance\ncoverage and Medicaid expansion. The variable `dins` shows the share of\nlow-income childless adults with health insurance in the state. The\nvariable `yexp2` gives the year that a state expanded Medicaid coverage\nunder the Affordable Care Act, and is missing if the state never\nexpanded.\n\n### Estimate the baseline DiD\n\nFor simplicity, we will first focus on assessing sensitivity to\nviolations of parallel trends in a non-staggered DiD (see below\nregarding methods for staggered timing). We therefore restrict the\nsample to the years 2015 and earlier, and drop the small number of\nstates who are first treated in 2015. We are now left with a panel\ndataset where some units are first treated in 2014 and the remaining\nunits are not treated during the sample period. We can then estimate the\neffects of Medicaid expansion using a canonical two-way fixed effects\nevent-study specification,\n\n$$\nY_{it} = \\alpha_i + \\lambda_t + \\sum_{s \\ne 2013} 1[s = t] \\times D_i \\times \\beta_s + u_{it}\n$$\n\nwhere $D$ is 1 if a unit is first treated in 2014 and 0 otherwise.\n\n\n```stata\n* Keep years before 2016. Drop the 2016 cohort\nkeep if (year \u003c 2016) \u0026 (missing(yexp2) | (yexp2 != 2015))\n\n* Create a treatment dummy\ngen byte D = (yexp2 == 2014)\ngen `:type year' Dyear = cond(D, year, 2013)\n\n* Run the TWFE spec\nreghdfe dins b2013.Dyear, absorb(stfips year) cluster(stfips) noconstant\n\nlocal plotopts ytitle(\"Estimate and 95% Conf. Int.\") title(\"Effect on dins\")\ncoefplot, vertical yline(0) ciopts(recast(rcap)) xlabel(,angle(45)) `plotopts'\n```\n\n\u003c!-- --\u003e\n![fig](doc/readme_coefplot.png)\n\n## Sensitivity analysis using relative magnitudes restrictions\n\nWe are now ready to apply the HonestDiD package to do sensitivity\nanalysis. Suppose we’re interested in assessing the sensitivity of\nthe estimate for 2014, the first year after treatment.  The `pre()` and\n`post()` options specify the indices of the coefficients corresponding\nwith pre-treatment and post-treatment event-study coefficients\n(excluding the one for 2013, which is normalized to zero); Stata's\n`numlist` notation is allowed. Finally, `mvec()` specifies the values of\n$\\bar{M}$.\n\n```stata\nhonestdid, pre(1/5) post(7/8) mvec(0.5(0.5)2)\n```\n\n```\n|    M    |   lb   |   ub   |\n| ------- | ------ | ------ |\n|       . |  0.029 |  0.064 | (Original)\n|  0.5000 |  0.024 |  0.067 |\n|  1.0000 |  0.017 |  0.072 |\n|  1.5000 |  0.008 |  0.080 |\n|  2.0000 | -0.001 |  0.088 |\n(method = C-LF, Delta = DeltaRM, alpha = 0.050)\n```\n\nFirst, note in this case the coefficients are ordered and mostly\ncontiguous, so `pre(1/5)` refers to entries 1 through 5 and `post(7/8)`\nrefers to entries 7 through 8. If the coefficients happen to be in\ndifferent orders, positions, or if there are controls included in the\nregression, the user can pass an arbitrary list of indices to `pre()`\nand `post()`. For instance,\n\n```stata\nhonestdid, pre(1 2 3 4 5) post(7 8) mvec(0.5(0.5)2)\n```\n\ngives the same result. Second, note the coefficient vector returned by\n`reghdfe` includes an entry for `2013`, the reference period, which was\nomitted from the regression but is included in the vector of estimates.\nIt is possible to tell `honestdid` to ignore omitted regressors when\nspecifying variable indices; this can be specially useful when there\nare many such covariates. For example,\n\n```stata\nreghdfe dins b2013.year##D, absorb(stfips year) cluster(stfips) noconstant\nmatrix list e(b)\nhonestdid, pre(1/5) post(6/7) mvec(0.5(0.5)2) omit\n```\n\ngives the same results (i.e. the coefficient vector contains several\nzeros from omitted regressors, but with the `omit` option we only needed\nto specify the indices for the included regressors). It's important that\nhere the post-period indices are 6 and 7, since the reference period is\nno longer included. Further, the `omit` option does **not** exclude\nzeros; rather, it excludes vector entries indicated to have been omitted\nfrom a regression (based on the column names of the coefficient vector;\nsee `help _ms_omit_info` for more).\n\nFinally, in the special case where there are no controls or where the\nuser has gathered the pre- and post-treatment coefficients into a custom\nvector, it is also possible to specify just the number of pre-treatment\nperiods via `numpre()` and `honestdid` will automatically assume the\nfirst `numpre` entries are pre-treatment coefficients and the rest are\npost-treatment coefficients.\n\n```stata\nreghdfe dins b2013.Dyear, absorb(stfips year) cluster(stfips) noconstant\nhonestdid, numpre(5) mvec(0.5(0.5)2) omit\n\nmata index = 1..5, 7..8\nmata st_matrix(\"b\", st_matrix(\"e(b)\")[index])\nmata st_matrix(\"V\", st_matrix(\"e(V)\")[index, index])\nmatrix list b\nmatrix list V\nhonestdid, numpre(5) mvec(0.5(0.5)2)\n```\n\nIn all cases, the output of the `honestdid` command shows a robust\nconfidence interval for different values of $\\bar{M}$. We see that the\n\"breakdown value\" for a significant effect is $\\bar{M} \\approx 2$,\nmeaning that the significant result is robust to allowing for violations\nof parallel trends up to twice as big as the max violation in the\npre-treatment period.\n\nWe can also visualize the sensitivity analysis using the `coefplot`\noption. We can pass the option at the time of the CI computation or we\ncan use the last results from `honestdid` (which are cached in memory).\n\n```stata\nhonestdid, coefplot cached\n```\n\nAdditional options are passed to `coefplot`\n\n```stata\nlocal plotopts xtitle(Mbar) ytitle(95% Robust CI)\nhonestdid, cached coefplot `plotopts'\n```\n\n\u003c!-- --\u003e\n![fig](doc/readme_deltarm_ex1.png)\n\n## Sensitivity Analysis Using Smoothness Restrictions\n\nWe can also do a sensitivity analysis based on smoothness\nrestrictions---i.e. imposing that the slope of the difference in trends\nchanges by no more than $M$ between periods.\n\n```stata\nlocal plotopts xtitle(M) ytitle(95% Robust CI)\nhonestdid, pre(1/5) post(6/7) mvec(0(0.01)0.05) delta(sd) omit coefplot `plotopts'\n```\n\n```\n|    M    |   lb   |   ub   |\n| ------- | ------ | ------ |\n|       . |  0.029 |  0.064 | (Original)\n|  0.0000 |  0.026 |  0.061 |\n|  0.0100 |  0.013 |  0.079 |\n|  0.0200 |  0.003 |  0.091 |\n|  0.0300 | -0.007 |  0.101 |\n|  0.0400 | -0.017 |  0.111 |\n|  0.0500 | -0.027 |  0.121 |\n(method = FLCI, Delta = DeltaSD, alpha = 0.050)\n```\n\n\u003c!-- --\u003e\n![fig](doc/readme_deltasd_ex1.png)\n\nWe see that the breakdown value for a significant effect is $M \\approx 0.03$,\nmeaning that we can reject a null effect unless we are willing to allow\nfor the linear extrapolation across consecutive periods to be off by\nmore than 0.03 percentage points.\n\n## Sensitivity Analysis for Average Effects or Other Periods\n\nSo far we have focused on the effect for the first post-treatment\nperiod, which is the default in HonestDiD. If we are instead interested\nin the average over the two post-treatment periods, we can use the\noption `l_vec(matrix_name)`:\n```\nmatrix l_vec = 0.5 \\ 0.5\nlocal plotopts xtitle(Mbar) ytitle(95% Robust CI)\nhonestdid, l_vec(l_vec) pre(1/5) post(6/7) mvec(0(0.5)2) omit coefplot `plotopts'\n```\n\n```\n|    M    |   lb   |   ub   |\n| ------- | ------ | ------ |\n|       . |  0.040 |  0.075 | (Original)\n|  0.0000 |  0.041 |  0.075 |\n|  0.5000 |  0.033 |  0.080 |\n|  1.0000 |  0.020 |  0.090 |\n|  1.5000 |  0.006 |  0.103 |\n|  2.0000 | -0.008 |  0.117 |\n(method = C-LF, Delta = DeltaRM, alpha = 0.050)\n```\n\n\u003c!-- --\u003e\n![fig](doc/readme_deltarm_ex2.png)\n\nMore generally, the package accommodates inference on any scalar\nparameter of the form $\\theta = l_{vec}'\\tau_{post}$, where\n$\\tau_{post} = (\\tau_1,...,\\tau_{\\bar{T}})'$ is the vector of dynamic\ntreatment effects. Thus, for example, creating `matrix l_vec = 0 \\ 1`\nand setting `l_vec(l_vec)` allows us to do inference on the effect for\nthe second period after treatment.\n\n## Speeding up with the parallel package\n\n`honestdid` has built-in support for the user-written\n[parallel](https://github.com/gvegayon/parallel) package (latest stable\nversion required). `parallel(#)` can be specified as an option with `#`\nsignifying the number of cores (parallel processes; default 4). Each\ncore processes an $M$ in parallel. For example,\n\n```stata\nnet install parallel, from(https://raw.github.com/gvegayon/parallel/stable) replace\nmata mata mlib index\nhonestdid, pre(1/5) post(7/8) mvec(0.5(0.5)2) parallel(4)\n```\n\nprocesses each entry of `mvec` in a different core (with 8 values, 2\nwould be processed per core and so on; further, if more cores than $M$\nare requested, the additional cores are not used). Note the `parallel`\npackage creates several temporary files in the current working directory;\n`honestdid` runs `parallel clean` to delete them after a successful\nrun, but in case of an error the user may need to delete them manually.\n\n## Staggered Timing\n\nSo far we have focused on a simple case without staggered\ntiming.  Fortunately, the HonestDiD approach works well with\nrecently-introduced methods for DiD under staggered treatment\ntiming. Specifically, the HonestDiD can be used with any estimator that produces a\nvector of (asymptotically normal) event study coefficients, provided one is willing to impose relative magnitudes or smoothness restricts that relate the bias of the \"post-treatment\" estimates to the \"pre-treatment\" estimates.  Below, we show how the package can be used with several recent methods for DiD with staggered treatment timing. We start with an example implementing using the [did package](https://github.com/bcallaway11/did#difference-in-differences-)\nimplementing Callaway and Sant’Anna.\n\n```stata\nlocal mixtape https://raw.githubusercontent.com/Mixtape-Sessions\nuse `mixtape'/Advanced-DID/main/Exercises/Data/ehec_data.dta, clear\nqui sum year, meanonly\nreplace yexp2 = cond(mi(yexp2), r(max) + 1, yexp2)\nqui csdid dins, time(year) ivar(stfips) gvar(yexp2) long2 notyet\ncsdid_estat event, window(-4 5) estore(csdid)\nestimates restore csdid\n\nlocal plotopts xtitle(Mbar) ytitle(95% Robust CI)\nhonestdid, pre(3/6) post(7/12) mvec(0.5(0.5)2) coefplot `plotopts'\n```\n\n\u003c!-- --\u003e\n![fig](doc/readme_deltarm_csdid.png)\n\nHonestDiD is also compatible\nwith the estimator introduced in Chaisemartin and D'Haultfoeuille (2020),\navailable for Stata via the `did_multiplegt` package.\n\n```stata\nlocal mixtape https://raw.githubusercontent.com/Mixtape-Sessions\nuse `mixtape'/Advanced-DID/main/Exercises/Data/ehec_data.dta, clear\ngen byte D = (year \u003e= yexp2) \u0026 !mi(yexp2)\ndid_multiplegt dins stfips year D, robust_dynamic dynamic(5) placebo(5) breps(50) cluster(stfips)\nhonestdid, pre(7/11) post(1/6) vcov(didmgt_vcov) b(didmgt_results_no_avg)\n```\n\n\u003c!-- --\u003e\n![fig](doc/readme_did_multiplegt.png)\n\nHonestDiD is also compatible with the `jwdid` estimator that implements the\nestimation approach proposed by Wooldridge (2021).\n\n```stata\nlocal mixtape https://raw.githubusercontent.com/Mixtape-Sessions\nuse `mixtape'/Advanced-DID/main/Exercises/Data/ehec_data.dta, clear\njwdid dins, ivar(stfips) time(year) gvar(yexp2) cluster(stfips) never\nestat event, post\nhonestdid, pre(1/8) post(10/14) vcov(e(V)) b(e(b)) mvec(0(0.1)1) delta(rm)\n```\n\n\u003c!-- --\u003e\n![fig](doc/readme_jwdid.png)\n\n## Additional options and resources\n\nYou can view a video presentation about this paper [here](https://www.youtube.com/watch?v=6-NkiA2jN7U).\n\n## Authors\n\n- [Mauricio Cáceres Bravo](https://mcaceresb.github.io)\n- [Ashesh Rambachan](https://asheshrambachan.github.io)\n- [Jonathan Roth](https://jonathandroth.github.io)\n\n## Acknowledgements\n\nThis software package is based upon work supported by the National\nScience Foundation Graduate Research Fellowship under Grant DGE1745303\n(Rambachan) and Grant DGE1144152 (Roth).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmcaceresb%2Fstata-honestdid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmcaceresb%2Fstata-honestdid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmcaceresb%2Fstata-honestdid/lists"}