*
* @NBERCycles(options) start end
* Generates dummy variables for quarterly, monthly, weekly or daily data
* based upon the NBER business cycle reference dates.
*
* Parameters:
*  start end    Range over which to define dummies [full data range]
*
* Options:
*  PEAKS=0-1 dummy which is 1 for cycle peaks
*  TROUGHS=0-1 dummy which is 1 for cycle troughs
*  UP=0-1 dummy which is 1 from trough date + 1 until next peak date
*  DOWN=0-1 dummy which is 1 from peak date + 1 until next trough date
*
* Revision Schedule:
*  05/2009 Written by Tom Doan, Estima
*  02/2010 Revised to allow for daily/weekly data
*  09/2010 Added June 2009 trough
*  09/2020 Added Feb 2020 peak
*  05/2021 Changed to do separate year for quarterly.
*  09/2022 Added April 2020 trough
*
* Source:
* National Bureau of Economic Research, Inc.
* 1050 Massachusetts Avenue
* Cambridge MA 02138
* USA
* www.nber.org/cycles.html
*
* Example:
*
* cal(m) 1950
* all 2024:12
* @NBERCycles(peaks=peaks,troughs=troughs,up=ups,down=downs)
* graph(style=spike) 2
* # peaks
* # troughs
* graph 2
* # ups
* # downs
*
procedure NBERCycles start end
option series *peaks
option series *troughs
option series *up
option series *down
*
* These are month, year and quarter for the reference dates
*
fixed rect[int] NBERpeaks(34,4)
 6 ,1857 ,2, 1857
10	,1860	,3, 1860
 4	,1865	,1, 1865
 6	,1869	,2, 1869
10	,1873	,3, 1873

 3	,1882	,1, 1882
 3	,1887	,2, 1887
 7	,1890	,3, 1890
 1	,1893	,1, 1893
12	,1895	,4, 1895

 6	,1899	,3, 1899
 9	,1902	,4, 1902
 5	,1907	,2, 1907
 1	,1910	,1, 1910
 1	,1913	,1, 1913

 8	,1918	,3, 1918
 1	,1920	,1, 1920
 5	,1923	,2, 1923
10	,1926	,3, 1926
 8	,1929	,3, 1929

 5	,1937	,2, 1937
 2	,1945	,1, 1945
11	,1948	,4, 1948
 7	,1953	,2, 1953
 8	,1957	,3, 1957

 4	,1960	,2, 1960
12	,1969	,4, 1969
11	,1973	,4, 1973
 1	,1980	,1, 1980
 7	,1981	,3, 1981

 7	,1990	,3, 1990
 3	,2001	,1, 2001
12	,2007	,4, 2007
 2, 2020 ,4, 2019

fixed rect[int] NBERTroughs(35,4)
12	,1854	,4, 1854

12	,1858	,4, 1858
 6	,1861	,3, 1861
12	,1867	,1, 1867
12	,1870	,4, 1870
 3	,1879	,1, 1879

 5	,1885	,2, 1885
 4	,1888	,1, 1888
 5	,1891	,2, 1891
 6	,1894	,2, 1894
 6	,1897	,2, 1897

12	,1900	,4, 1900
 8	,1904	,3, 1904
 6	,1908	,2, 1908
 1	,1912	,4, 1912
12	,1914	,4, 1914

 3	,1919	,1, 1919
 7	,1921	,3, 1921
 7	,1924	,3, 1924
11	,1927	,4, 1927
 3	,1933	,1, 1933

 6	,1938 ,2, 1938
10	,1945 ,4, 1945
10	,1949 ,4, 1949
 5	,1954 ,2, 1954
 4	,1958 ,2, 1958

 2	,1961 ,1, 1961
11	,1970 ,4, 1970
 3	,1975 ,1, 1975
 7	,1980 ,3, 1980
11	,1982 ,4, 1982

 3	,1991 ,1, 1991
11	,2001 ,4, 2001
 6 ,2009 ,2, 2009
 4, 2020 ,2, 2020
*
local integer twodigits
local integer pslot lower upper
*
if 2:1-1:1==4
   compute pslot=3
else
   compute pslot=1
compute twodigits=(2:1-1:1<=12)
*
* Set dummy for peaks
*
if %defined(peaks) {
   set peaks start end = 0.0
   do i=1,%rows(NBERPeaks)
      if twodigits
         set peaks start end = peaks(t).or.t==NBERPeaks(i,pslot+1):NBERPeaks(i,pslot)
      else
         set peaks start end = peaks(t).or.t==NBERPeaks(i,2):NBERPeaks(i,1):1
   end do i
}
*
* Set dummy for troughs
*
if %defined(troughs) {
   set troughs start end = 0.0
   do i=1,%rows(NBERTroughs)
      if twodigits
         set troughs start end = troughs(t).or.t==NBERTroughs(i,pslot+1):NBERTroughs(i,pslot)
      else
         set troughs start end = troughs(t).or.t==NBERTroughs(i,2):(NBERTroughs(i,1)+1):1-1
   end do i
}
*
* Set dummy for up-cycles. Note that the logic here (and for the down
* cycles) uses the fact that the first trough is before the first peak
* in the dates.
*
if %defined(up) {
   set up start end = 0.0
   do i=1,%rows(NBERPeaks)
      if twodigits {
         compute lower=NBERTroughs(i,pslot+1):NBERTroughs(i,pslot)
         compute upper=NBERPeaks(i,pslot+1):NBERPeaks(i,pslot)
      }
      else {
         compute lower=NBERTroughs(i,2):NBERTroughs(i,1):1
         compute upper=NBERPeaks(i,2):(NBERPeaks(i,1)+1):1-1
      }
      set up start end = up(t).or.(t>lower.and.t<=upper)
   end do i
   *
   * If there is an extra trough, fill out an open-ended range
   *
   if %rows(NBERTroughs)>%rows(NBERPeaks) {
      if twodigits
         compute lower=NBERTroughs(i+1,pslot+1):NBERTroughs(i+1,pslot)
      else
         compute lower=NBERTroughs(i+1,2):NBERTroughs(i+1,1):1
      set up start end = up(t).or.(t>lower)
   }
}
*
* Set dummy for down cycles
*
if %defined(down) {
   set down start end = 0.0
   do i=2,%rows(NBERTroughs)
      if twodigits {
         compute lower=NBERPeaks(i-1,pslot+1):NBERPeaks(i-1,pslot)
         compute upper=NBERTroughs(i,pslot+1):NBERTroughs(i,pslot)
      }
      else {
         compute lower=NBERPeaks(i-1,2):NBERPeaks(i-1,1):1
         compute upper=NBERTroughs(i,2):(NBERTroughs(i,1)+1):1-1
      }
      set down start end = down(t).or.(t>lower.and.t<=upper)
   end do i
   *
   * If there is an extra peak, fill out an open-ended range
   *
   if %rows(NBERPeaks)>=%rows(NBERTroughs) {
      if twodigits
         compute lower=NBERPeaks(i,pslot+1):NBERPeaks(i,pslot)
      else
         compute lower=NBERPeaks(i,2):NBERPeaks(i,1):1
      set down start end = down(t).or.(t>lower)
   }
}
end
