*
* @ADFAutoSelect( options )  series   start  end
*
* @ADFAutoSelect computes a sequence of ADF tests for various lag
* lengths, selecting the lag length based upon a chosen criterion.
* Optionally (with PRINT), it displays a table with the test statistics
* and the lag selection criteria.
*
* Parameters:
*
*    series     series being tested for unit roots
*
*    start end  range to use in calculations (this is NOT the range
*               used in the actual regressions). By default, the defined
*               range of series.
*
* Options:
*
*   MAXLAG=maximum number of lags to consider [Schwert's 12(n/100)**.25]
*   MINLAG=minimum number of lags to consider [0]
*   DET=NONE/[CONSTANT]/TREND  deterministic components
*   CRIT=[AIC]/BIC/HQ/MAIC/MBIC  criterion to use in selecting lag length
*   YD=(input) GLS detrended series [not used]
*
*   PRINT/[NOPRINT]  Prints a table for the various criteria
*   TITLE=title of report ["Information Criteria for ADF Lag Lengths"]
*
* Variables Defined:
*   %%LAGS  = chosen number of lags
*   %%AUTOP = chosen number of lags (also)
*   %CDSTAT = ADF test statistic at the chosen lag
*
* Revision Schedule
* 07/2004 Written by Tom Doan, Estima. Based loosely on Norman Morin's
*         SELECTUNI procedure.
* 08/2008 Added MINLAG option, add ADF column to output, define %CDSTAT
*         as the ADF statistic at the chosen number of lags, use CMOM
*         on LINREG.
* 09/2009 Fix MAIC calculation to extract deterministic components from
*         the sum of squared lags.
* 09/2010 Change to LOCAL REPORT
* 07/2012 Add TITLE option. Define %%AUTOP as well as %%LAGS
* 05/2019 Add RANGE option
* 05/2021 Add MBIC option
*
procedure ADFAutoSelect series start end
type series  series
type integer start end
*
option integer maxlag
option integer minlag   0
option choice  det      2  none  constant trend
option choice  crit     1  aic bic hq maic mbic
option series  yd
option switch  print    0
option string  title
option choice  range    1  data estimation
*
declare integer %%lags %%autop
*
local integer nobs
local series  trend delseries ylag
local real    sigsq aic bic hq maic adf maicss
local real    test besttest bestadf
local integer startl endl lags lag
local rect    topcorner
local report  areport
local string  ltitle
*
if .not.%defined(series) {
   disp "Syntax: @ADFAutoSelect(options)  SERIES start end"
   return
}
*
inquire(series=series) startl<<start endl<<end
compute  nobs = endl-startl+1
if .not.%defined(maxlag)
   compute lags=fix(12*(.01*nobs)^.25)
else
   compute lags=maxlag
*
if range==2.and.%defined(start)
   compute startl = start-lags

set delseries startl endl = series-series{1}
*
if %defined(yd)
   set ylag startl endl = yd{1}
else
   set ylag startl endl = series{1}

set trend startl endl = t
cmom startl+lags+1 endl
# series ylag constant trend delseries{0 to lags}
*
* Get SSR from ylag on deterministic components for MAIC and MBIC
*
compute topcorner=%xsubmat(%cmom,2,1+det,2,1+det)
if det>1
   compute topcorner=%sweeplist(topcorner,%seq(2,det))
compute maicss=topcorner(1,1)
*
if %defined(title)
   compute ltitle=title
else
   compute ltitle="Information Criteria for ADF Lag Lengths, Series "+%l(series)

report(use=areport,action=define,title=ltitle)
report(use=areport,atrow=1,atcol=1,span) ltitle
report(use=areport,atrow=2,atcol=1,align=center) "Lags" "AIC" "BIC" "HQ" "MAIC" "MBIC" "ADF"
report(use=areport,action=format,atcol=2,tocol=6,width=10)

do lag=minlag,lags
   if lag==0 {
      linreg(noprint,cmom,entries=det) delseries
      # ylag constant trend
   }
   else {
      linreg(noprint,cmom,entries=6+det) delseries
      # ylag delseries{1 to lag} constant trend
   }
   compute adf   = %tstats(1)
   compute sigsq = %rss/%nobs
   compute aic   = log(sigsq)+2.0*%nreg/%nobs
   compute bic   = log(sigsq)+log(%nobs)*%nreg/%nobs
   compute hq    = log(sigsq)+2.0*log(log(%nobs))*%nreg/%nobs
   compute maic  = log(sigsq)+2.0*(lag+%beta(1)^2*maicss/sigsq)/%nobs
   compute mbic  = log(sigsq)+log(%nobs)*(lag+%beta(1)^2*maicss/sigsq)/%nobs
   report(use=areport,atrow=lag+3,atcol=1,align=decimal) lag aic bic hq maic mbic adf
   if crit==1
      compute test=aic
   else
   if crit==2
      compute test=bic
   else
   if crit==3
      compute test=hq
   else
   if crit==4
      compute test=maic
   else
   if crit==5
      compute test=mbic
   if lag==minlag.or.test<besttest
      compute besttest=test,bestadf=adf,%%lags=lag
end do lag
*
compute %cdstat=bestadf
compute %%autop=%%lags
*
* Tag the minimum criterion in each column of the output
*
report(use=areport,action=format,tag=minimum,special=onestar,align=decimal,atrow=3,atcol=2,tocol=2)
report(use=areport,action=format,tag=minimum,special=onestar,align=decimal,atrow=3,atcol=3,tocol=3)
report(use=areport,action=format,tag=minimum,special=onestar,align=decimal,atrow=3,atcol=4,tocol=4)
report(use=areport,action=format,tag=minimum,special=onestar,align=decimal,atrow=3,atcol=5,tocol=5)
report(use=areport,action=format,tag=minimum,special=onestar,align=decimal,atrow=3,atcol=6,tocol=6)
report(use=areport,action=format,atcol=2,tocol=6,picture="###.###")

if print
   report(use=areport,action=show)
end
