*! Meng Ke, allenmeng97@gmail.com, 2024-9-10
*! 1.1 2024.09.10


cap program drop dynamic_est
program define dynamic_est

	version 10

    // Adjust the syntax to not require quotes around options
    syntax varlist(min=1 max=1) [if],  ///
	treat(varlist) time(varlist) ref(integer) [absorb(string)] ///
	[cluster(varlist)] [cov(string)] ///
	[level(string)] [treattype(string)] [figname(string)] ///
	[figtitle(string)] [figsubtitle(string)]  [regtype(string)]

	// Assign the first variable in varlist to y and the second to did
    local y : word 1 of `varlist'
    // local treat : word 2 of `varlist'

	// default options
	di "------------------------------------------------------------------------------------"
	di "reghdfe required"

	di "Option warning:"

	if "`regtype'" == ""{
	    local regtype = "reg"
		di "The option {regtype} was not specified, defaulting to {reg}"
	}

	if "`level'" == "" {
	    local level = "95"
		di "The option {level} was not specified, defaulting to {95%}"
	}

	if "`treattype'" == ""{
		// local treattype = "binary"	// binary or intensity
		qui{
		levelsof `treat'
		local levelsoftreat = r(r)
		su `treat'
		if `levelsoftreat' == 2 & r(min) == 0 & r(max) == 1{
			local treattype = "binary"
		}
		if `levelsoftreat' > 2 {
			local treattype = "intensity"
		}
		}
		di "The option {treattype} was not specified, the treat var you entered should be {`treattype'}"
	}

	qui{
    // Summarize the year variable to find the range
	cap ren _ty xjsktf29186
    su `time', d
    local s_y = r(min)
    local e_y = r(max)
    local period = `e_y' - `s_y'
    local coef_t ""
	}

	qui{
	if `s_y' >=0 {
	    local gap = 0
		di "时间为正数，可直接运行"
	}

	if `s_y' < 0{
	    su `time', d
		gen _ty = `time' - r(min) + 1
		local gap = 1 -r(min)
		local time _ty
		local ref = `ref' + `gap'
		su `time', d
		local s_y = r(min)
		local e_y = r(max)
		local period = `e_y' - `s_y'
		local coef_t ""
	}
	}

	di "------------------------------------------------------------------------------------"
	qui{
	// Loop through the years to construct the coefficient time variables
	forv i = 1/`period' {
		local j = `i' + `s_y' - 1
		if `j' < `ref' {
			local coef_t "`coef_t' `=`s_y'-1+`i''"
			local coef_k "`coef_k' `=`i'-`gap''"
		}
		if `j' >= `ref' {
			local coef_t "`coef_t' `=`s_y'+`i''"
			local coef_k "`coef_k' `=`i'+1-`gap''"
		}
	}
	}
	// Display the constructed coef_t string for debugging purposes
	// di "`coef_t'"

	// binary or intensity?

	if "`treattype'" == "binary"{
		// binary
		if `gap' == 0{
	    di "INPUT TIME: natural time {standard-DID}"
		di "INPUT treatment type: binary"
		di "INPUT Y: `y'"
		di "INPUT COV: `cov'"
		di "INPUT absorb: `absorb'"
		di "INPUT Cluster: `cluster'"
		di "method `regtype'hdfe"
		di "------------------------------------------------------------------------------------"
		di ":::::::::RUN:::::::::"
		di "------------------------------------------------------------------------------------"

		// Execute the regression with or without cluster & absorb
		if "`cluster'" != ""{
			if "`absorb'" != ""{
				di "TWFE: `regtype'hdfe `y' i1.`treat'#i(`coef_t').`time' `cov' `if', absorb(`absorb') cluster(`cluster')"
				`regtype'hdfe `y' i1.`treat'#i(`coef_t').`time' `cov' `if', absorb(`absorb') cluster(`cluster') level(`level')
			}
			if "`absorb'" == ""{
				di "TWFE: `regtype'hdfe `y' i1.`treat'#i(`coef_t').`time' `cov' `if', noa cluster(`cluster')"
				`regtype'hdfe `y' i1.`treat'#i(`coef_t').`time' `cov' `if', noa cluster(`cluster') level(`level')
			}
		}

		if "`cluster'" == ""{
			if "`absorb'" != ""{
				di "TWFE: `regtype'hdfe `y' i1.`treat'#i(`coef_t').`time' `cov' `if', absorb(`absorb') vce(r)"
				`regtype'hdfe `y' i1.`treat'#i(`coef_t').`time' `cov' `if', absorb(`absorb') vce(r) level(`level')
			}
			if "`absorb'" == ""{
				di "TWFE: `regtype'hdfe `y' i1.`treat'#i(`coef_t').`time' `cov' `if', noa vce(r)"
				`regtype'hdfe `y' i1.`treat'#i(`coef_t').`time' `cov' `if', noa cluster(`cluster') level(`level')
			}
		}

	}

	if `gap' != 0{
	    di "INPUT TIME: relative time {staggered-DID}"
		di "INPUT treatment type: binary"
		di "INPUT Y: `y'"
		di "INPUT COV: `cov'"
		di "INPUT absorb: `absorb'"
		di "INPUT Cluster: `cluster'"
		di "method `regtype'hdfe"
		di "------------------------------------------------------------------------------------"
		di ":::::::::RUN:::::::::"
		di "------------------------------------------------------------------------------------"

		// Execute the regression with or without condition
		if "`cluster'" != ""{
			if "`absorb'" != "" {
				di "TWFE: `regtype'hdfe `y' i1.`treat'#i(`coef_k').`time' `cov' `if', absorb(`absorb') cluster(`cluster')"
				`regtype'hdfe `y' i1.`treat'#i(`coef_t').`time' `cov' `if' , absorb(`absorb') cluster(`cluster') level(`level')
			}
			if "`absorb'" == "" {
				di "TWFE: `regtype'hdfe `y' i1.`treat'#i(`coef_k').`time' `cov' `if', noa cluster(`cluster')"
				`regtype'hdfe `y' i1.`treat'#i(`coef_t').`time' `cov' `if' , noa cluster(`cluster') level(`level')
			}
		}
		if "`cluster'" == ""{
			if "`absorb'" != "" {
				di "TWFE: `regtype'hdfe `y' i1.`treat'#i(`coef_k').`time' `cov' `if', absorb(`absorb') vce(r)"
				`regtype'hdfe `y' i1.`treat'#i(`coef_t').`time' `cov' `if', absorb(`absorb') vce(r) level(`level')
			}
			if "`absorb'" == "" {
				di "TWFE: `regtype'hdfe `y' i1.`treat'#i(`coef_k').`time' `cov' `if', noa vce(r)"
				`regtype'hdfe `y' i1.`treat'#i(`coef_t').`time' `cov' `if' , noa vce(r) level(`level')
			}
		}
	}
	}

	if "`treattype'" == "intensity"{
		// intensity
		if `gap' == 0{
	    di "INPUT TIME: natural time {standard-DID}"
		di "INPUT treatment type: intensity"
		di "INPUT Y: `y'"
		di "INPUT COV: `cov'"
		di "INPUT absorb: `absorb'"
		di "INPUT Cluster: `cluster'"
		di "method `regtype'hdfe"
		di "------------------------------------------------------------------------------------"
		di ":::::::::RUN:::::::::"
		di "------------------------------------------------------------------------------------"

		// Execute the regression with or without condition
		if "`cluster'" != ""{
			if "`absorb'" != ""{
				di "TWFE: `regtype'hdfe `y' c.`treat'#i(`coef_t').`time' `cov' `if' , absorb(`absorb') cluster(`cluster')"
				`regtype'hdfe `y' c.`treat'#i(`coef_t').`time' `cov' `if' , absorb(`absorb') cluster(`cluster') level(`level')
			}
			if "`absorb'" == ""{
				di "TWFE: `regtype'hdfe `y' c.`treat'#i(`coef_t').`time' `cov' `if' , noa cluster(`cluster')"
				`regtype'hdfe `y' c.`treat'#i(`coef_t').`time' `cov' `if' , noa cluster(`cluster') level(`level')
			}
		}
		if "`cluster'" == ""{
			if "`absorb'" != ""{
				di "TWFE: `regtype'hdfe `y' c.`treat'#i(`coef_t').`time' `cov' `if' , absorb(`absorb') vce(r)"
				`regtype'hdfe `y' c.`treat'#i(`coef_t').`time' `cov' `if' , absorb(`absorb') vce(r) level(`level')
			}
			if "`absorb'" == ""{
				di "TWFE: `regtype'hdfe `y' c.`treat'#i(`coef_t').`time' `cov' `if' , noa vce(r)"
				`regtype'hdfe `y' c.`treat'#i(`coef_t').`time' `cov' `if' , noa vce(r) level(`level')
			}
		}
	}

	if `gap' != 0{
	    di "INPUT TIME: relative time {staggered-DID}"
		di "INPUT treatment type: intensity"
		di "INPUT Y: `y'"
		di "INPUT COV: `cov'"
		di "INPUT absorb: `absorb'"
		di "INPUT Cluster: `cluster'"
		di "method `regtype'hdfe"
		di "------------------------------------------------------------------------------------"
		di ":::::::::RUN:::::::::"
		di "------------------------------------------------------------------------------------"

		// Execute the regression with or without condition
		if "`cluster'" != ""{
			if "`absorb'" != ""{
				di "TWFE: `regtype'hdfe `y' c.`treat'#i(`coef_k').`time' `cov' `if', absorb(`absorb') cluster(`cluster')"
				`regtype'hdfe `y' c.`treat'#i(`coef_t').`time' `cov' `if' , absorb(`absorb') cluster(`cluster') level(`level')
			}
			if "`absorb'" == ""{
				di "TWFE: `regtype'hdfe `y' c.`treat'#i(`coef_k').`time' `cov' `if', noa cluster(`cluster')"
				`regtype'hdfe `y' c.`treat'#i(`coef_t').`time' `cov' `if' , noa cluster(`cluster') level(`level')
			}
		}
		if "`cluster'" == ""{
			if "`absorb'" != ""{
				di "TWFE: `regtype'hdfe `y' c.`treat'#i(`coef_k').`time' `cov' `if', absorb(`absorb') vce(r)"
				`regtype'hdfe `y' c.`treat'#i(`coef_t').`time' `cov' `if' , absorb(`absorb') vce(r) level(`level')
			}
			if "`absorb'" == ""{
				di "TWFE: `regtype'hdfe `y' c.`treat'#i(`coef_k').`time' `cov' `if', noa vce(r)"
				`regtype'hdfe `y' c.`treat'#i(`coef_t').`time' `cov' `if' , noa vce(r) level(`level')
			}
		}
	}
	}

	cap{
	mat N = e(N)
	local obs =  N[1,1]
	}

	// ↓↓↓↓↓ fig ↓↓↓↓↓
	if "`treattype'" == "intensity"{
	local length = `period' + 1
	mat M = J(`length',5,.)
	if "`level'" == "90"{
		forv i = `s_y' / `e_y'{
			local row = `i' - `s_y' + 1
			cap mat M[`row',1] = _b[c.`treat'#`i'.`time']
			cap mat M[`row',2] = _se[c.`treat'#`i'.`time']
			cap mat M[`row',3] = _b[c.`treat'#`i'.`time'] + 1.96 * _se[c.`treat'#`i'.`time']
			cap mat M[`row',4] = _b[c.`treat'#`i'.`time'] - 1.96 * _se[c.`treat'#`i'.`time']
			cap mat M[`row',5] = `i'
		}
	}
	if "`level'" == "95"{
		forv i = `s_y' / `e_y'{
			local row = `i' - `s_y' + 1
			cap mat M[`row',1] = _b[c.`treat'#`i'.`time']
			cap mat M[`row',2] = _se[c.`treat'#`i'.`time']
			cap mat M[`row',3] = _b[c.`treat'#`i'.`time'] + 2.33 * _se[c.`treat'#`i'.`time']
			cap mat M[`row',4] = _b[c.`treat'#`i'.`time'] - 2.33 * _se[c.`treat'#`i'.`time']
			cap mat M[`row',5] = `i'
		}
	}
	if "`level'" == "99"{
		forv i = `s_y' / `e_y'{
			local row = `i' - `s_y' + 1
			cap mat M[`row',1] = _b[c.`treat'#`i'.`time']
			cap mat M[`row',2] = _se[c.`treat'#`i'.`time']
			cap mat M[`row',3] = _b[c.`treat'#`i'.`time'] + 2.58 * _se[c.`treat'#`i'.`time']
			cap mat M[`row',4] = _b[c.`treat'#`i'.`time'] - 2.58 * _se[c.`treat'#`i'.`time']
			cap mat M[`row',5] = `i'
		}
	}
	}

	if "`treattype'" == "binary"{
	local length = `period' + 1
	mat M = J(`length',5,.)
	if "`level'" == "90"{
		forv i = `s_y' / `e_y'{
			local row = `i' - `s_y' + 1
			cap mat M[`row',1] = _b[1.`treat'#`i'.`time']
			cap mat M[`row',2] = _se[1.`treat'#`i'.`time']
			cap mat M[`row',3] = _b[1.`treat'#`i'.`time'] + 1.96 * _se[1.`treat'#`i'.`time']
			cap mat M[`row',4] = _b[1.`treat'#`i'.`time'] - 1.96 * _se[1.`treat'#`i'.`time']
			cap mat M[`row',5] = `i'
		}
	}
	if "`level'" == "95"{
		forv i = `s_y' / `e_y'{
			local row = `i' - `s_y' + 1
			cap mat M[`row',1] = _b[1.`treat'#`i'.`time']
			cap mat M[`row',2] = _se[1.`treat'#`i'.`time']
			cap mat M[`row',3] = _b[1.`treat'#`i'.`time'] + 2.33 * _se[1.`treat'#`i'.`time']
			cap mat M[`row',4] = _b[1.`treat'#`i'.`time'] - 2.33 * _se[1.`treat'#`i'.`time']
			cap mat M[`row',5] = `i'
		}
	}
	if "`level'" == "99"{
		forv i = `s_y' / `e_y'{
			local row = `i' - `s_y' + 1
			cap mat M[`row',1] = _b[1.`treat'#`i'.`time']
			cap mat M[`row',2] = _se[1.`treat'#`i'.`time']
			cap mat M[`row',3] = _b[1.`treat'#`i'.`time'] + 2.58 * _se[1.`treat'#`i'.`time']
			cap mat M[`row',4] = _b[1.`treat'#`i'.`time'] - 2.58 * _se[1.`treat'#`i'.`time']
			cap mat M[`row',5] = `i'
		}
	}
	}

	qui{
	preserve
		clear
		svmat M
		replace M1 = 0 if M5 == `ref'
		format M1 %9.2f
		format M2 %9.2f

		gen se = "(0" + string(round(M2,0.001))  + ")"
		replace se = "." if strmatch(se,"*.*") == 0
		replace se = "." if strmatch(se,"(0.)") == 1
		forv i = 1/9{
			replace se = regexr(se, "\(0([`i'])\.", "(`i'.")
		}

		gen coef = string(abs(round(M1,0.01)))
		replace coef = "0"+coef if strmatch(coef,".*") & M1 >=0
		replace coef = "-"+coef if strmatch(coef,".*")==0 & M1 <0
		replace coef = "-0"+coef if strmatch(coef,".*") & M1 <0
		replace coef ="" if M5 == `ref'

		gen sig_se = subinstr(se,"(","",.)
		replace sig_se = subinstr(sig_se,")","",.)
		destring sig_se,replace force
		replace sig_se = M1/M2
		replace se= "" if M5 == `ref'

		gen sig = "***" if abs(sig_se) > 2.58 & sig_se!=.
		replace sig = "**" if abs(sig_se) <= 2.58 & abs(sig_se) > 2.33
		replace sig = "*" if abs(sig_se) <= 2.33 & abs(sig_se) > 1.96

		gen coef_sig = coef + sig

		if `gap' == 0{
			tw (rcap M3 M4 M5, lp(solid) lc(gs4)) ///
			   (connect M1 M5 if M5 <=`ref', ms(o) mc(gs6) mlab(coef_sig) mlabp(1) lp(solid)) ///
			   (connect M1 M5 if M5 >=`ref', ms(o) lc(gs6) mlab(coef_sig) mlabp(11) lp(solid)) ///
			   (scatter M1 M5 if M5 <=`ref', ms(i) mlab(se) mlabp(5)) ///
			   (scatter M1 M5 if M5 >= `ref', ms(i) mlab(se) mlabp(7)) ///
			   , scheme(s1mono) legend(off) ///
			   xline(`=`ref'+0.5' ,lp(shortdash)) ///
			   yline(0,lp(shortdash)) xtitle("time") ///
			   ytitle("coef. and `level'% CI") ///
			   name("`figname'",replace) ///
			   subtitle("`figsubtitle'") ///
			   title("`figtitle'") note("observations: `obs'")
		}

		if `gap' != 0{
		replace M5 = M5 - `gap'
		local ref = `ref' - `gap'
		tw (rcap M3 M4 M5, lp(solid) lc(gs4)) ///
		   (connect M1 M5 if M5 <=`ref', ms(o) mc(gs6) mlab(coef_sig) mlabp(1) lp(solid)) ///
		   (connect M1 M5 if M5 >=`ref', ms(o) lc(gs6) mlab(coef_sig) mlabp(11) lp(solid)) ///
		   (scatter M1 M5 if M5 <=`ref', ms(i) mlab(se) mlabp(5)) ///
		   (scatter M1 M5 if M5 >= `ref', ms(i) mlab(se) mlabp(7)) ///
		   , scheme(s1mono) legend(off) ///
		   xline(`=`ref'+0.5' ,lp(shortdash)) ///
		   yline(0,lp(shortdash)) xtitle("time") ///
		   ytitle("coef. and `level'% CI") ///
		   name("`figname'",replace) ///
		   subtitle("`figsubtitle'") ///
		   title("`figtitle'") note("observations: `obs'")
		}
	restore

	cap drop _ty
	cap ren xjsktf29186 _ty
	}

end