*! _qardl_ecm v1.0.0 - QARDL Error Correction Model estimation *! Translates qardlecm.m (MATLAB) *! Author: Dr Merwan Roudane (merwanroudane920@gmail.com) program define _qardl_ecm, rclass version 14.0 * Ensure core Mata function _qardl_qreg() is available capture mata: mata which _qardl_qreg() if _rc { * Load it by running the estimation ado capture program drop _qardl_estimate qui findfile _qardl_estimate.ado qui run "`r(fn)'" } syntax varlist(min=2 numeric ts) [if] [in], P(integer) Q(integer) /// TAU(numlist >0 <1 sort) [NOCONStant] marksample touse gettoken depvar indepvars : varlist local k : word count `indepvars' qui count if `touse' local nobs = r(N) * First run standard QARDL _qardl_estimate `varlist' if `touse', p(`p') q(`q') tau(`tau') `noconstant' tempname beta beta_cov phi phi_cov gamma gamma_cov bt_raw fh_vec mat `beta' = r(beta) mat `beta_cov' = r(beta_cov) mat `phi' = r(phi) mat `phi_cov' = r(phi_cov) mat `gamma' = r(gamma) mat `gamma_cov' = r(gamma_cov) mat `bt_raw' = r(bt_raw) mat `fh_vec' = r(fh_vec) * Put data into Mata for ECM computation qui putmata _ecm_y = `depvar' if `touse', replace local vi = 0 local mxvars "" foreach v of local indepvars { local ++vi tempvar xv`vi' qui gen double `xv`vi'' = `v' if `touse' local mxvars `mxvars' `xv`vi'' } qui putmata _ecm_X = (`mxvars') if `touse', replace mata: _ecm_tau = strtoreal(tokens(st_local("tau")))' * Run ECM estimation in Mata mata: _qardl_ecm_estimate(_ecm_y, _ecm_X, `p', `q', _ecm_tau) * Return all results return matrix beta = `beta' return matrix beta_cov = `beta_cov' return matrix phi = `phi' return matrix phi_cov = `phi_cov' return matrix gamma = `gamma' return matrix gamma_cov = `gamma_cov' return matrix phi_ecm = _qardl_phi_ecm return matrix phi_ecm_cov = _qardl_phi_ecm_cov return matrix theta = _qardl_theta return matrix theta_cov = _qardl_theta_cov return matrix bt_raw = `bt_raw' return matrix fh_vec = `fh_vec' return scalar p = `p' return scalar q = `q' return scalar k = `k' return scalar N = `nobs' end capture mata: mata drop _qardl_ecm_estimate() mata: mata set matastrict off void _qardl_ecm_estimate(real colvector yy, real matrix xx, real scalar ppp, real scalar qqq, real colvector tau) { real scalar nn, k0, ss, jj, ii, i, rr, neff real colvector hb, hs, bt1 real matrix ee, eei, xxi, yyi, X_mat, ONEX, Y_vec real matrix bt, fh, uu, barw, tw, mm, bb, qq_mat real matrix midbt, midphi real matrix kk, kkk_vec, bbt, kka, tilw, llla, cc real matrix bigpib, bigphi_vec, dd1, bigphia, bigpia, R1, A, A1, A2 real matrix gg, gg1, gg2, dg, uu2, barw1, QQQ, psiu, sigmma, distmt real matrix distmt1, distmt2, distmt3, thett1, thett2, thett3, thett4 real matrix thett34, thett345, thett, distthett real scalar var1, sum_phi nn = rows(yy) k0 = cols(xx) ss = rows(tau) // Bandwidth hb = J(ss, 1, 0) hs = J(ss, 1, 0) for (jj = 1; jj <= ss; jj++) { var1 = invnormal(tau[jj]) hb[jj] = (4.5 * normalden(var1)^4 / (nn*(2*var1^2+1)^2))^0.2 hs[jj] = invnormal(0.975)^(2/3) * (1.5*normalden(var1)^2 / (nn*(2*var1^2+1)))^(1/3) } // Data construction (same as standard QARDL) ee = xx[2..nn, .] - xx[1..nn-1, .] ee = J(1, k0, 0) \ ee eei = J(nn-qqq, qqq*k0, 0) xxi = xx[qqq+1..nn, .] yyi = J(nn-ppp, ppp, 0) for (jj = 1; jj <= k0; jj++) { for (ii = 0; ii <= qqq-1; ii++) { eei[., ii+1+(jj-1)*qqq] = ee[qqq+1-ii..nn-ii, jj] } } for (ii = 1; ii <= ppp; ii++) { yyi[., ii] = yy[1+ppp-ii..nn-ii] } if (ppp > qqq) { X_mat = (eei[rows(eei)+1-rows(yyi)..rows(eei), .], xxi[rows(xxi)+1-rows(yyi)..rows(xxi), .], yyi) } else { X_mat = (eei, xxi, yyi[rows(yyi)+1-rows(xxi)..rows(yyi), .]) } ONEX = (J(rows(X_mat), 1, 1), X_mat) Y_vec = yy[nn-rows(X_mat)+1..nn] // Quantile regression bt = J(cols(ONEX), ss, 0) fh = J(ss, 1, 0) if (ppp > qqq) { uu = J(nn-ppp, ss, 0) } else { uu = J(nn-qqq, ss, 0) } for (jj = 1; jj <= ss; jj++) { bt1 = _qardl_qreg(Y_vec, ONEX, tau[jj]) uu[., jj] = Y_vec - ONEX * bt1 fh[jj] = mean(normalden(-uu[., jj] / hb[jj])) / hb[jj] bt[., jj] = bt1 } // barw and tw barw = J(nn-1, qqq*k0, 0) for (jj = 1; jj <= qqq; jj++) { barw[jj..nn-1, k0*(jj-1)+1..k0*jj] = ee[2..nn-jj+1, .] } tw = (J(nn-1, 1, 1), barw) // phi coefficients for ECM if (ppp > qqq) { neff = nn - ppp real matrix yyj_ecm, xxj_ecm, wwj_ecm yyj_ecm = J(neff, ppp, 0) wwj_ecm = J(neff, qqq*k0, 0) for (jj = 1; jj <= ppp; jj++) { yyj_ecm[., jj] = yy[ppp+1-jj..nn-jj] } for (ii = 1; ii <= k0; ii++) { for (jj = 1; jj <= qqq; jj++) { wwj_ecm[., jj+(ii-1)*qqq] = ee[ppp-jj+2..nn-jj+1, ii] } } xxj_ecm = xx[ppp+1..nn, .] kk = J(neff, ss*ppp, 0) for (jj = 1; jj <= ppp; jj++) { Y_vec = yyj_ecm[., jj] ONEX = (J(neff, 1, 1), xxj_ecm, wwj_ecm) for (ii = 1; ii <= ss; ii++) { bbt = _qardl_qreg(Y_vec, ONEX, tau[ii]) kkk_vec = Y_vec - ONEX * bbt kk[., jj+(ii-1)*ppp] = kkk_vec } } } else { neff = nn - qqq real matrix yyj_e2, xxj_e2, wwj_e2 yyj_e2 = J(neff, ppp, 0) wwj_e2 = J(neff, qqq*k0, 0) for (jj = 1; jj <= ppp; jj++) { yyj_e2[., jj] = yy[qqq+1-jj..nn-jj] } for (ii = 1; ii <= k0; ii++) { for (jj = 1; jj <= qqq; jj++) { wwj_e2[., jj+(ii-1)*qqq] = ee[qqq-jj+2..nn-jj+1, ii] } } xxj_ecm = xx[qqq+1..nn, .] kk = J(neff, ss*ppp, 0) for (jj = 1; jj <= ppp; jj++) { Y_vec = yyj_e2[., jj] ONEX = (J(neff, 1, 1), xxj_ecm, wwj_e2) for (ii = 1; ii <= ss; ii++) { bbt = _qardl_qreg(Y_vec, ONEX, tau[ii]) kkk_vec = Y_vec - ONEX * bbt kk[., jj+(ii-1)*ppp] = kkk_vec } } } // Remove first column of each tau block (ECM specific) // dd1 contains indices to remove: 1, 1+ppp, 1+2*ppp, ... real colvector dd_idx, keep_idx dd_idx = J(ss, 1, 0) dd_idx[1] = 1 for (jj = 2; jj <= ss; jj++) { dd_idx[jj] = 1 + ppp*(jj-1) } // Build kka by removing columns at dd_idx real scalar ncols_kk, ncols_kka, col_keep, is_remove ncols_kk = cols(kk) ncols_kka = ncols_kk - ss kka = J(rows(kk), ncols_kka, 0) col_keep = 0 for (jj = 1; jj <= ncols_kk; jj++) { is_remove = 0 for (ii = 1; ii <= ss; ii++) { if (jj == dd_idx[ii]) is_remove = 1 } if (!is_remove) { col_keep++ kka[., col_keep] = kk[., jj] } } if (ppp > qqq) { tilw = tw[ppp..nn-1, .] llla = (kka' * kka - kka' * tilw * luinv(tilw' * tilw) * tilw' * kka) / neff } else { tilw = tw[qqq..nn-1, .] llla = (kka' * kka - kka' * tilw * luinv(tilw' * tilw) * tilw' * kka) / neff } // C matrix cc = J(ss, ss, 0) for (jj = 1; jj <= ss; jj++) { for (ii = 1; ii <= ss; ii++) { cc[jj, ii] = (min((tau[jj], tau[ii])) - tau[jj]*tau[ii]) / (fh[ii]*fh[jj]) } } // Big Pi for ECM phi (p-1 dimensional) real scalar pp1 pp1 = ppp - 1 if (pp1 < 1) pp1 = 1 bigpib = J(ss*pp1, ss*pp1, 0) for (jj = 1; jj <= ss; jj++) { for (ii = 1; ii <= ss; ii++) { real matrix llla_jj, llla_ji, llla_ii, psu_mat llla_jj = llla[(jj-1)*pp1+1..jj*pp1, (jj-1)*pp1+1..jj*pp1] llla_ji = llla[(jj-1)*pp1+1..jj*pp1, (ii-1)*pp1+1..ii*pp1] llla_ii = llla[(ii-1)*pp1+1..ii*pp1, (ii-1)*pp1+1..ii*pp1] psu_mat = luinv(llla_jj) * llla_ji * luinv(llla_ii) bigpib[(jj-1)*pp1+1..jj*pp1, (ii-1)*pp1+1..ii*pp1] = cc[jj,ii] * psu_mat } } // Extract phi and reparameterize for ECM midphi = J(ppp, ss, 0) for (jj = 1; jj <= ss; jj++) { midphi[., jj] = bt[2+(qqq+1)*k0..1+(qqq+1)*k0+ppp, jj] } bigphi_vec = vec(midphi) // Remove first element per quantile block real colvector bigphi_ecm real scalar nkeep nkeep = rows(bigphi_vec) - ss bigphi_ecm = J(nkeep, 1, 0) col_keep = 0 for (jj = 1; jj <= rows(bigphi_vec); jj++) { is_remove = 0 for (ii = 1; ii <= ss; ii++) { if (jj == dd_idx[ii]) is_remove = 1 } if (!is_remove) { col_keep++ bigphi_ecm[col_keep] = bigphi_vec[jj] } } // Apply upper triangular cumulative sum transformation A = J(pp1, pp1, 0) for (i = 1; i <= pp1; i++) { for (jj = i; jj <= pp1; jj++) { A[i, jj] = 1 } } A1 = A A2 = I(ss) R1 = A2 # A1 bigphia = -R1 * bigphi_ecm bigpia = R1 * bigpib * R1' // Theta computation // Scale matrix if (ppp > qqq) { gg1 = J(1+qqq*k0, 1, sqrt(neff)) gg2 = J(k0, 1, neff) } else { gg1 = J(1+qqq*k0, 1, sqrt(neff)) gg2 = J(k0, 1, neff) } gg = gg1 \ gg2 dg = diag(gg) uu2 = uu if (ppp > qqq) { barw1 = barw[ppp..nn-1, .] } else { barw1 = barw[qqq..nn-1, .] } // Q matrix real scalar r1 real rowvector r2, r3 real matrix r5, r6, r9 r1 = 1 r2 = colsum(barw1) / neff r3 = colsum(xxj_ecm) / neff^(3/2) r5 = barw1' * barw1 / neff r6 = barw1' * xxj_ecm / neff^(3/2) r9 = xxj_ecm' * xxj_ecm / neff^2 QQQ = (r1, r2, r3 \ r2', r5, r6 \ r3', r6', r9) // Psi matrix psiu = J(neff, ss, 0) for (jj = 1; jj <= ss; jj++) { for (rr = 1; rr <= neff; rr++) { if (uu2[rr, jj] <= 0) { psiu[rr, jj] = tau[jj] - 1 } else { psiu[rr, jj] = tau[jj] } } } sigmma = psiu' * psiu / neff // Distribution matrix real scalar dim1 dim1 = 1 + k0*qqq + k0 distmt = J(ss*dim1, ss*dim1, 0) for (ii = 1; ii <= ss; ii++) { for (jj = 1; jj <= ss; jj++) { distmt[(ii-1)*dim1+1..ii*dim1, (jj-1)*dim1+1..jj*dim1] = neff * fh[ii]^(-1) * fh[jj]^(-1) * sigmma[ii,jj] * luinv(dg) * luinv(QQQ) * luinv(dg) } } // Extract distmt blocks for theta covariance distmt1 = J(ss*qqq*k0, ss*qqq*k0, 0) distmt2 = J(ss*qqq*k0, ss*qqq*k0, 0) distmt3 = J(ss*qqq*k0, ss*qqq*k0, 0) for (ii = 1; ii <= ss; ii++) { for (jj = 1; jj <= ss; jj++) { // distmt1 - upper left block distmt1[(ii-1)*qqq*k0+1..(ii-1)*qqq*k0+k0*qqq, (jj-1)*qqq*k0+1..(jj-1)*qqq*k0+k0*qqq] = distmt[2+(ii-1)*dim1..qqq*k0+1+(ii-1)*dim1, 2+(jj-1)*dim1..qqq*k0+1+(jj-1)*dim1] // distmt3 - lower right block contribution real matrix A00, A01, A02 A00 = distmt[qqq*k0+2+(ii-1)*dim1..1+qqq*k0+k0+(ii-1)*dim1, qqq*k0+2+(jj-1)*dim1..1+qqq*k0+k0+(jj-1)*dim1] A01 = J(k0*(qqq-1), k0*(qqq-1), 0) A02 = J(k0, k0*(qqq-1), 0) distmt3[(ii-1)*qqq*k0+1..(ii-1)*qqq*k0+k0*qqq, (jj-1)*qqq*k0+1..(jj-1)*qqq*k0+k0*qqq] = (A00, A02 \ A02', A01) // distmt2 - cross block real matrix B01, B02, B03 B01 = J(k0*(qqq-1), k0*(qqq-1), 0) if (qqq > 1) { B02 = distmt[k0+2+(ii-1)*dim1..qqq*k0+1+(ii-1)*dim1, qqq*k0+2+(jj-1)*dim1..1+qqq*k0+k0+(jj-1)*dim1] } else { B02 = J(0, k0, 0) } B03 = distmt[2+(ii-1)*dim1..k0+1+(ii-1)*dim1, qqq*k0+2+(jj-1)*dim1..qqq*k0+1+k0+(jj-1)*dim1] if (qqq > 1) { distmt2[(ii-1)*qqq*k0+1..(ii-1)*qqq*k0+k0*qqq, (jj-1)*qqq*k0+1..(jj-1)*qqq*k0+k0*qqq] = (B03, B02' \ B02, B01) } else { distmt2[(ii-1)*qqq*k0+1..(ii-1)*qqq*k0+k0*qqq, (jj-1)*qqq*k0+1..(jj-1)*qqq*k0+k0*qqq] = B03 } } } distthett = distmt1 + distmt3 + 2*distmt2 // Theta parameters thett1 = J(k0*(qqq+1), ss, 0) for (jj = 1; jj <= ss; jj++) { for (ii = 1; ii <= k0*(qqq+1); ii++) { thett1[ii, jj] = bt[1+ii, jj] } } thett2 = J(k0*qqq*ss, 1, 0) for (jj = 1; jj <= ss; jj++) { thett2[k0*qqq*(jj-1)+1..k0*qqq*jj] = thett1[1..k0*qqq, jj] } thett3 = thett1[k0*qqq+1..k0*qqq+k0, 1..ss] thett4 = J(k0*(qqq-1), ss, 0) thett34 = thett3 \ thett4 thett345 = J(k0*qqq*ss, 1, 0) for (ii = 1; ii <= ss; ii++) { thett345[1+(k0*qqq)*(ii-1)..(k0*qqq)*ii] = thett34[., ii] } thett = thett2 + thett345 // Store ECM results st_matrix("_qardl_phi_ecm", bigphia) st_matrix("_qardl_phi_ecm_cov", bigpia) st_matrix("_qardl_theta", thett) st_matrix("_qardl_theta_cov", distthett) } end