*! Timothy Neal -- 17/10/16
*! This is the third public version of xtcce, used to conduct a number of versions of Pesaran's Common Correlated Effects approach. 
*! If there are any questions, issues, or comparatibility problems with this procedure, please email tjrneal@gmail.com. 
*! I acknowledge the help of the command xtmg by Markus Eberhardt when setting up the display of the preliminary panel statistics.  
*! List of changes for the third version:
*!	- Fixes a bug that occasionally occured when 2SLS or GMM models were run. Please rerun all results if these were used in your research.
*! List of changes for the second version:
*!	- Corrects the estimation results from the option "pooled". Please rerun all results if this option was selected in your research.
*! 	- Allows the user to save the residuals.

program define xtcce, eclass prop(xt)
	version 11
	*! Parses ivregress syntax 
	_iv_parse `0'
	local Y `s(lhs)'
	local endo `s(endog)'
	local Xs `s(exog)'
	local instr `s(inst)'
	local 0 `s(zero)'

	syntax [if] [in] [, COV(string) ALAGS(integer -2) DYNAMIC GMM POOLED FULL WEIGHTED RES(string)]
	qui{	
	*! Mark the sample that is usable, identify the panel and time variable, and calculate other panel statistics.
	marksample touse
	xtset
	local ivar `r(panelvar)'
	local tvar `r(timevar)'
	sort `ivar' `tvar'
	quie levels `ivar' if `touse', local(ids)
	global iis "`ids'"
	quie count if `touse'
	local is=wordcount("$iis")
	count if `touse' 
	local n = r(N)
	
	*! Determine the title
	if "`endo'" == "" & "`dynamic'" != "" { // DCCE MG
		if ("`pooled'" != "") local title "Dynamic Common Correlated Effects Estimation - Pooled OLS"
		else local title "Dynamic Common Correlated Effects Estimation - Mean Group OLS"
	} 
	else if "`endo'" == "" { // CCE MG
		if ("`pooled'" != "") local title "Common Correlated Effects Estimation - Pooled OLS"
		else local title "Common Correlated Effects Estimation - Mean Group OLS"
	} 
	else if "`dynamic'" != "" & "`gmm'" != "" { // DCCE-GMM MG
		if ("`pooled'" != "") local title "Dynamic Common Correlated Effects Estimation - Pooled GMM"
		else local title "Dynamic Common Correlated Effects Estimation - Mean Group GMM (HAC)"
	}
	else if "`gmm'" != "" { // CCE-GMM MG
		if ("`pooled'" != "") local title "Common Correlated Effects Estimation - Pooled GMM"
		else local title "Common Correlated Effects Estimation - Mean Group GMM (HAC)"
	}
	else if "`dynamic'" != "" { // DCCE-2SLS MG
		if ("`pooled'" != "") local title "Dynamic Common Correlated Effects Estimation - Pooled 2SLS"		
		else local title "Dynamic Common Correlated Effects Estimation - Mean Group 2SLS"	
	}
	else { // CCE-2SLS MG
		if ("`pooled'" != "") local title "Common Correlated Effects Estimation - Pooled 2SLS"
		else local title "Common Correlated Effects Estimation - Mean Group 2SLS"
	}

	*! Create a list of vars that have the time averages, for inclusion in later regression.
	local i = 1
	foreach x in `Y' `Xs' `endo' `cov' {
		if (!strpos("`x'", ".")) {
			tempvar tm`i' hold
			gen `hold' = `x'
			bysort `tvar': egen `tm`i''`x'_csa = mean(`hold') if `touse'
			sort `ivar' `tvar'
			drop `hold'
			local tmeanlist "`tmeanlist' `tm`i''`x'_csa"
			local tmeanlistnames "`tmeanlistnames' `x'_csa"
			local i = `i' + 1
		}
	}
	*! Determine the number of lags to the cross-section averages to use
	if "`dynamic'" != "" {
		if (`alags' < 0) local alags1 = round((`n'/`is')^(1/3))
		else local alags1 = `alags'
	}	
	*! Find m and also set up a name macro
	if "`dynamic'" != "" {
			tsunab dylist: `endo' `Xs' l(`alags1'/0).(`tmeanlist')
			local m=wordcount("`dylist'") + 1
			// Modifying the names list so that the local macro jargon doesn't come up in the results table
			local i = 1
			local names `dylist' constant
			foreach x in `Y' `endo' `Xs' `cov' {
				local names = subinstr("`names'","`tm`i''","",.)
				local i = `i' + 1
			}
	}
	else {
			local m=wordcount("`Xs' `endo' `tmeanlist'") + 1
			local names `endo' `Xs' `tmeanlistnames' constant
	}
	
	if "`res'" != "" {
		tempvar resid
		gen `res' = .
	}
		

	
	*! Part 2: Pooled Regression
	if "`pooled'" != "" {
		if ("`endo'" == "" & "`dynamic'" != "") regress `Y' `Xs' i.`ivar' i.`ivar'#c.(l(`alags1'/0).(`tmeanlist')) if `touse' // DCCE Pooled
		else if ("`endo'" == "") regress `Y' `Xs' i.`ivar' i.`ivar'#c.(`tmeanlist') if `touse' // CCE Pooled
		else if ("`dynamic'" != "" & "`gmm'" != "") ivregress gmm `Y' `Xs' i.`ivar' i.`ivar'#c.(l(`alags1'/0).(`tmeanlist')) (`endo' = `instr') if `touse' // DCCE-GMM Pooled
		else if ("`gmm'" != "") ivregress gmm `Y' `Xs' i.`ivar' i.`ivar'#c.(`tmeanlist') (`endo' = `instr') if `touse' // CCE-GMM Pooled
		else if ("`dynamic'" != "") ivregress 2sls `Y' `Xs' i.`ivar' i.`ivar'#c.(l(`alags1'/0).(`tmeanlist')) (`endo' = `instr') if `touse' // DCCE-2sls Pooled
		else ivregress 2sls `Y' `Xs' i.`ivar' i.`ivar'#c.(`tmeanlist') (`endo' = `instr') if `touse' // CCE-2SLS Pooled
		matrix bavg = e(b)
		matrix vce = e(V)	
		
		// Save residuals (if specified)
		if "`res'" != "" {
			predict `resid', residuals 
			replace `res' = `resid' if `touse'
			drop `resid'
		}
	}
	else { // Part 3: Mean Group Regression
		mata: setup(`m')
				
		qui foreach i of global iis {		
			tempvar tvar2
			// Regressions
			if ("`endo'" == "" & "`dynamic'" != "") regress `Y' `Xs' l(`alags1'/0).(`tmeanlist') if `ivar' == `i' & `touse' // DCCE MG
			else if ("`endo'" == "") regress `Y' `Xs' `tmeanlist' if `ivar' == `i' & `touse' // CCE MG
			else if "`dynamic'" != "" & "`gmm'" != "" { // DCCE-GMM MG
				gen `tvar2' = `tvar' if `ivar'==`i'
				tsset `tvar2'
				ivregress gmm `Y' `Xs' l(`alags1'/0).(`tmeanlist') (`endo' = `instr') if `ivar' == `i' & `touse', wmatrix(hac bartlett opt)
				xtset `ivar' `tvar'
			}
			else if "`gmm'" != "" { // CCE-GMM MG
				gen `tvar2' = `tvar' if `ivar'==`i'
				tsset `tvar2'
				ivregress gmm `Y' `Xs' `tmeanlist' (`endo' = `instr') if `ivar' == `i' & `touse', wmatrix(hac bartlett opt)		
				xtset `ivar' `tvar'
			}
			else if ("`dynamic'" != "") ivregress 2sls `Y' `Xs' l(`alags1'/0).(`tmeanlist') (`endo' = `instr') if `ivar' == `i' & `touse' // DCCE-2SLS MG
			else ivregress 2sls `Y' `Xs' `tmeanlist' (`endo' = `instr') if `ivar' == `i' & `touse' // CCE-2SLS MG

			// Save residuals (if specified)
			if "`res'" != "" {
				predict `resid', residuals 
				replace `res' = `resid' if `ivar' == `i' & `touse'
				drop `resid'
			}
			
			// Display the individual results if specified
			local nind = e(N)
			if "`full'" != "" {
				//count if `touse' & `ivar' == `i'
				noi display ""
				noi display ""
				noi display "`title'"
				noi display ""
				noi display in gr "Results for panel unit: `i'			" in gr "	Observations: `nind'" 
				noi ereturn display
			}
			
			// Save results
			mata: saveresults(`nind')
		}
		mata: meanresults(`is', "`weighted'")
	}
	
	// Averaging of the results
	if ("`pooled'" == "") local obies = obsv
	else local obies = e(N)
	
	if ("`pooled'" == "") matrix colnames bavg = `names'
	if ("`pooled'" == "") matrix rownames vce = `names'
	if ("`pooled'" == "") matrix colnames vce = `names'
	if ("`pooled'" == "") matrix colnames fullb = `names'
	ereturn post bavg vce, depname("`Y'") esample(`touse') obs(`obies')
	
	// Ereturn storing
	if ("`pooled'" == "") mata: poste()
	ereturn local tvar "`tvar'"
	ereturn local ivar "`ivar'"
	ereturn local cmd "xtcce"
	if ("`pooled'" != "") ereturn local title "Pooled Estimation"
	else if ("`weighted'" != "") ereturn local title "Weighted mean group estimation"
	else ereturn local title "Mean group estimation"
	if ("`pooled'" == "") ereturn matrix bfull = fullb
	ereturn scalar N_g = `is'
	
	capture test `Xs' `endo', min constant
	if (_rc == 0) {
		ereturn scalar chi2 = r(chi2)
		ereturn scalar df_m = r(df)
	}
	else est scalar df_m = 0
	ereturn local chi2type "Wald"

	noi { // Display Results
		display ""
		display ""
		display "`title'" 
		
	// Preliminary stats
	_crcphdr
	
	// Display the main regression results	
	ereturn display
	
	// Postscripts
	display "The suffix _csa is used to denote the cross section average of the preceding variable." 
	if ("`weighted'" != "" & "`pooled'" == "") display in gr "The mean group estimates have been weighted by the standard errors of the individual coefficients."
	else if ("`pooled'" == "") display in gr "The mean group estimates are unweighted."
	if ("`dynamic'" != "") {
		if ("`endo'" != "") display in gr "Instruments for endogenous vars: `Xs' `instr' l(`alags1'/0).(`tmeanlistnames') constant" 
	}
	else {
		if ("`endo'" != "") display in gr "Instruments for endogenous vars: `Xs' `instr' `tmeanlistnames' constant" 
	}
	}
	}
end

mata:
void setup (real scalar m) {
	external real matrix fullresults, nind, fullse
	fullresults = J(1,m,0)
	nind = J(1,1,0)
	fullse = J(1,m,0)
}
void saveresults (real scalar n) {
	external real matrix fullresults, nind, fullse
	b = st_matrix("e(b)")
	fullresults = fullresults \ b
	nind = nind \ n
	eV = sqrt(diagonal(st_matrix("e(V)")))'
	fullse = fullse \ eV
}
void meanresults (real scalar is, string weighted) {
	external real matrix fullresults, fullse, nind
	obs = sum(nind)
	bfull = fullresults[| 2,1 \ .,.|]
	fullse2 = 1 :/ fullse[|2,1 \ .,.|]
	if (weighted != "") {
		bmean = colsum(bfull :* fullse2) :/ colsum(fullse2)
	}
	else {
		bmean = mean(bfull)
	}
	tmp = bfull - J(is,1,1)#(bmean)
	v = tmp' * tmp / (is*(is-1))
	st_matrix("nind2", nind2)
	st_matrix("bavg", bmean)
	st_matrix("vce", v)
	st_matrix("fullb", bfull)
	st_numscalar("obsv",obs)
}
void poste () {
	external real matrix nind
	nind2 = nind[| 2,1 \ .,.|]
	g1 = min(nind2)
	g2 = mean(nind2)
	g3 = max(nind2)
	st_numscalar("e(g_min)",g1)
	st_numscalar("e(g_avg)",g2)
	st_numscalar("e(g_max)",g3)
}
end