*! xtccecoint.ado — Panel CCE Cointegration Test
*! Version 1.0.0 — 2026-05-11
*! Author: Dr. Merwan Roudane (merwanroudane920@gmail.com)
*!
*! Implements the CADF_P panel cointegration test from:
*!   Banerjee, A. & Carrion-i-Silvestre, J.L. (2017).
*!   "Testing for Panel Cointegration Using Common Correlated Effects Estimators."
*!   Journal of Time Series Analysis, DOI: 10.1111/jtsa.12234
*!
*! GAUSS source translated: cadfcoin_multiple.src
*!   by Josep Lluis Carrion-i-Silvestre (August 21st, 2021)
*!
*! Key options mirror the GAUSS sample.prg setup:
*!   model   : 0=none, 1=constant, 2=constant+trend   [GAUSS: model = 0|1|2]
*!   nfactors: number of common factors               [GAUSS: num_factors]
*!   method  : 0=no CCE, 1=CCE                        [GAUSS: method = 0|1]
*!   option  : 0=Individual, 1=MG, 2=Pooled CCE       [GAUSS: option = 0|1|2]
*!   plags   : AR order for CADF regression           [GAUSS: p]
*!
*! Data: Stata long format (xtset panelvar timevar), balanced panel required

capture program drop xtccecoint
program define xtccecoint, eclass
    version 14

    // ── Syntax ──────────────────────────────────────────────────────────────
    syntax varlist(min=2 numeric) [if] [in], ///
        [Model(string)          /// 0, 1, or 2 (default: 2)
         NFactors(string)       /// number of common factors (default: k+1)
         Method(string)         /// 0=no CSD, 1=CCE (default: 1)
         OPTion(string)         /// 0=individual, 1=MG, 2=pooled (default: 2)
         PLags(string)          /// AR lag order for CADF (default: 1)
         NOTRuncate             /// suppress truncation of t-ratios
         PLot                   /// produce visualization plots
         NOTable                /// suppress output tables
         SAVing(string)         /// filename stem for saving graphs
         NOIsily                /// verbose Mata output
         ]

    // ── Parse options ────────────────────────────────────────────────────────
    if "`model'"    == "" local model    "2"
    if "`method'"   == "" local method   "1"
    if "`option'"   == "" local option   "2"
    if "`plags'"    == "" local plags    "1"

    local model_n  = real("`model'")
    local method_n = real("`method'")
    local option_n = real("`option'")
    local plags_n  = real("`plags'")

    if !inlist(`model_n', 0, 1, 2) {
        di as error "model() must be 0, 1, or 2."
        exit 198
    }
    if !inlist(`method_n', 0, 1) {
        di as error "method() must be 0 (no CSD) or 1 (CCE)."
        exit 198
    }
    if !inlist(`option_n', 0, 1, 2) {
        di as error "option() must be 0 (individual), 1 (MG), or 2 (pooled CCE)."
        exit 198
    }

    local do_trunc = ("`notruncate'" == "")
    local verbose  = ("`noisily'"    != "")

    // ── Sample ──────────────────────────────────────────────────────────────
    marksample touse
    markout `touse' `varlist'

    // ── Validate panel structure ─────────────────────────────────────────────
    qui xtset
    local panelvar "`r(panelvar)'"
    local timevar  "`r(timevar)'"

    if "`panelvar'" == "" {
        di as error "Data must be xtset before calling xtccecoint."
        exit 459
    }

    // ── Parse varlist ────────────────────────────────────────────────────────
    local depvar    : word 1 of `varlist'
    local indepvars : list varlist - depvar
    local k         : word count `indepvars'

    if `k' < 1 {
        di as error "xtccecoint requires at least one independent variable."
        exit 102
    }

    // ── Default nfactors = k+1 (rank condition with equality) ────────────────
    if "`nfactors'" == "" local nfactors = `k' + 1
    local nfactors_n = real("`nfactors'")
    if `nfactors_n' < 1 {
        di as error "nfactors() must be a positive integer."
        exit 198
    }

    // ── Count observations ───────────────────────────────────────────────────
    qui xtsum `depvar' if `touse'
    local N_g = r(n)
    local T   = r(Tbar)

    if `N_g' < 5 {
        di as error "xtccecoint requires at least 5 panel units."
        exit 2000
    }
    if `T' < 20 {
        di as error "xtccecoint requires at least 20 time periods."
        exit 2001
    }

    // ── Model label ──────────────────────────────────────────────────────────
    if `model_n' == 0 local modlab "0 (no deterministics)"
    else if `model_n' == 1 local modlab "1 (constant)"
    else local modlab "2 (constant + trend)"

    // ── Estimator label ──────────────────────────────────────────────────────
    if `method_n' == 0 local estlab "OLS (no cross-section dependence)"
    else {
        if `option_n' == 0 local estlab "Individual CCE"
        else if `option_n' == 1 local estlab "Mean Group CCE (MG-CCE)"
        else local estlab "Pooled CCE (PCCE) [recommended]"
    }

    // ── Display running message ──────────────────────────────────────────────
    di ""
    di as text "  {bf:xtccecoint} {c -} Panel CCE Cointegration Test"
    di as text "  Banerjee & Carrion-i-Silvestre (2017, JTSA)"
    di as text "  " "{hline 65}"
    di as text "  N = `N_g' units | T ≈ `=round(`T')' periods"
    di as text "  Model: `modlab'"
    di as text "  Estimator: `estlab'"
    di as text "  Common factors (r): `nfactors_n' | AR lags (p): `plags_n'"
    if `do_trunc' di as text "  Truncation: ON (Pesaran 2007)"
    else           di as text "  Truncation: OFF"
    di as text "  Computing..."
    di ""

    // ── Load Mata engine ─────────────────────────────────────────────────────
    capture mata: mata describe xtcce_main
    if _rc {
        capture quietly do "_xtccecoint_mata.ado"
        if _rc {
            capture findfile _xtccecoint_mata.ado
            if !_rc {
                capture quietly do `"`r(fn)'"'
            }
            if _rc {
                local mypath : sysdir PLUS
                capture quietly do `"`mypath'x/xtccecoint/_xtccecoint_mata.ado"'
            }
        }
    }

    // ── Call Mata engine ─────────────────────────────────────────────────────
    mata: xtcce_main("`depvar'", "`indepvars'",    ///
                     "`touse'",  "`panelvar'",       ///
                     "`timevar'",                    ///
                     `model_n',  `nfactors_n',       ///
                     `method_n', `option_n',         ///
                     `plags_n',  `do_trunc',         ///
                     `verbose')

    // ── Retrieve scalars ─────────────────────────────────────────────────────
    local cadfp = _xcce_cadfp
    local N_obs = _xcce_N
    local T_obs = _xcce_T
    local k_obs = _xcce_k
    local r_obs = _xcce_r

    // ── Get critical values ──────────────────────────────────────────────────
    // Look up 5% and 10% CVs using embedded tables
    mata: st_numscalar("_xcce_cv5",  xtcce_cv_lookup(`model_n', `k_obs'+1, `nfactors_n', `plags_n', `T_obs', `N_obs', 5))
    mata: st_numscalar("_xcce_cv10", xtcce_cv_lookup(`model_n', `k_obs'+1, `nfactors_n', `plags_n', `T_obs', `N_obs', 10))
    local cv5  = _xcce_cv5
    local cv10 = _xcce_cv10

    // ── Display output tables ────────────────────────────────────────────────
    if "`notable'" == "" {
        _xtccecoint_display,            ///
            cadfp(`cadfp')              ///
            cv5(`cv5') cv10(`cv10')     ///
            nunits(`N_obs')             ///
            tperiods(`T_obs')           ///
            kregs(`k_obs')              ///
            rfactors(`r_obs')           ///
            plagopt(`plags_n')          ///
            modelopt(`model_n')         ///
            depopt(`depvar')            ///
            indepopt(`indepvars')       ///
            panopt(`panelvar')          ///
            timeopt(`timevar')          ///
            estlab(`estlab')            ///
            dotrunc(`do_trunc')
    }

    // ── Plots ────────────────────────────────────────────────────────────────
    if "`plot'" != "" {
        local save_opt ""
        if "`saving'" != "" local save_opt "saving(`saving')"

        _xtccecoint_plot,               ///
            depopt(`depvar')            ///
            indepopt(`indepvars')       ///
            modelopt(`model_n')         ///
            nunits(`N_obs')             ///
            tperiods(`T_obs')           ///
            plagopt(`plags_n')          ///
            cv5(`cv5') cv10(`cv10')     ///
            `save_opt'
    }

    // ── Store results in e() ─────────────────────────────────────────────────
    tempname b_pcce V_pcce t_ind beta_vec ids_vec

    // Build e(b) from PCCE estimate
    matrix `beta_vec' = _xcce_beta
    matrix colnames `beta_vec' = `indepvars'

    // Build dummy e(V)
    matrix `V_pcce' = J(`k_obs', `k_obs', 0)
    matrix colnames `V_pcce' = `indepvars'
    matrix rownames `V_pcce' = `indepvars'

    ereturn clear
    ereturn post `beta_vec' `V_pcce', esample(`touse')

    // Individual statistics
    matrix `t_ind' = _xcce_t_ind
    ereturn matrix cadf_ind = `t_ind'

    // Scalars
    ereturn scalar cadfp     = `cadfp'
    ereturn scalar cv5       = `cv5'
    ereturn scalar cv10      = `cv10'
    ereturn scalar N         = `N_obs'
    ereturn scalar T         = `T_obs'
    ereturn scalar k         = `k_obs'
    ereturn scalar nfactors  = `r_obs'
    ereturn scalar plags     = `plags_n'
    ereturn scalar model     = `model_n'
    ereturn scalar method    = `method_n'
    ereturn scalar opttype   = `option_n'
    ereturn scalar truncated = `do_trunc'

    // Macros
    ereturn local cmd       "xtccecoint"
    ereturn local cmdline   "xtccecoint `0'"
    ereturn local depvar    "`depvar'"
    ereturn local indepvars "`indepvars'"
    ereturn local panelvar  "`panelvar'"
    ereturn local timevar   "`timevar'"
    ereturn local estimator "`estlab'"
    ereturn local modtype   "`modlab'"
    ereturn local papers    "Banerjee & Carrion-i-Silvestre (2017, JTSA)"

    di as text "  Note: All results stored in {cmd:e()}. Use {cmd:ereturn list} for details."
    di as text "  CADF_P = {res:`=string(round(`cadfp',0.0001))'}"
    di ""
end