*! ghansen 1.02 29sep2013 * 02sep2011 Fix bug causing crash in Stata 9 and 10, optimize forvalues code * 29sep2013 Fix bug caused by minindex returning a matrix instead of a scalar when ic were positive program define ghansen, rclass byable(recall, noheader) version 9.2 syntax varlist(ts) [if] [in], break(string) lagmethod(string) [maxlags(numlist min=1 max=1 >0 integer) trim(real 0.15) level(real 0.95)] * Mark the sample to use marksample touse * Verify that data have been tsset _ts timevar panelvar if `touse', sort onepanel * Exclude observations if time variable is missing markout `touse' `timevar' * Check for gaps tsreport if `touse', report * Error message is sample contains gaps if r(N_gaps) { di as error "sample may not contain gaps". exit 198 } gettoken lhs rhs : varlist local m: word count `rhs' if `m'>4 { di as error "more than 4 right hand side variables not supported" exit 198 } tempvar count qui gen `count'= sum(`touse') local nobs= `count'[_N] if `trim' ~= . { if `trim' > =0 & `trim' < 0.25 { local fraction = `trim' } else { di as err "Trim must be a positive real number greater than 0 and less than 0.25" exit 198 } } if ("`break'"!="" & "`break'"!="level" & "`break'"!="trend" & "`break'"!="regime" & "`break'"!="regimetrend") { di as err "break must be level, trend, regime or regimetrend" exit 198 } if ("`lagmethod'"!="" & "`lagmethod'"!="aic" & "`lagmethod'"!="bic" & "`lagmethod'"!="downt" & "`lagmethod'"!="fixed") { di as err "lagmethod must be fixed, aic, bic or downt " exit 198 } if ("`lagmethod'"!="fixed" & "`maxlags'"=="" ) { local maxlags=int(`nobs'^0.25) } if ("`lagmethod'"=="fixed" & "`maxlags'"=="" ) { di as err "maxlags is required if lagmethod is fixed" exit 198 } qui tsset local rts="`r(tsfmt)'" local brtype="`break'" mata: main("`lhs'","`rhs'","`brtype'","`lagmethod'",`maxlags',"`touse'",`trim',`level') local tstat=tstat local breakptadf=breakptadf local badfdate = string(`timevar'[`breakptadf'],"`rts'") local lag=lag local za=za local breakptza=breakptza local bzadate = string(`timevar'[`breakptza'],"`rts'") local zt=zt local breakptzt=breakptzt local bztdate = string(`timevar'[`breakptzt'],"`rts'") local obs=obs noi di as text _n "Gregory-Hansen Test for Cointegration with Regime Shifts" if "`break'"=="level" local mm="Change in Level" if "`break'"=="trend" local mm="Change in Level and Trend" if "`break'"=="regime" local mm="Change in Regime" if "`break'"=="regimetrend" local mm="Change in Regime and Trend" noi di as text "Model: `mm'" _col(52) "Number of obs = " as result %9.0g `obs' if "`lagmethod'"=="aic" local cc="Akaike criterion" if "`lagmethod'"=="bic" local cc="Bayesian criterion" if "`lagmethod'"=="downt" local cc="downward t-statistics" if "`lagmethod'"=="fixed" local cc="user" noi di as text "Lags = " as result `lag' as text " chosen by `cc'" _col(52) "Maximum Lags = " as result %9.0g `maxlags' crit `break' `m' noi di as text _n _col(15) "Test" _col(26) "Breakpoint" _col(39) "Date" _col(51) "Asymptotic Critical Values" noi di as text _col(13) "Statistic" _col(50) "1%" _col(63) "5%" _col(75) "10%" di as text in smcl "{hline 78}" di as text _col(4) "ADF" as result _col(9) %10.2f `tstat' _col(29) %10.0f "`breakptadf'" _col(38) "`badfdate'" _col(43) %10.2f `r(a1)' _col(56) %10.2f `r(a2)' _col(68) %10.2f `r(a3)' di as text _col(4) "Zt" as result _col(9) %10.2f `zt' _col(29) %10.0f "`breakptza'" _col(38) "`bzadate'" _col(43) %10.2f `r(a1)' _col(56) %10.2f `r(a2)' _col(68) %10.2f `r(a3)' di as text _col(4) "Za" as result _col(9) %10.2f `za' _col(29) %10.0f "`breakptza'" _col(38) "`bzadate'" _col(43) %10.2f `r(z1)' _col(56) %10.2f `r(z2)' _col(68) %10.2f `r(z3)' di in gr in smcl "{hline 78}" return scalar tstat=tstat return scalar lag=lag return scalar breakptadf=breakptadf return scalar za=za return scalar breakptza=breakptza return scalar zt=zt return scalar breakptzt=breakptzt return local break="`break'" return local badfdate="`badfdate'" return local bzadate="`bzadate'" return local bztdate="`bztdate'" end program define crit, rclass args break m mat alevel=(-5.13,-4.61,-4.34\-5.44,-4.92,-4.69\-5.77,-5.28,-5.02\-6.05,-5.56,-5.31) mat atrend=(-5.45,-4.99,-4.72\-5.80,-5.29,-5.03\-6.05,-5.57,-5.33\-6.36,-5.83,-5.59) mat aregime=(-5.47,-4.95,-4.68\-5.97,-5.50,-5.23\-6.51,-6.00,-5.75\-6.92,-6.41,-6.17) mat aregimetrend=(-6.02,-5.50,-5.24\-6.45,-5.96,-5.72\-6.89,-6.32,-6.16\-7.31,-6.84,-6.58) mat zlevel=(-50.07,-40.48,-36.19\-57.01,-46.98,-42.49\-63.64,-53.58,-48.65\-70.18,-59.40,-54.38) mat ztrend=(-57.28,-47.96,-43.22\-64.77,-53.92,-48.94\-70.27,-59.76,-54.94\-76.95,-65.44,-60.12) mat zregime=(-57.17,-47.04,-41.85\-68.21,-58.33,-52.85\-80.15,-68.94,-63.42\-90.35,-78.52,-75.56) mat zregimetrend=(-69.37,-58.58,-53.31\-79.65,-68.43,-63.10\-90.84,-78.87,-72.75\-100.69,-88.47,-82.30) forv i=1(1)3 { return local a`i' = a`break'[`m',`i'] return local z`i' = z`break'[`m',`i'] } end mata void main(string scalar Y, string scalar X, string scalar brtype, string scalar lagmethod, real scalar k, string scalar touse, real scalar trim, real scalar level) { real scalar n, begin, final, lag, za, zt, breakptza, breakptzt real matrix y,x, temp1, temp2, temp3, temp4, dummy, x1, lags, breakptzas, breakptzts y=st_data(.,Y,touse) x=st_data(.,tokens(X),touse) n=rows(y) /* these are the default trimming values, could allow the user to change them */ begin=round(trim*n) final=round((1-trim)*n) temp1=J(final-begin+1,1,0) temp2=temp1 temp3=temp1 temp4=temp1 for (i=begin; i<=final; i++) { /* adjust regressors for different models */ dummy=(J(i,1,0)\J(n-i,1,1)) if (brtype=="trend") x1=(J(n,1,1),dummy,range(1,n,1),x) if (brtype=="regime") x1=(J(n,1,1),dummy,x,dummy*J(1,cols(x),1):*x) if (brtype=="level") x1=(J(n,1,1),dummy,x) if (brtype=="regimetrend") x1=(J(n,1,1),dummy,range(1,n,1),range(1,n,1):*dummy,x,dummy*J(1,cols(x),1):*x) /* compute ADF for each i */ adf(y,x1,k,lagmethod,tstat=.,lag=.,b=.,level) temp1[i-begin+1]=tstat temp2[i-begin+1]=lag /* compute Za or Zt for each i */ phillips(y,x1,za=.,zt=.) temp3[i-begin+1]=za temp4[i-begin+1]=zt st_numscalar("tstat",min(temp1)) minindex(temp1,1,lags,w=.) lag=lags[1] st_numscalar("breakptadf",(lag+begin-1)) st_numscalar("lag",temp2[lag]) st_numscalar("za",min(temp3)) minindex(temp3,1,breakptzas,w=.) breakptza=breakptzas[1] st_numscalar("breakptza",(breakptza+begin-1)) st_numscalar("zt",min(temp4)) minindex(temp4,1,breakptzts,w=.) breakptzt=breakptzts[1] st_numscalar("breakptzt",(breakptzt+begin-1)) st_numscalar("obs",n) } } function adf(real matrix y, real matrix x, real scalar kmax, string scalar lagmethod, real scalar tstat, real scalar lag, real matrix b, real scalar level) { real scalar n, ic, k, n1, j, aic, bic, w real matrix de, yde, xe, e1,temp1,temp2, lags n=rows(y) estimate(y,x,b=.,e=.,sig2=.,se=.,df=.) de=e[2..n]-e[1..n-1] ic=0 k=kmax temp1=J(kmax+1,1,0) temp2=J(kmax+1,1,0) while (k>=0) { yde=de[1+k..n-1] n1=rows(yde) xe=e[k+1..n-1] j=1 while (j<=k) { xe=(xe,de[k+1-j..n-1-j]) j=j+1 } estimate(yde,xe,b=.,e1=.,sig2=.,se=.,df=.) if (lagmethod=="fixed") { temp1[k+1]=-1000 temp2[k+1]=b[1]/se[1] break } if (lagmethod=="aic") { aic=log((e1'*e1)/n1)+2*(k+2)/n1 ic=aic } if (lagmethod=="bic") { bic=log((e1'*e1)/n1)+(k+2)*log(n1)/n1 ic=bic } if (lagmethod=="downt") { if (ttail(df,abs(b[k+1]/se[k+1]))<((1-level)/2) | k==0 ) { temp1[k+1]=-1000 temp2[k+1]=b[1]/se[1] break } } temp1[k+1]=ic temp2[k+1]=b[1]/se[1] k=k-1 } minindex(temp1,1,lags,w=.) lag=lags[1] tstat=temp2[lag] lag=lag-1 } function phillips(real matrix y, real matrix x, real scalar za, real scalar zt) { real scalar n,nu,su,be,bu,a2,bw,m,j,lambda,c,w,gamma,p,sigma2,s real matrix b,e,ue,uu n=rows(y) b=qrsolve(x,y) e=y-x*b be=qrsolve(e[1..n-1],e[2..n]) ue=e[2..n]-e[1..n-1]*be nu=rows(ue) bu=qrsolve(ue[1..nu-1],ue[2..nu]) uu=ue[2..nu]-ue[1..nu-1]*bu su=mean(uu:^2) a2=(4*bu^2*su/(1-bu)^8)/(su/(1-bu)^4) bw=1.3221*((a2*nu)^0.2) m=bw j=1 lambda=0 while (j<=m) { gamma=(ue[1..nu-j]'*ue[j+1..nu])/nu c=j/m w=(75/(6*pi()*c)^2)*(sin(1.2*pi()*c)/(1.2*pi()*c)-cos(1.2*pi()*c)) lambda=lambda+w*gamma j=j+1 } p=sum(e[1..n-1]:*e[2..n]:-lambda)/sum(e[1..n-1]:^2) za=n*(p-1) sigma2=(2*lambda+ue'*ue)/nu s=sigma2/(e[1..n-1]'*e[1..n-1]) zt=(p-1)/sqrt(s) } function estimate(real matrix y, real matrix x, real matrix b, real matrix e, real matrix sig2, real matrix se, real scalar df) { real matrix m m=cholinv(x'*x) b=m*x'*y e=y-x*b sig2=(e'*e):/(rows(y)-cols(x)) se=sqrt(diagonal(m):*sig2) df=rows(y)-cols(x) } end