*! xtcd2 4.1 May 2023 *! author Jan Ditzen *! see viewsource xtcd2.ado for more info. /* Jan Ditzen - jan.ditzen@unibz.it Changelog: 05.03.2015 Option NOESTimation added 09.03.2015 Error in r(rho) corrected. 20.01.2016 Mata matrices are being dropped now 06.03.2016 Mata function RHO added 23.06.2016 Error in e(sample) fixed. 09.01.2017 Error in histogram fixed 03.03.2017 kdensity instead of histogram 10.03.2017 Changed output of CD and p-value 01.06.2017 Added version function. 31.10.2017 Cross sectional into cross-sectional renamed 05.06.2019 Added check which command used before 10.06.2019 Uses xtset2 to detect type of panel rather than xtset. 25.11.2019 Added heatplot and contour plots for rho 25.02.2020 Added ts support 08.02.2021 Added Juodis, Reese weighted CD test (cdw), repetions and pea 23.02.2021 Added option noadjust; do not remove means from vars; now standard to remove means! 23.09.2022 Improved calculation for unbalanced panels, fixed bug that CD test statistic becomes 1, added EM algorithm from xtnumfac for CDstar test 04.11.2022 Added seed() option to control seed for CDW test. 15.05.2023 Added trace option; bug fixed when using noadjust option */ cap program drop xtcd2 program define xtcd2, rclass syntax [anything] [if] , [repeatoutput VERsion *] version 14 if "`version'" != "" { di in gr "Version 4.0" *ereturn clear return local version 4.0 exit } if "`repeatoutput'" == "" { xtcd2_int `anything' `if' , `options' } xtcd2_output return add end cap program drop xtcd2_int program define xtcd2_int, rclass syntax [varlist(default=none ts)] [if] [, KDENsity name(string) rho /// NOESTimation /// not needed anymore contour(string) CONTOURmap order(varlist max=1) heatplot(string) HEATPLOTmap reps(integer 1) NOADJust /// /// repeat output repeatoutput /// /// defactor variable first DEFACtor /// /// which method pea pesaran cdw cdstar pca(real 4)) /// /// seed(string) /// /// loop method for unbalanced panels and if noadjust option used loop /// /// force using unbalanced algorithm FORCEUnbalanced /// trace ] if "`trace'" != "" local trace noi else local trace qui if "`repeatoutput'" != "" { xtcd2_output exit } if `pca' < 1 { noi disp "Option pca() must be larger than zero." error 199 } if "`contour'`contourmap'" != "" & "`heatplot'`heatplotmap'" != "" { noi disp "Options heatplot and contour cannot combined" exit } local methods "" if "`pesaran'`cdw'`pea'`cdstar'" == "" { local methods "CD CDw CDwplus CDstar" local pesaran pesaran local cdw cdw local pea pea local cdstar cdstar } else { if "`pesaran'" != "" local methods `methods' CD if "`cdw'" != "" | "`pea'" != "" local methods `methods' CDw if "`pea'" != "" local methods `methods' CDwplus if "`cdstar'" != "" local methods `methods' CDstar } if "`cdw'" != "" & "`seed'" != "" { set seed `seed' } *if regexm("`methods'","CDw") & `reps' == 1 local reps = 30 tempvar id_n time_new preserve if "`if'" != "" { `trace' keep `if' } ** Check which estimation command if "`varlist'" == "" { *** xtdcce2 if regexm("`e(cmd)'","xtdcce2") == 1 { local restype residuals disp in smcl "Residuals calculated using {it: predict, residuals} from {it:xtdcce2}." } else if regexm("`e(cmd)'","xtreg") == 1 { local restype e disp in smcl "Residuals calculated using {it: predict, e} from {it:`e(cmd)'}." } else { local restype residuals disp in smcl "Residuals calculated using {it: predict, residuals}." } local residual_name "residuals" } if "`noadjust'" == "" { local noadjust = 0 } else { local noadjust = 1 local loop loop } tsunab varlist : `varlist', min(0) if "`varlist'" == "" { tempname varlist predict `varlist' , `restype' `trace' keep if e(sample) } *} **Test if sample exists `trace' sum `varlist' if "`r(N)'" == "0" { display in red "Error: no sample set" exit } ** Determine N, T and type of panel qui xtset2 , checkvars(`varlist') local id "`r(panelvar)'" local timevar "`r(timevar)'" local balanced "`r(balanced)'" sort `id' `timevar' egen `id_n' = group(`id') egen `time_new' = group(`timevar') if "`balanced'" != "strongly balanced" { local balanced = 0 **Fill Panel such that panel has entries for any year and id timer on 97 tsfill, full timer off 97 display "Unbalanced panel detected, test adjusted." } if "`balanced'" == "strongly balanced" { local balanced = 1 } if "`forceunbalanced'" != "" local balanced = 0 cap qui xtset2 if _rc != 0 { noi disp "Please install xtset2 from xtdcce2 package." noi disp "Panel information might be incorrect." sum `id_n' local N = r(max) sum `time_new' local T = r(max) } else { local T = r(Tmax) local N = r(N_g) } tempname RhoID qui putmata `RhoID' = `id' , replace mata `RhoID' = uniqrows(`RhoID') tempname CD CDp rhoMat `trace' sum `varlist' `trace' mata xtcd2_CD("`varlist'",`N',`T',`balanced',`noadjust',`pca',"`methods'",("`defactor'"!=""),`reps',"`CD'","`CDp'",("`rho'`heatplot'`heatplotmap'`kdensity'`contour'"!= ""),`rhoMat'=.,("`loop'"!="")) **** Return return clear return matrix CD = `CD', copy return matrix p = `CDp', copy return local methods "`methods'" return hidden local varlist "`varlist'" return hidden local residual_name "`residual_name'" return hidden local pesaran "`pesaran'" return hidden local cdw "`cdw'" return hidden local pea "`pea'" return hidden local cdstar "`cdstar'" return hidden local npca "`pca'" return hidden local CDN_g "`N'" return hidden local CDT "`T'" return hidden local noadjust = `noadjust' *** here order program if "`order'" != "" { tempname rho_tmp foreach var in `varlist' { mata `rho_tmp' = asarray(`rhoMat',"`var'") mata `rho_tmp' = xtcd2_rho_order(`rho_tmp',"`order'","`id'") mata `RhoID'_`var' = `rho_tmp'[.,cols(`rho_tmp')] mata asarray(`rhoMat',`rho_tmp'[.,1..cols(`rho_tmp')-1],"`var'") } } if "`kdensity'" == "kdensity" { tempname rho_tmp foreach var in `varlist' { mata `rho_tmp' = asarray(`rhoMat',"`var'") mata: `rho_tmp' = colshape(`rho_tmp' ,1) / sqrt(2*`T') drop _all getmata `rho_tmp' , replace qui sum `rho_tmp' , detail foreach s in mean min max p25 p50 p75 { local s`s' : di %9.3f `r(`s')' local s`s' = trim("`s`s''") } local sN: di %9.0f `r(N)' local sN = trim("`sN'") tempname CDi pi scalar `CDi' = `CD'["`var'",1] scalar `pi' = `CDp'["`var'",1] local cd: di %9.3f `CDi' local cd = trim("`cd'") local pval: di %9.3f `pi' local pval = trim("`pval'") if "`name'" != "" { local graphname name(`name'_`var' , replace) nodraw } else if wordcount("`varlist'") > 1 { local graphname name(`var', replace) } qui kdensity `rho_tmp' , xtitle({&rho}{sub:ij}) title(Cross-Sectional Correlations) `graphname' /// note("{bf:Statistics:} CD = `cd', p-value: `pval'" "Obs: `sN', Mean: `smean'" "Min: `smin', Max: `smax'" "Percentiles:" "25%: `sp25' , 50%: `sp50', 75:% `sp75'") } } if "`rho'" != "" { tempname rho_tmp local NumVar = wordcount("`varlist'") foreach var in `varlist' { mata st_matrix("`rho_tmp'",asarray(`rhoMat',"`var'")) if `NumVar' > 1 { return matrix rho_`var' = `rho_tmp' } else { return matrix rho = `rho_tmp' } } } restore if "`contour'`contourmap'`heatplot'`heatplotmap'" != "" { tempname rho_tmp qui { foreach var in `varlist' { mata `rho_tmp' = asarray(`rhoMat',"`var'") preserve clear local 0 ", `contour' `heatplot'" syntax [anything] , [ABSolute interp(string) levels(real 0) yscale(string) * ] if "`absolute'" != "" { mata `rho_tmp' = abs(`rho_tmp') } if `levels' == 0 { if `N' < 30 { local levels = `N' } else { local levels = 30 } } if "`interp'" == "" { local interp "none" } if "`yscale'" == "" { local yscale "reverse" } ///mata _makesymmetric(RHO_output) mata `rho_tmp' = xtcd2_rho_sym(`rho_tmp') mata `rho_tmp' = xtcd2_lowersym(`rho_tmp') tempname ordermat mata `ordermat' = (1::rows(`rho_tmp')) mata st_local("namelist",(invtokens("rho_" :+ strofreal(`ordermat')'))) getmata ( `namelist' ) = `rho_tmp' id1=`ordermat' reshape long rho_ , i(id1) j(id2) rename rho_ rho label var id1 "`id'" label var id2 "`id'" sort id1 id2 if "`name'" != "" & wordcount("`varlist'") == 1 { local graphname name(`name') } else { local graphname name(`var') } noi dis "" if "`contour'`contourmap'" != "" { twoway contour rho id1 id2 , interp(`interp') `options' level(`levels') yscale(`yscale') `graphname' } else { heatplot rho id1 id2 , `options' level(`levels') yscale(`yscale') `graphname' } restore } } } end ** auxiliary file with auxiliary programs findfile "xtdcce2_auxiliary.ado" include "`r(fn)'" /// output program cap program drop xtcd2_output program define xtcd2_output disp "" disp as text "Testing for weak cross-sectional dependence (CSD)" disp as text "{col 4}H0: weak cross-section dependence" disp as text "{col 4}H1: strong cross-section dependence" local firstline "{col 16}{c |}" local nums = 0 local coli_start = 15 local coli = `coli_start' + 5 local step = 14 tempname CD CDp matrix `CD' = r(CD) matrix `CDp' = r(p) local methods: colnames `CD' local varlist: rownames `CD' foreach type in `methods' { local firstline "`firstline' {col `coli'} `type'" local coli = `coli' + `step' local nums = `nums' + 1 } disp as text "{hline 15}{c TT}{hline `=`nums'*`step''}" disp as text "`firstline'" disp as text "{hline 15}{c +}{hline `=`nums'*`step''}" local i = 1 foreach var in `varlist' { local listi1 "" local listi2 "" local j = 1 foreach ests in `methods' { local val1 : disp %7.2f `CD'[`i',`j'] local listi1 `"`listi1' {col `=`coli_start'+(`j'-1)*`step'+1'} `val1'"' local val2 : disp %4.3f `CDp'[`i',`j'] local listi2 `"`listi2' {col `=`coli_start'+(`j'-1)*`step'+1'} (`val2')"' *disp as text "{col `=`coli_start'+(`j'-1)*`step''}" as result %7.2g _continue local j = `j' + 1 } if "`r(residual_name)'" != "" local var "`r(residual_name)'" disp as text abbrev("`var'",13) "{col `=`coli_start'+1'}{c |}" as result "`listi1'" disp as text "{col `=`coli_start'+1'}{c |}" as result "`listi2'" local i = `i' + 1 } local NumVar = `j' disp as text "{hline 15}{c BT}{hline `=`nums'*`step''}" *disp as text "Under null, CD ~ N(0,1)." disp as text "p-values in parenthesis." disp as text "References" if "`r(pesaran)'" != "" disp as smcl " CD: {col 13} Pesaran ({help xtcd2##Pesaran2015:2015}, {help xtcd2##Pesaran2021:2021})" if "`r(cdw)'" != "" disp as smcl " CDw: {col 13} Juodis, Reese ({help xtcd2##JR2021:2021})" if "`r(pea)'" != "" disp as smcl " CDw+: {col 13} CDw with power enhancement from Fan et al. ({help xtcd2##Fan2015:2015})" if "`r(cdstar)'" != "" disp as smcl " CD*: {col 13} Pesaran, Xie ({help xtcd2##PesaranXie2021:2021}) with `r(npca)' PC(s)" if `r(noadjust)' == 1 disp as smcl "Cross-sectional units not demeaned for calculation of cross-correlations." end /// program to calculate CD tests capture mata mata drop xtcd2_CD() mata: function xtcd2_CD ( string scalar data_names, real scalar N, real scalar T, real scalar balanced, real scalar stand, real scalar numpca, string scalar methods, real scalar defac, real scalar reps, string scalar CD_return, string scalar CDp_return, real scalar returnrho, real matrix rho, real matrix loop ) { data = st_data(.,data_names) K = cols(data) if (returnrho == 1) { rho = asarray_create() } /// which methods names = J(0,1,"") methods = tokens(methods) if (sum(methods:=="CD")==1) { cdpes = 1 names = names \ "CD" } if (sum(methods:=="CDw")==1) { cdw = 1 names = names \ "CDw" } if (sum(methods:=="CDwplus")==1) { pea = 1 names = names \ "CDw+" } if (sum(methods:=="CDstar")==1) { cdstar = 1 names = names \ "CD*" } CD = J(K,1,.) CD_star = J(K,1,.) CD_w = J(K,reps,.) CD_pea = J(K,reps,.) rng = rseed() /// inital CD test for (i=1;i<=K;i++) { /// reset seed rseed(rng) data_start = colshape(data[.,i],T)' for (r=1;r<=reps;r++) { /// standard CD stat if (r == 1) { rho_i = xtcd2_rho(data_start,N,T,stand,balanced,loop) CD[i,1] = sqrt(2/(N*(N-1))) * sum(rho_i) } if (cdw==1 | pea == 1) { data_cdw = data_start :* (2*runiformint(1,N,0,1):-1) rho_cdw = xtcd2_rho(data_cdw,N,T,stand,balanced,loop) CD_w[i,r] = sqrt(2/(N*(N-1))) * sum(rho_cdw) } if ((cdstar==1 & r==1) | defac == 1) { xtcd2_cdstar(data_start,N,T,numpca,loop,defac,stand,i,r,rho_i=rho_i,CD=CD,CD_w=CD_w,CD_star=CD_star) } if (pea == 1) { rabs = abs(rho_i) /// use correction Pesaran, Xie (2021) crit = 2*sqrt(log(N)/T) crit2 = (rabs:>crit) CD_pea[i,r] = CD_w[i,r] :+ sum(rabs:*(crit2)) } rho_i = rho_i / sqrt(2*T) if (returnrho == 1 & r==1) { asarray(rho,tokens(data_names)[i],rho_i) } } } CDo = J(K,0,.) if (cdpes == 1) CDo = CDo,CD if (cdw == 1) CDo = CDo, rowsum(CD_w) / sqrt(reps) if (pea == 1) CDo = CDo, rowsum(CD_pea) / sqrt(reps) if (cdstar == 1) CDo = CDo, CD_star[.,1] CDp = 2*(1:-normal(abs(CDo))) st_matrix(CD_return,CDo) st_matrix(CDp_return,CDp) cols = J(rows(names),1,""),(names) rows = J(K,1,""),tokens(data_names)' st_matrixrowstripe(CD_return,rows) st_matrixrowstripe(CDp_return,rows) st_matrixcolstripe(CD_return,cols) st_matrixcolstripe(CDp_return,cols) } end capture mata mata drop xtcd2_cdstar() mata: function xtcd2_cdstar( /// real matrix data_start,real scalar N, real scalar T,real scalar numpca,real scalar loop, real scalar defac, real scalar stand,real scalar i, real scalar r, /// real matrix rho_i, real matrix CD, real matrix CD_w, real matrix CD_star) { meanM = mean(data_start) sqrtM = sqrt(diagonal(quadvariance(data_start)))' if (hasmissing(data_start)) { meanM = quadcolsum(data_start):/quadcolsum(data_start!=.) sqrtM = colsum((data_start :- meanM):^2):/quadcolsum(data_start!=.) } data_ii = (data_start:-meanM):/sqrtM if (hasmissing(data_ii)==1) data_ii = xtdcce2_EM(data_ii,N,T,numpca,"CD*") data_i2 = data_ii * data_ii' eigensystem(data_i2,evec=.,eval=.) f = evec[.,numpca..1] fx = J(T,1,1),f fx = Re(fx) beta = qrinv(quadcross(fx,fx))*quadcross(fx,data_ii) res = data_ii :- fx*beta rho_defac = xtcd2_rho(res,N,T,stand,balanced,loop) CD_defac = sqrt(2/(N*(N-1))) * sum(rho_defac) /// update CD if defactored residuals used; might need to remove later? if (defac == 1) { if (r == 1) { CD[i,1] = sqrt(2/(N*(N-1))) * sum(rho_defac) } if (cdw==1 | pea == 1) { data_cdw = res :* (2*runiformint(1,N,0,1):-1) rho_cdw = xtcd2_rho(data_cdw,N,T,stand,balanced,loop) CD_w[i,r] = sqrt(2/(N*(N-1))) * sum(rho_cdw) } /// update rho rho_i = rho_defac } betai = beta[2..rows(beta),.] betaij = betai*betai':/N betasum = sqrt(diagonal(betaij)) /// what does this step do??? gamma = qrinv(diag(betasum))*betai sgm = sqrt(mean(res:^2)) eps = res :/ sgm phi = mean((gamma:/sgm)')' ai = (1:-(gamma:*sgm)'*phi)*1/sqrt(N) ewt = sum(ai:^2) ai2 = ai CD_star[i,1] = (CD_defac+sqrt(T/2)*(1:-ewt))/ewt } end capture mata mata drop xtcd2_rho() mata: function xtcd2_rho (real matrix r, real scalar N, real scalar T, real scalar stand,balanced,real scalar loop) { if ((balanced == 1 & hasmissing(meanM) == 0 & loop == 0) | (nonmissing(r)==0)) { "balanced" RHO = quadcorrelation(r)*sqrt(T) RHO = sublowertriangle(RHO)' _diag(RHO, 0) } else { "unbalanced - or no demeaning" if (stand == 0) { meanM = quadcolsum(r) :/quadcolsum(r:!=.) } else { meanM = J(1,N,0) } "mean" meanM RHO = quadcorrelation(r :- meanM)*sqrt(T) RHO = sublowertriangle(RHO)' _diag(RHO, 0) if (hasmissing(RHO) | loop == 1) { if (hasmissing(RHO) | loop == 1) { maxi = N - 1 RHO = J(N,N,.) r2 = editmissing(r,0) "do loop" for (i=1; i<=maxi; i++) { minj = i + 1 for (j = minj; j<=N; j++) { if (i 0 ) { neworder = neworder \ newi } i++ } rho = xtcd2_rho_sym(rho) rhorder = rho[neworder,neworder] /// remove lower symmetric part rhorder= xtcd2_lowersym(rhorder) rhoID = rhoiuniq[neworder,1] ///_makesymmetric(rhorder) rhorder = rhorder,rhoID return(rhorder) } end capture mata mata drop xtcd2_rho_sym() mata: function xtcd2_rho_sym(real matrix rhorder) { N = rows(rhorder) i = 1 while(i<=N) { j=i while (j<=N) { ij = rhorder[i,j] ji = rhorder[j,i] if (ij:==. & ji:!= .) { rhorder[i,j] = ji } else if (ij:!= . & ji:== .) { rhorder[j,i] = ij } j++ } i++ } return(rhorder) } end capture mata mata drop xtcd2_lowersym() mata: function xtcd2_lowersym(real matrix rhorder) { N = rows(rhorder) i = 1 while(i<=N) { j=1 while (j