* * PROGRAM DYNARDL * * version 1.0.5 * 4/18/18 * Soren Jordan and Andrew Q. Philips * * * Note: previous versions of this program were titled dynpss * * ------------------------------------------------------------------------- * ------------------------------------------------------------------------- * ------------------------------------------------------------------------- capture program drop dynardl capture program define dynardl , eclass syntax [varlist] [if] [in], [Lags(string) Diffs(string) LAGDiffs(string) /// levels(string) forceset(string) Time(numlist integer > 1) shockval(numlist) /// shockvar(varname) range(numlist integer > 1) SAVing(string) /// sig(numlist integer < 100) ec NOCONstant TRend /// burnin(numlist integer > 1) sims(numlist) graph rarea change expectedval] version 8 preserve // we're going to remove existing data di "-----------------------------------------------" if "`sig'" != "" { // getting the CI's signif scalar signif = `sig' } else { scalar signif = 95 } loc sigl = (100-signif)/2 loc sigu = 100-((100-signif)/2) if "`sims'" != "" { // How many sims are desired? loc simulations `sims' } else { loc simulations 1000 } if "`shockvar'" == "" | "`shockval'" == "" { // check shockval/var di in r _n "both shockvar and shockval must be specified" exit 198 } if "`lags'" == "" { di in r _n "lags( ) must be specified" exit 198 } if "`range'" != "" { // How far to simulate? loc range `range' } else { loc range 20 di "" di in y "No range specified; default to t=20" } if "`time'" != "" { // When to shock? loc time `time' } else { loc time 10 di in y "No time of shock specified; default to t=10" } if `time' >= `range' { // Check di in r _n "The range of simulation must be longer than the shock time" exit 198 } if "`burnin'" != "" { // burnins loc burnin `burnin' di "" di in y "Number of burnins: `burnin'" } else { loc burnin 20 } loc brange = `range' + `burnin' loc btime = `time' + `burnin' if "`ec'" != "" { // ECM or ARDL di "" di in y "Option ec specified, dependent variable to be run in differences" } else { di in y "Dependent variable to be run in levels" } * ----------------- Generate L and D as needed ----------------------------- * loc ldvs "" // lagged DVs loc lnumdvs "" // vector of dv lag lengths loc lddvs "" // lagged-diff DVs loc ldnumdvs "" // vector of ld DV lag lengths loc dsiv "" // differenced shockvar loc lsiv "" // lagged shockvar loc lnumsiv "" // vector of shockvar lag lengths loc ldsiv "" // lagged-diff shockvar loc ldnumsiv "" // vector of ld shockvar lag lengths loc siv "" // levels shockvar loc ivset "" // levels of other vars loc divset "" // differenced other vars loc livset "" // lagged other vars loc ldivset "" // lagged-diff other vars loc n_vars : word count `varlist' // count of vars forv i = 1/`n_vars' { loc varname_`i' : word `i' of `varlist' // localize var name } * for the lags ---------- qui if "`lags'" != "" { local lagslist : subinstr local lags "," `"" ""', all // local that stops at each comma local lagslist `""`lagslist'""' loc n_lags : word count `lagslist' if "`n_lags'" != "`n_vars'" { // does # lag entries == # variables? di in r _n "Lag list has `n_lags' entries, but `n_vars' variables specified in [varlist]." di in r _n "Add entry for each variable, separated by a comma (missing is '.')" exit 198 } local i 1 foreach e of local lagslist { foreach j of local e { tokenize `j', parse ("/") if "`1'" == "0" { // no lags dealt w/ using levels() di in r _n "Specify lag(0) by using the levels( ) command" exit 198 } * situation 1: lo/hi range of lags desired if "`3'" != "" { forv r = `1'/`3' { cap drop L`r'_`varname_`i'' gen L`r'_`varname_`i'' = l`r'.`varname_`i'' if "`i'" == "1" { loc ldvs "`ldvs' L`r'_`varname_`i''" // add to ldv list loc lnumdvs "`lnumdvs' `r'" // lag lengths to list } else if "`varname_`i''" == "`shockvar'" { loc lsiv "`lsiv' L`r'_`varname_`i''" // add to lag shockset loc lnumsiv "`lnumsiv' `r'" // lag length to list } else { loc livset "`livset' L`r'_`varname_`i''" // else to other varlist } } } * situation 2: no lag desired else if "`1'" == "." { if "`i'" == "1" { // LDV must be there di in r _n "At least 1 lag of the dependent variable must be specified" exit 198 } } * situation 3: single lag desired else { cap drop L`1'_`varname_`i'' gen L`1'_`varname_`i'' = l`1'.`varname_`i'' if "`i'" == "1" { loc ldvs "`ldvs' L`1'_`varname_`i''" // add to ldv list loc lnumdvs "`lnumdvs' `1'" } else if "`varname_`i''" == "`shockvar'" { loc lsiv "`lsiv' L`1'_`varname_`i''" // add to lag shockset loc lnumsiv "`lnumsiv' `1'" } else { loc livset "`livset' L`1'_`varname_`i''" // else add to other varlist } } } local i = `i' + 1 } } // close if diffs != . * For the differences ----- qui if "`diffs'" != "" { local difflist : subinstr local diffs "," `"" ""', all local difflist `""`difflist'""' loc n_diffs : word count `difflist' if "`n_diffs'" != "`n_vars'" { // does # diff entries == # variables? di in r _n "Diff list has `n_diffs' entries, but `n_vars' variables specified in [varlist]." di in r _n "Add entry for each variable, separated by a comma (missing is '.')" exit 198 } local i 1 foreach e of local difflist { foreach j of local e { tokenize `j', parse("/") if "`1'" != "." { if "`1'" == "1" { cap drop D_`varname_`i'' gen D_`varname_`i'' = d.`varname_`i'' // create diff if "`varname_`i''" == "`shockvar'" { // if var == shockvar loc dsiv "`dsiv' D_`varname_`i''" } else { // else add to other varlist loc divset "`divset' D_`varname_`i''" } } else { di in r _n "Variables can only be first-differenced; specify diff = 1" exit 198 } } } local i = `i' + 1 } } // close if diffs != . * For the levels ----- qui if "`levels'" != "" { // any vars in levels? local levellist : subinstr local levels "," `"" ""', all local levellist `""`levellist'""' loc n_levels : word count `levellist' if "`n_levels'" != "`n_vars'" { // does # levels entries == # variables? di in r _n "Levels list has `n_levels' entries, but `n_vars' variables specified in [varlist]." di in r _n "Add entry for each variable, separated by a comma (missing is '.')" exit 198 } local i 1 foreach e of local levellist { foreach j of local e { tokenize `j', parse("/") if "`1'" == "." { } else { cap drop __`varname_`i'' if "`varname_`i''" == "`shockvar'" { // if shock var in levels gen __`varname_`i'' = `varname_`i'' loc siv "`siv' __`varname_`i''" } else { // else add to other varlist gen __`varname_`i'' = `varname_`i'' loc ivset "`ivset' __`varname_`i''" } } } local i = `i' + 1 } } * For the lagged diffs ----- qui if "`lagdiffs'" != "" { local ldlist : subinstr local lagdiffs "," `"" ""', all // create local that stops at each comma local ldlist `""`ldlist'""' loc n_ldiffs : word count `ldlist' if "`n_ldiffs'" != "`n_vars'" { di in r _n "Lag-diff list has `n_ldiffs' entries, but `n_var' variables specified in [varlist]" di in r _n "Add entry for each variable, separated by a comma (missing is '.')" exit 198 } local i 1 foreach e of local ldlist { foreach j of local e { tokenize `j', parse ("/") if "`1'" == "0" { di in r _n "Specify lagdiff = 0 by using the diffs( ) command" exit 198 } * situation 1: lo/hi range of ld's desired if "`3'" != "" { forv r = `1'/`3' { cap drop L`r'D_`varname_`i'' gen L`r'D_`varname_`i'' = l`r'd.`varname_`i'' if "`i'" == "1" { loc lddvs "`lddvs' L`r'D_`varname_`i''" // to lddv list loc ldnumdvs "`ldnumdvs' `r'" } else if "`varname_`i''" == "`shockvar'" { loc ldsiv "`ldsiv' L`r'D_`varname_`i''" // to ld shockset loc ldnumsiv "`ldnumsiv' `r'" } else { loc ldivset "`ldivset' L`r'D_`varname_`i''" // to ld varlist } } } * situation 2: no lag desired else if "`1'" == "." { } * situation 3: single lag(s) desired else { cap drop L`1'D_`varname_`i'' gen L`1'D_`varname_`i'' = l`1'd.`varname_`i'' if "`i'" == "1" { loc lddvs "`lddvs' L`1'D_`varname_`i''" // to lddv list loc ldnumdvs "`ldnumdvs' `1'" } else if "`varname_`i''" == "`shockvar'" { loc ldsiv "`ldsiv' L`1'D_`varname_`i''" // add to lag shockset loc ldnumsiv "`ldnumsiv' `1'" } else { loc ldivset "`ldivset' L`1'D_`varname_`i''" // to ld varlist } } } local i = `i' + 1 } } qui if "`ec'" != "" { // make d.Y if error-correction cap drop d`varname_1' gen d`varname_1' = d.`varname_1' } if "`levels'" != "" & "`ec'" != "" { // issue warning di in y "Option ec specified with variables appearing in levels; are you sure you want this?" } qui if "`trend'" != "" { // linear time trend desired? gen Trend = _n loc trend "Trend" di in y "Deterministic linear trend specified" } if "`noconstant'" != "" { // suppress constant? loc nocon ", noconstant" di in y "Suppress constant specified" } * ----------------- Estimate Model ----------------------------- * * ARDL: if "`ec'" == "" { regress `varname_1' `ldvs' `lddvs' `dsiv' `lsiv' `ldsiv' `siv' `ivset' `divset' `livset' `ldivset' `trend' `nocon' } * ECM: else { regress d`varname_1' `ldvs' `lddvs' `dsiv' `lsiv' `ldsiv' `siv' `ivset' `divset' `livset' `ldivset' `trend' `nocon' } * ----------------- Store Values for pssbounds ----------------- * * keep existing regress ereturns for things like wald tests if ecm. * TYPE: if "`ec'" != "" { if "`trend'" != "" { if "`noconstant'" != "" { ereturn scalar type = 0 // no crit values available. } else { ereturn scalar type = 5 // unrestricted intercept and trend } } else { if "`noconstant'" != "" { ereturn scalar type = 1 // no intercept or trend } else { ereturn scalar type = 3 // unrestricted intercept, no trend } } * lag list (needed for k and f-test) foreach var of varlist `ldvs' { if substr("`var'",1,2) == "L1" { local lag1list "`var'" ereturn scalar ldv_t = _b[`var']/_se[`var'] // tstat on LDV } } loc k foreach var of varlist `lsiv' `livset' { if substr("`var'",1,2) == "L1" { // is it in coint. eq? local lag1list "`lag1list' `var'" loc k = `k' + 1 // no. of vars } } ereturn local laglist `lag1list' // vector of l.y + l.x1 + l.x2... ereturn scalar k = `k' // # of indep vars appearing in lagged levels ereturn local cmd dynardl } * ----------------- Obtain Means and Things for Below -------------------- * mat B = e(b) // betas mat V = e(V) // VCV matrix scalar sigma2 = e(rmse)^2 // sigma squared scalar dfsig = e(df_r) // residual d.f. scalar length = e(rank) // rank of matrix * if forceset is not missing, permanently set to forceset value. if "`forceset'" != "" { local forcesetlist : subinstr local forceset "," `"" ""', all local forcesetlist `""`forcesetlist'""' local n_fslist : word count `forcesetlist' if "`n_fslist'" != "`n_vars'" { // does # levels entries == # variables? di in r _n "Forceset list has `n_fslist' entries, but `n_vars' variables specified in [varlist]." di in r _n "Add entry for each variable, separated by a comma (missing is '.')" exit 198 } local i 1 foreach e of local forcesetlist { foreach j of local e { tokenize `j', parse("/") loc var : word `i' of `varlist' // localize variable name if "`i'" == "1" & "`1'" != "." { di in r _n "Lagged DV cannot be forceset. Set to '.'" exit 198 } if "`1'" != "." { scalar _`var'_mean = `1' } else { // if forceset val is ".", just use means. su `varname_`i'' if e(sample), meanonly scalar _`var'_mean = r(mean) } } local i = `i' + 1 } } else { // if not, will just use means qui foreach var in `varlist' { su `var' if e(sample), meanonly scalar _`var'_mean = r(mean) // grab means of levels } } * ----------------- Create Posterior Draws ------------------------------- * * draw posterior betas (and constant if applicable) if "`noconstant'" != "" { qui drawnorm `ldvs' `lddvs' `dsiv' `lsiv' `ldsiv' `siv' `ivset' `divset' `livset' `ldivset' `trend' , n(`simulations') cov(V) means(B) clear * place vars in posterior beta's (PB) matrix: mkmat `ldvs' `lddvs' `dsiv' `lsiv' `ldsiv' `siv' `ivset' `divset' `livset' `ldivset' `trend' , matrix(PB) } else { qui drawnorm `ldvs' `lddvs' `dsiv' `lsiv' `ldsiv' `siv' `ivset' `divset' `livset' `ldivset' `trend' const , n(`simulations') cov(V) means(B) clear * place vars in posterior beta's (PB) matrix: mkmat `ldvs' `lddvs' `dsiv' `lsiv' `ldsiv' `siv' `ivset' `divset' `livset' `ldivset' `trend' const, matrix(PB) } * draw sigma-squared from inv chi-2 to constrain to [0-1]: tempvar Sigma2 qui gen `Sigma2' = sigma2*(dfsig)/invchi2(dfsig,uniform()) * ----------------- Values at t = 1 ------------------------------- * mat set = J(length,1,.) // container to hold set values * parsing routine through regression varlist (and set), * splitting out the name and leaving the d, l1, etc., and replaces set * with their sample mean if L, and 0 if L*D or D. loc i 1 * lagged DV's always set to sample means, unless constant suppressed: foreach var in `ldvs' { gettoken dynamics name: var, parse("_") if "`noconstant'" != "" { mat set[`i',1] = 0 } else { mat set[`i',1] = `name'_mean } loc i = `i' + 1 } * lagged diff DV's set to 0 foreach var in `lddvs' { mat set[`i',1] = 0 loc i = `i' + 1 } * differenced shocked IV set to 0 foreach var in `dsiv' { mat set[`i',1] = 0 loc i = `i' + 1 } * lagged shocked IV set to sample means foreach var in `lsiv' { gettoken dynamics name: var, parse("_") mat set[`i',1] = `name'_mean loc i = `i' + 1 } * lagged diff shocked IV set to 0 foreach var in `ldsiv' { mat set[`i',1] = 0 loc i = `i' + 1 } * shocked IV in levels set to means, as are other varlist in levels: foreach var in `siv' `ivset' { gettoken dynamics name: var, parse("_") mat set[`i',1] = `name'_mean loc i = `i' + 1 } * differenced other varlist set to 0 foreach var in `divset' { mat set[`i',1] = 0 loc i = `i' + 1 } * lagged other varlist set to means foreach var in `livset' { gettoken dynamics name: var, parse("_") mat set[`i',1] = `name'_mean loc i = `i' + 1 } * lagged diff of other varlist set to 0 foreach var in `ldivset' { mat set[`i',1] = 0 loc i = `i' + 1 } * trend (if present) set to -burnin s.t. trend = t=0 at t=0 foreach var in `trend' { mat set[`i',1] = -`burnin' loc i = `i' + 1 } * constant if "`noconstant'" != "" { } else { mat set[`i',1] = 1 } * Create predicted values ----------------- * multiply [s x k] posterior beta matrix by [k x 1] set matrix tempname PV mat `PV' = PB*set svmat `PV' * add error into XB: expected values or predicted values: qui if "`expectedval'" != "" { tempvar tid gen `tid' = _n expand 1000 replace `PV' = `PV' + rnormal(0,sqrt(`Sigma2')) collapse (mean) `PV' `Sigma2', by(`tid') } else { qui replace `PV' = `PV' + rnormal(0,sqrt(`Sigma2')) } * predicted values are obtained: if "`graph'" == "" { _pctile `PV', p(`sigl', `sigu') // grab ll and ul scalar ll_1 = r(r1) // grab values scalar ul_1 = r(r2) } else { // need all these for graph _pctile `PV', p(2.5, 5, 12.5, 87.5, 95, 97.5) scalar ll95_1 = r(r1) scalar ll90_1 = r(r2) scalar ll75_1 = r(r3) scalar ul75_1 = r(r4) scalar ul90_1 = r(r5) scalar ul95_1 = r(r6) } * need means of predicted values: su `PV', meanonly * if ECM, add PV to sample mean (from set matrix): if "`ec'" != "" { scalar meanpv_1 = r(mean) + set[1,1] } * if LDV, PV is new value else { scalar meanpv_1 = r(mean) } * ----------------- Values at t = 2/brange ------------------------------- * * loop through all time periods: di "" noi di in g "Please wait:" nois _dots 0, title(dynardl is currently creating `simulations' simulations across `range' time points) reps(`range') qui forv p = 2/`brange' { noi _dots `p' 0 * Set l.DV's to predicted value: local w = `p' - 1 // new LDV value is previous LDV value loc row = 1 // start at the top of set matrix foreach lag in `lnumdvs' { loc w = `p' - `lag' if `w' > 0 { mat set[`row',1] = meanpv_`w' } else { } loc row = `row' + 1 // move down set list } * Set ld.DVs to predicted changes lagged (t - (t-1), t-1 - (t-2)...) foreach lagd in `ldnumdvs' { loc w = `p' - `lagd' // subtract current time by ld.Y if `w' > 1 { loc wl = `w' - 1 mat set[`row',1] = meanpv_`w' - meanpv_`wl' // ld set matrix replaced with value of the difference at w'th lag } else { } loc row = `row' + 1 } * if t = shocktime ----------------------------- if `p' == `btime' { * shock differenced var: foreach var in `dsiv' { mat set[`row',1] = `shockval' local row = `row' + 1 } foreach var in `lsiv' `ldsiv' { // get past these...nothing happens local row = `row' + 1 } * shock vars in levels: foreach var in `siv' { gettoken dynamics name: var, parse("_") mat set[`row',1] = `name'_mean + `shockval' } } * else if t > shocktime ------------------------------ else if `p' > `btime' { * differenced var back to 0: foreach var in `dsiv' { mat set[`row',1] = 0 local row = `row' + 1 } * lagged var shock: foreach lag in `lnumsiv' { loc w = `p' - `btime' if `w' >= `lag' { mat set[`row',1] = _`shockvar'_mean + `shockval' } else { // lag remains unchanged } loc row = `row' + 1 } * lagged diff var shock foreach lagd in `ldnumsiv' { loc w = `p' - `btime' if `w' == `lagd' { mat set[`row',1] = `shockval' } else { mat set[`row',1] = 0 } loc row = `row' + 1 } /* shock in levels: * shockvar already shocked. Don't need to do anything. */ } else { // if t < shocktime...nothing happens } * set trend to t+1, if it exists if "`trend'" != "" { foreach var in `trend' { * if no constant, trend = rowsof(set) if "`noconstant'" != "" { scalar f = rowsof(set) } else { // if not it's 1 less than row total scalar f = rowsof(set) - 1 } mat set[f,1] = `p' - `burnin' // trend = sim time - burnin time } } * create Y = XB + E ----------------------------- mat `PV' = PB*set capture drop `PV' svmat `PV' * add error into XB: expected values or predicted values: qui if "`expectedval'" != "" { tempvar tid gen `tid' = _n expand 1000 replace `PV' = `PV' + rnormal(0,sqrt(`Sigma2')) collapse (mean) `PV' `Sigma2', by(`tid') } else { replace `PV' = `PV' + rnormal(0,sqrt(`Sigma2')) } * values are obtained: if "`graph'" == "" { _pctile `PV', p(`sigl', `sigu') // grab ll and ul if "`ec'" != "" { // if ECM, add pc'tiles to old predicted values. scalar ll_`p' = r(r1) + set[1,1] scalar ul_`p' = r(r2) + set[1,1] } else { scalar ll_`p' = r(r1) // grab values scalar ul_`p' = r(r2) } } else { // need all these for graph _pctile `PV', p(2.5, 5, 12.5, 87.5, 95, 97.5) if "`ec'" != "" { // if ECM, add pc'tiles to old predicted values. scalar ll95_`p' = r(r1) + set[1,1] scalar ll90_`p' = r(r2) + set[1,1] scalar ll75_`p' = r(r3) + set[1,1] scalar ul75_`p' = r(r4) + set[1,1] scalar ul90_`p' = r(r5) + set[1,1] scalar ul95_`p' = r(r6) + set[1,1] } else { scalar ll95_`p' = r(r1) scalar ll90_`p' = r(r2) scalar ll75_`p' = r(r3) scalar ul75_`p' = r(r4) scalar ul90_`p' = r(r5) scalar ul95_`p' = r(r6) } } * need means of predicted values: su `PV', meanonly * if ECM, PV added to sample mean * (which was saved in set matrix): if "`ec'" != "" { scalar meanpv_`p' = r(mean) + set[1,1] } * if LDV, PV is new predicted value else { scalar meanpv_`p' = r(mean) } } // close time loop * ----------------- Store Values for Saving or Graphing ----------------- * loc z = `range' + 1 // need 1 more row than range. if "`graph'" == "" { mat sims = J(`z',3,.) // empty container of "."'s to hold sims loc p = 1 forv i = `burnin'/`brange' { mat sims[`p',1] = meanpv_`i' mat sims[`p',2] = ll_`i' mat sims[`p',3] = ul_`i' loc p = `p' + 1 } mat colnames sims = mean ll_ ul_ } else { mat sims = J(`z',7,.) // empty container of "."'s to hold sims loc p = 1 forv i = `burnin'/`brange' { mat sims[`p',1] = meanpv_`i' mat sims[`p',2] = ll95_`i' mat sims[`p',3] = ll90_`i' mat sims[`p',4] = ll75_`i' mat sims[`p',5] = ul75_`i' mat sims[`p',6] = ul90_`i' mat sims[`p',7] = ul95_`i' loc p = `p' + 1 } mat colnames sims = mean ll_95 ll_90 ll_75 ul_75 ul_90 ul_95 } svmat sims, names(col) qui keep mean ll_* ul_* qui drop in 1 // 1st one is technically t = 0 qui keep if mean != . qui gen time = _n if "`saving'" != "" { noi save `saving'.dta, replace } else { noi save dynardl_results.dta, replace } qui if "`graph'" != "" { if "`change'" != ""{ // is graph in changes? if "`expectedval'" != "" { loc titletype = "Change in Expected Value" } else { loc titletype = "Change in Predicted Value" } su mean if time == 1, meanonly local pmean = r(mean) foreach var of varlist mean ll_95 ll_90 ll_75 ul_75 ul_90 ul_95 { gen ch`var' = `var' - `pmean' } loc st = `time' - 1 drop in 1/`st' replace time = _n if "`rarea'" != "" { // area plot twoway rarea chll_95 chul_95 time, color(eltblue) || /// rarea chll_90 chul_90 time, color(ebblue) || /// rarea chll_75 chul_75 time, color(navy) || line chmean time, /// lcolor(black) lwidth(thick) legend(off) /// yline(0, lwidth(medium) lcolor(black) lpattern(solid)) /// ytitle("`titletype'") xtitle("Time") } else { // line plot twoway rspike chll_95 chul_95 time, lcolor(eltblue) lwidth(thin) /// || rspike chll_90 chul_90 time, lcolor(ebblue) lwidth(medthick) /// || rspike chll_75 chul_75 time, lcolor(navy) lwidth(thick) /// || scatter chmean time, mcolor(dknavy) msymbol(o) /// yline(0, lwidth(medium) lcolor(black) lpattern(solid)) /// msize(large) legend(off) ytitle("`titletype'") xtitle("Time") } } else { // graph in levels if "`expectedval'" != "" { loc titletype = "Expected Value" } else { loc titletype = "Predicted Value" } if "`rarea'" != "" { // area plot twoway rarea ll_95 ul_95 time, color(eltblue) || /// rarea ll_90 ul_90 time, color(ebblue) || /// rarea ll_75 ul_75 time, color(navy) || line mean time, /// lcolor(black) lwidth(thick) legend(off) /// ytitle("`titletype'") xtitle("Time") } else { // line plot twoway rspike ll_95 ul_95 time, lcolor(eltblue) lwidth(thin) /// || rspike ll_90 ul_90 time, lcolor(ebblue) lwidth(medthick) /// || rspike ll_75 ul_75 time, lcolor(navy) lwidth(thick) /// || scatter mean time, mcolor(dknavy) msymbol(o) /// msize(large) legend(off) ytitle("`titletype'") xtitle("Time") } } } // close graph restore // restore user data end * -------------------------------------------------------------------------