-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathxt2treatments.ado
195 lines (169 loc) · 5.91 KB
/
xt2treatments.ado
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
*! version 0.8.4 21may2024
program xt2treatments, eclass
version 18.0
syntax varname(numeric) [if], treatment(varname numeric) control(varname numeric) [, pre(integer 1) post(integer 3) baseline(string) weighting(string) graph]
if ("`baseline'" == "") {
local baseline "-1"
}
if ("`weighting'" == "") {
local weighting "equal"
}
local T1 = `pre'-1
local K = `pre'+`post'+1
marksample touse
* read panel structure
xtset
local group = r(panelvar)
local time = r(timevar)
local y `varlist'
tempvar yg evert everc time_g dy eventtime n_g n_gt
tempname w W0 bad_coef bad_Var b V Wcum Wsum D
quietly egen `evert' = max(cond(`touse', `treatment', 0)), by(`group')
quietly egen `everc' = max(cond(`touse', `control', 0)), by(`group')
* no two treatment can happen to the same group
capture assert !(`evert' & `everc') if `touse'
if (_rc) {
display in red "Some groups receive both treatments"
inspect `group' if `evert' & `everc' & `touse'
error(459)
}
quietly egen `time_g' = min(cond(`treatment' | `control', `time', .)) if `touse', by(`group')
* everyone receives treatment
capture assert !missing(`time_g') if `touse'
if (_rc) {
display in red "Some groups do not receive any treatment"
inspect `group' if !`evert' & !`everc' & `touse'
error(459)
}
quietly generate `eventtime' = `time' - `time_g' if `touse'
quietly egen `n_gt' = count(1) if `touse', by(`time_g' `time')
quietly egen `n_g' = max(`n_gt') if `touse', by(`time_g')
quietly levelsof `time_g' if `touse', local(gs)
quietly levelsof `time' if `touse', local(ts)
local G : word count `gs'
local T : word count `ts'
local N = `G' * (`T' - 1)
tempname n1 n0
matrix `w' = J(`G', `T', 0.0)
forvalues g = 1/`G' {
forvalues t = 2/`T' {
local time_t : word `t' of `ts'
local cohort : word `g' of `gs'
local e = `time_t' - `cohort'
if inrange(`e', -`pre', `post') {
quietly count if `time_g' == `cohort' & (`touse') & `everc' & `time_t' == `time'
scalar `n0' = r(N)
quietly count if `time_g' == `cohort' & (`touse') & `evert' & `time_t' == `time'
scalar `n1' = r(N)
if ("`weighting'" == "equal") {
* if either of the groups has no observations, we cannot estimate a treatment effect
matrix `w'[`g', `t'] = cond(`n0'*`n1'==0, 0.0, 1.0)
}
if ("`weighting'" == "proportional") {
matrix `w'[`g', `t'] = cond(`n0'*`n1'==0, 0.0, `n0' + `n1')
}
if ("`weighting'" == "optimal") {
matrix `w'[`g', `t'] = cond(`n0'*`n1'==0, 0.0, `n0' * `n1' / (`n0' + `n1'))
}
}
}
}
quietly egen `yg' = mean(cond(`eventtime' == -1, `y', .)) if `touse', by(`group')
quietly generate `dy' = `y' - `yg' if `touse'
capture drop _att_*
forvalues g = 1/`G' {
forvalues t = 2/`T' {
local running_time : word `t' of `ts'
local treatment_time : word `g' of `gs'
quietly generate byte _att_`g'_`t' = cond(`time_g' == `treatment_time' & `time' == `running_time', `evert', 0) if `touse'
}
}
***** This is the actual estimation
quietly reghdfe `dy' _att_*_* if `touse', a(`time_g'##`time') cluster(`group') nocons
matrix `bad_coef' = e(b)
matrix `bad_Var' = e(V)
local GT = colsof(`bad_coef')
assert `GT' == `G' * `=`T'-1'
assert colsof(`bad_Var') == `GT'
matrix `Wcum' = J(`GT', `K', 0)
local i = 1
forvalues g = 1/`G' {
forvalues t = 2/`T' {
local time_t : word `t' of `ts'
local start : word `g' of `gs'
local e = `time_t' - `start'
if inrange(`e', -`pre', `post') {
matrix `Wcum'[`i', `e' + `pre' + 1] = `w'[`g', `t']
}
local i = `i' + 1
}
}
matrix `Wsum' = J(1, `GT', 1) * `Wcum'
matrix `D' = diag(`Wsum')
matrix `Wcum' = `Wcum' * inv(`D')
tempvar esample
* exclude observations outside of the event window
quietly generate `esample' = e(sample)
quietly replace `esample' = 0 if !`touse'
quietly count if `esample'
local Nobs = r(N)
******
capture drop _att_*
if ("`baseline'" == "average") {
matrix `W0' = I(`K') - (J(`K', `pre', 1/`pre'), J(`K', `post'+1, 0))
}
else if ("`baseline'" == "atet") {
matrix `W0' = (J(1, `pre', -1/`pre'), J(1, `post'+1, 1/(`post'+1)))
}
else {
if (!inrange(`baseline', -`pre', -1)) {
display in red "Baseline must be between -`pre' and -1"
error 198
}
matrix `W0' = I(`K')
local bl = `pre' + `baseline' + 1
forvalues i = 1/`K' {
matrix `W0'[`i', `bl'] = `W0'[`i', `bl'] - 1.0
}
}
matrix `b' = `bad_coef' * `Wcum' * `W0''
matrix `V' = `W0' * `Wcum'' * `bad_Var' * `Wcum' * `W0''
if ("`baseline'" == "atet") {
local colnames "ATET"
}
else {
* label coefficients
forvalues t = -`pre'/`post' {
local colnames `colnames' `t'
}
}
matrix colname `b' = `colnames'
matrix colname `V' = `colnames'
matrix rowname `V' = `colnames'
local level 95
tempname coefplot
matrix `coefplot' = J(`K', 4, .)
matrix colname `coefplot' = xvar b ll ul
local tlabels ""
forvalues t = -`pre'/`post' {
local tlabels `tlabels' `t'
local i = `t' + `pre' + 1
matrix `coefplot'[`i', 1] = `t''
matrix `coefplot'[`i', 2] = `b'[1, `i']
matrix `coefplot'[`i', 3] = `b'[1, `i'] + invnormal((100-`level')/200) * sqrt(`V'[`i', `i'])
matrix `coefplot'[`i', 4] = `b'[1, `i'] - invnormal((100-`level')/200) * sqrt(`V'[`i', `i'])
}
ereturn post `b' `V', obs(`Nobs') esample(`esample')
ereturn local depvar `y'
ereturn local cmd xt2treatments
ereturn local cmdline xt2treatments `0'
_coef_table_header, title(Event study relative to `baseline') width(62)
display
_coef_table, bmat(e(b)) vmat(e(V)) level(`level') ///
depname(`depvar') coeftitle(ATET)
if ("`graph'" == "graph") {
hetdid_coefplot, mat(`coefplot') title(Event study relative to `baseline') ///
ylb(`y') xlb("Length of exposure to the treatment") ///
yline(0) legend(off) level(`level') yline(0, extend) ytick(0, add) ylabel(0, add) xlabel(`tlabels')
}
end