Beispiel #1
0
   //      LookUp Today, int da, WAHDD wahdd)
   /// <summary>
   /// Load up the Factor matrix.
   /// Factor(i,j,k) is i=0,3 for ActHDD, MAHDD, LagSprd, & actual stock;
   ///   j=1,3 for currrent, forecast, and last Fri.;
   ///   k=1,2 for Now & Then.
   /// </summary>
   /// <param name="MinYear"></param>
   /// <param name="Factor"></param>
   /// <param name="Var"></param>
   /// <param name="Today"></param>
   /// <param name="da"></param>
   public void Matrices(int MinYear, double[, ,] Factor, VarClass[, ,] Var,
 LookUp Today, WAHDD wahdd, StreamWriter log)
   {
       //
         //  Load up the Factor matrix.
         //
         //  Before advancing the date, record the factors for the current Fri.
         //  Factor[i,j,k) is i=0,3 for ActHDD, MAHDD, LagSprd, & actual stock;
         //                   j=1,3 for currrent, forecast, and last Fri.;
         //                   k=1,2 for Now & Then.
         //
         //      Factor[1, 1, 1] = wahdd.DevForStocks(Today.Year, Today.Mon, Today.Day, Var, da);
         Factor[1, 1, 1] = wahdd.DevForStocks(Today.Year, Today.Mon, Today.Day, Var, log);
         ActStkCurWeek = Var[Today.Year, Today.Mon, Today.Day].ActStk;
         Factor[3, 1, 1] = ActStkCurWeek;
         //
         //  Do not Lag spread in this app. as is done in forecasting.
         //
         LookUp Temp = new LookUp();
         Temp.Year = Today.Year;
         Temp.Mon = Today.Mon;
         Temp.Day = Today.Day;
         Factor[2, 1, 1] = Var[Temp.Year, Temp.Mon, Temp.Day].Spread;
         //
         //  Drop back a day.
         //
         Temp.DateShift(Temp.Year, Temp.Mon, Temp.Day, -1);
         Factor[0, 1, 1] = Var[Temp.Year, Temp.Mon, Temp.Day].ActHDD;
         //
         //  Get this year's current & forecast stocks back to the 5th week being
         //  careful to check for missing values as we back up over early Oct.
         //
         Temp.DateShift(Temp.Year, Temp.Mon, Temp.Day, -6);
         Factor[3, 3, 1] = Var[Temp.Year, Temp.Mon, Temp.Day].ActStk;      //Last week's stocks
         //
         Temp.DateShift(Temp.Year, Temp.Mon, Temp.Day, -1);
         //
         //  Move ahead 1 week to the forecast date, which also steps ahead to the
         //  next current date.
         //  11-16:  Do not lag spread.
         //
         Today.DateShift(Today.Year, Today.Mon, Today.Day, 6);
         Factor[0, 2, 1] = Var[Today.Year, Today.Mon, Today.Day].ActHDD;
         Today.DateShift(Today.Year, Today.Mon, Today.Day, 1);           // 1 week ahead
         Factor[2, 2, 1] = Var[Today.Year, Today.Mon, Today.Day].Spread;
         ActStkNextWeek = Var[Today.Year, Today.Mon, Today.Day].ActStk;
         //
       //      Factor[1, 2, 1] = wahdd.DevForStocks(Today.Year, Today.Mon, Today.Day, Var, da);
         Factor[1, 2, 1] = wahdd.DevForStocks(Today.Year, Today.Mon, Today.Day, Var, log);
         Factor[3, 2, 1] = ActStkNextWeek;
         //
         return;
   }
Beispiel #2
0
 //  Estimate the relationship between spread & stock deviations from normal
 //    adjusted for day of season & recent HDD deviations.  The result
 //    provides a nonlinear transformation of spread that is used in other
 //    regressions (with prefix SC) to represent the nonlinear relationship
 //    between spread & stocks.  Run annually.
 //  By Asa Janney, autumn 2009
 //  V4:  Functions the same as V3 but all the irrelevant code carried over
 //    from the parent program has been deleted.
 // 12-4-13:  Replaced input files with updated data.
 // 8-26-14:  Started coding C#.
 // 8-29-14:  Finished draft coding; program runs; start debugging.
 // V5:  Edits to fit into the system.
 // V6, 12-19-14:  Edits to output file writes to match existing file.
 // V7, 12-21-15:  Added season dummies to SAS file & removed HDD as ind. var. because
 //   it is always insig. now.  It is retained w/ a zero in the coef file to remind
 //   that it is not in service but could be brought back.
 //   Added code to weight Spread cats & season dummies by freq.
 // V8, 5-13-16:  Edits to analyze only the last 6 seasons.
 //
 static void Main(string[] args)
 {
     Console.WriteLine();
       int d, DiS, Y5, M5, D5, Y12, M12, D12, RunDoW, DiSda, Season, Mon, FirstDay,
     Year, Day, i, j, k, m, n, NSeasons = 0, NFri = 0, ID = 0;
       int NObs;
       NObs = 0;
       int[] CountByGroup = new int[9];    // CountByGroup[0:8)
       int[] CountBySeason = new int[2020];   // 12-22-15
       int GetMon, GetDay, GetYr;
       string FileName, input;
       string Bell = new string((char)7, 1);
       //
       //  Weights for the moving-average HDD.  Originally estimated in
       //  HDDAdjustedStocks3.xlsx on ForwardSpread2/SSModels.  Signs are reversed
       //  from the original to get positive weights.
       //
       WAHDD wahdd = new WAHDD();
       double[] MAHDDStkCoef = new double[4] {0,
     0.04926,       //Intercept
     0.03000,       //Linear term
     -0.002493};    //Quadratic term
       int MAHDDLagLength = 13;
       double[] MAHDDStkWght = new double[21];         // 0:20
       double TotMAW = 0, DepVarMean = 0;
       //
       // Compute the weights & transfer the coefs to the wahdd object.
       //
       for (i = 0; i <= MAHDDLagLength; i++)
       {
     MAHDDStkWght[i] = MAHDDStkCoef[1] + MAHDDStkCoef[2] * i + MAHDDStkCoef[3] * i * i;
     if (MAHDDStkWght[i] <= 0) Warning.Message("Negative MA HDD weight.", "Terminate", 1);
     TotMAW = TotMAW + MAHDDStkWght[i];        // Used to normalize weigths.
     wahdd.MAHDDStkWght[i] = MAHDDStkWght[i];
       }
       //double LastStk, LastActStk, NextActStk;
       double Intercept;
       double[] HoldHDD = new double[21];      // HoldHDD(0:20)
       double[] MeanSprdByGroup = new double[9];   // MeanSprdByGroup[0:8)
       //bool FirstDA;
       int EndDataYear = 2020;   // Later, make this into an input.
       //
       // VarClass holds all the essential daily data indexed by year, month, & day.
       // It is used like a Fortran structure.  In this application it works better
       // as an object than as a struct.  Note that here & elsewhere the array size
       // is set one larger in every dimension because the program rarely uses the
       // first (zero) element.
       //
       VarClass[, ,] Var = new VarClass[EndDataYear + 1, 13, 32];
       //
       //  Fill with missing value indicator before reading in data so that every
       //  cell that we don"t read in will show as missing.
       //
       for (Year = 1987; Year <= EndDataYear; Year++)                      //Changed to EndDataYear
       {
     for (Mon = 1; Mon <= 12; Mon++)
     {
       for (Day = 1; Day <= 31; Day++)
       {
     // Each element of Var has to have this:
     //
     Var[Year, Mon, Day] = new VarClass();
     Var[Year, Mon, Day].DaysInto = -9999;
     Var[Year, Mon, Day].Spread = -9999;
     Var[Year, Mon, Day].ActStk = -9999;
     Var[Year, Mon, Day].NormStk = -9999;
     Var[Year, Mon, Day].RelStkDev = -9999;
     Var[Year, Mon, Day].ActHDD = -9999;
     Var[Year, Mon, Day].HDDDev = -9999;
     for (i = 1; i <= 7; i++)
     {
       Var[Year, Mon, Day].HDDForeAct[i] = -9999;
       Var[Year, Mon, Day].HDDForeDev[i] = -9999;
     }
       }  // End Day
     }  // End Mon
       }  // End Year
       //
       int[] DaysInMon = new int[13] { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
       int[] MoS = new int[7] { 0, 10, 11, 12, 1, 2, 3 };          //Month of season
       string[] CoefLabel = new string[40] {"",
     "Intercept","Sprd Int 1","Sprd Int 2","Sprd Int 3","Sprd Int 4",
        "Sprd Int 5","Sprd Int 6","Day -20","Day -10","Day   0","Day  10","Day  20",
        "Day  30","Day  40","Day  50","Day  60","Day  70","Day  80","Day  90","Day 100",
        "Day 110","Day 120","Day 130","Day 140","Day 150","HS2009","HS2010","HS2011",
        "HS2012","HS2013","HS2014","WAHDDDev","","","","","","",""};
       //
       // X & Y matrices for stock/sprd regression
       //
       double[, ,] Factor = new double[4, 4, 3];     // Factor[0:3,3,2)
       double[,] Z = new double[1001, 40];         // Z(1000,26)
       double[] B = new double[1001];
       double[] Spread = new double[1001];    // 9-23-15 Actual spread, not just its category.
       double[,] XPrimeX = new double[40, 40];                 // (27,27)
       double[,] XPrimeXInv = new double[40, 40];           //(27,27),
       double[] Beta = new double[40];
       double[] XPrimeY = new double[40];
       //
       StreamWriter log = new
        StreamWriter(@"c:\\CSharp\\HeatingOil\\StockAdjReg15\\Log.txt");
       //FileName = @"c:\\CSharp\\HeatingOil\\StockSpreadPiecewiseLinearCoefsV5.txt";
       //
       //  Save last season's file & assign new, tentative name for 2016.
       //
       FileName = @"c:\\CSharp\\HeatingOil\\StockSpreadPiecewiseLinearCoefsV6.txt";   // 9-18-16
       StreamWriter StkSprdPLOut = new StreamWriter(FileName);
       //
       Console.WriteLine(
        "\n************************************************************\n"
        + "*  Program run annually to estimate stock adjustment as a  *\n"
        + "*    piecewise function of spread.  The regression results *\n"
        + "*    are written to StockSpreadPiecewiseLinearCoefs.txt.   *\n"
        + "*  Written by Asa Janney:  Fortran versions, autumn 2009   *\n"
        + "*  C# version, August 2014                                 *\n"
        + "************************************************************\n"
     + "\nThe file for SAS analysis produced by this program is called\n"
        + "StockAdjSASDataYY-MM-DD.txt on the StockAdjReg15 directory.\n"
        + "The original version of this program did not run the piece-\n"
        + "wise regression; SAS did that.  Now StockAdjReg15 can run the\n"
        + "regression, but SAS is still used for more extensive stats &\n"
        + "to test alternative models.");
       //
       Hesitate.ThisLong(100);
       //
       //  Get starting & ending years of data to process.
       //
       int StartSampleYear = 2050;   // Set higher than EndYear going into the next routine.
       int EndSampleYear = 2050;     // Does not have to be at the end of the data.
       bool FirstPass = true;
       while (EndSampleYear <= StartSampleYear)
       {
     if (!FirstPass)
     {
       Console.WriteLine(Bell + "  *** Invalid entry, try again.\n");
       Hesitate.ThisLong(100);
     }
     FirstPass = false;
     Console.WriteLine(
     "\nEnter start sample year (2009 or later) & ending sample year\n"
     + "(eg, 2010 2015).  Remember that seasons are designated by"
     + "the years they start in.  The program will use only the last 6\n"
     + "seasons in the regression.");
     input = Console.ReadLine();
     Hesitate.ThisLong(800);
     StartSampleYear = Convert.ToInt32(input.Substring(0, 4));
     EndSampleYear = Convert.ToInt32(input.Substring(5, 4));
     //EndDataYear = Convert.ToInt32(input.Substring(10, 4));   // Made this fix above.
     if (StartSampleYear <= 0)
     {
       StartSampleYear = 2009;
       if (EndSampleYear - StartSampleYear > 5)
     StartSampleYear = EndSampleYear - 5;
       Console.WriteLine("Starting year reset to " + StartSampleYear);
       Hesitate.ThisLong(100);
     }
       }  // End while
       int NVar = 26 + EndSampleYear - StartSampleYear + 1;   // Counting-year dummies.
       //
       DateTime TimeNow = DateTime.Now;
       log.WriteLine("Run time:  " + TimeNow);  // Put run time on log file.
       GetYr = TimeNow.Year;
       GetMon = TimeNow.Month;
       GetDay = TimeNow.Day;
       LookUp Today = new LookUp();
       if (EndSampleYear > GetYr - 1)
       {
     EndSampleYear = GetYr - 1;       //Highest number possible
     Console.WriteLine("Ending year reset to " + EndSampleYear);
     Hesitate.ThisLong(1200);
       }
       //
       //  File for regression results
       //
       StreamWriter regResults = new
     StreamWriter(@"c:\\CSharp\\HeatingOil\\StockAdjReg15\\RegressionResults.txt");
       //
       //*************************************************************************
       //  Open an output file to hold the data for SAS.  Use the date in the name
       //  to indentify it.
       //
       FileName = @"c:\\CSharp\\HeatingOil\\StockAdjReg15\\StockAdjSASData" + TimeNow.Year + "-"
     + TimeNow.Month + "-" + TimeNow.Day + ".txt";
       StreamWriter SASOut = new StreamWriter(FileName);
       //
       // Write heading onto SAS input file.
       //
       SASOut.WriteLine(
     "MM DD YYYY  DiS  Stocks  Spread I HDDDevFS  _Spread Category                     DiS Dummies ===>       " +
     "                                                                                    Heating-Season Dummies");
       //
       //  Read in forward spread from late 1988.
       //
       FileName = @"c:\\CSharp\\HeatingOil\\UnadjustedSprdThru2015Season.txt";  // Updated 4-11-16
       StreamReader spreadInput = new StreamReader(FileName);
       //string Dum1, Dum2;
       //double DumGDPDef;
       while (!spreadInput.EndOfStream)
       {
     input = spreadInput.ReadLine();
     Year = Convert.ToInt32(input.Substring(0, 4));
     Mon = Convert.ToInt32(input.Substring(8, 2));
     Day = Convert.ToInt32(input.Substring(12, 2));
     //
     // Check that an object for this day exists; if not, create it.
     //
     if (Var[Year, Mon, Day] == null) Var[Year, Mon, Day] = new VarClass();
     Var[Year, Mon, Day].Spread = Convert.ToDouble(input.Substring(40, 9)); // 8-24-15 Changed from 41, 8.
     //int IX = 1;
       }
       //
       //  Read in the latest HDD data.
       //
       FileName = @"c:\\CSharp\\HeatingOil\\HDDWithRevisedNormals.txt";
       StreamReader HDDIn = new StreamReader(FileName);
       FileName = @"c:\\CSharp\\HeatingOil\\MAHDDOut.txt";
       StreamWriter HDDOut = new StreamWriter(FileName);
       //
       input = HDDIn.ReadLine();                               // Skip heading.
       while (!HDDIn.EndOfStream)
       {
     input = HDDIn.ReadLine();
     Year = Convert.ToInt32(input.Substring(0, 4));
     Mon = Convert.ToInt32(input.Substring(4, 3));
     if (Year > EndDataYear + 1 || (Year > EndDataYear && Mon > 4)) break;
     Day = Convert.ToInt32(input.Substring(7, 3));
     Var[Year, Mon, Day].ActHDD = Convert.ToDouble(input.Substring(10, 8));
     Var[Year, Mon, Day].NormHDD = Convert.ToDouble(input.Substring(18, 8));
     Var[Year, Mon, Day].HDDDev = Convert.ToDouble(input.Substring(26, 8));
     Var[Year, Mon, Day].DaysInto = Convert.ToInt32(input.Substring(34, 4));
     //
     if (Year < 1987)
     {
       Console.WriteLine("Year = " + Year);
       Warning.Message("Error reading HDD input file; year < 1987",
     "Terminate", 1);
     }
     //
     Season = Year;
     int LastSeason = 0;
     if (Mon < 4) Season = Season - 1;
     if (Season > LastSeason) LastSeason = Season;
     //
     //  Slide the HDDs a day into the past & put the new one into the zero pos.
     //
     for (i = MAHDDLagLength; i >= 1; i--)
       HoldHDD[i] = HoldHDD[i - 1];
     //
     //  Find the WA HDD.
     //
     double X4 = 0;
     for (i = 0; i <= MAHDDLagLength; i++)
       X4 = X4 + HoldHDD[i] * MAHDDStkWght[i] / TotMAW;
     HDDOut.WriteLine(Year + " " + Mon + " " + Day + " " + Var[Year, Mon, Day].MAHDDDev);
       } // End while not end of stream
       //
       //  Read in actual Friday stocks & find adjusted stocks.
       //  This file has every season as wide as we can process.
       //
       FileName = @"c:\\CSharp\\HeatingOil\\StocksActualThru2015Season.txt"; // Updated 4-11-16
       StreamReader stocksIn = new StreamReader(FileName);
       while (!stocksIn.EndOfStream)
       {
     input = stocksIn.ReadLine();
     Year = Convert.ToInt32(input.Substring(0, 4));
     Mon = Convert.ToInt32(input.Substring(8, 2));
     Day = Convert.ToInt32(input.Substring(10, 6));
     Var[Year, Mon, Day].ActStk = Convert.ToDouble(input.Substring(16, 8));
     //
     //  Counts by heating season.
     //
     Season = Year;
     if (Mon < 4) Season = Season - 1;
     if (Mon >= 10 || Mon <= 3)
       CountBySeason[Season] = CountBySeason[Season] + 1;
     //
     //  Check for out of bounds.
     //
     if (Var[Year, Mon, Day].ActStk > 64.128)
     {
       string msg = " *** Stocks of " + string.Format("{0,7:###.000}", Var[Year, Mon, Day].ActStk)
     + " higher than historical max. on "
     + Year + "-" + Mon + "-" + Day;
       Warning.Message(msg, "Warning", 1);
     }
     if (Var[Year, Mon, Day].ActStk < 14.0)  // Edited
     {
       string msg = " *** Stocks of " + string.Format("{0,7:###.000}", Var[Year, Mon, Day].ActStk)
     + " lower than 14 on "
     + Year + "-" + Mon + "-" + Day; // Edited
       Warning.Message(msg, "Warning", 1);
     }
       }   // End of while
       stocksIn.Close();
       //
       //  Fill in days-into-season.
       //
       for (Year = 1988; Year <= 2015; Year++)
       {
     i = -31;
     for (n = 1; n <= 6; n++)
     {
       m = MoS[n];
       d = DaysInMon[m];
       if (m == 2 && (Year / 4) * 4 == Year) d = 29;   //leap year day
       FirstDay = 1;
       for (Day = 1; Day <= d; Day++)
       {
     if (i > 150) continue;
     Var[Year, m, Day].DaysInto = i;
     i = i + 1;
       }  // End for Day
     }  // End for n
       } // End for Year
       //
       //  Interpolated stocks are not needed in this program, so all this does now
       //  is to fill in day of the week.
       //
       //  The first day of October 1988 was a Saturday, so the day of week number, n, is
       //  set to 7 to begin.
       //
       n = 7;
       for (Year = 1988; Year <= 2019; Year++)  // 5-12-16 Changed upper bound to 2019.
       {
     for (Mon = 1; Mon <= 12; Mon++)
     {
       if (Year == 1988 && Mon < 10) continue;        //Start in Oct. 1988.
       if (Year == EndDataYear + 1 && Mon > 4) break;     //End after last season of data.
       d = DaysInMon[Mon];
       if (Mon == 2 && (Year / 4) * 4 == Year) d = 29;  //leap year day
       for (Day = 1; Day <= d; Day++)
       {
     Var[Year, Mon, Day].DoW = n;                 //Assign day of week.
     n = n + 1;                                 //Increment day of week index.
     if (n > 7) n = 1;
       }      //Days
     }        //Months
       }          //Years
       //
       //  Read in HDD projections.  All of Oct. is present for all years.
       //
       StreamReader HDDFore = new
       StreamReader(@"c:\\CSharp\\HeatingOil\\HDDAugmentedForecast.txt");  // Updated 4-11-16
       while (!HDDFore.EndOfStream)
       {
     input = HDDFore.ReadLine();
     Year = Convert.ToInt32(input.Substring(0, 4));
     Mon = Convert.ToInt32(input.Substring(4, 7));
     Day = Convert.ToInt32(input.Substring(11, 4));
     for (i = 1; i <= 7; i++)
     {
       if (Var[Year, Mon, Day] == null) Var[Year, Mon, Day] = new VarClass();
       Var[Year, Mon, Day].HDDForeAct[i] = Convert.ToDouble(input.Substring(15 + 11 * (i - 1), 11));
     }
       }
       // *******************************
       //  Find projected HDD deviations.
       //  Index values of 1 - 7 correspond to tomorrow, the next day, etc.
       //  9-9-14:  Make file of HDD deviations for debug.
       //
       FileName = @"c:\\CSharp\\HeatingOil\\StockAdjReg15\\HDDDeviations.txt";
       StreamWriter HDDDevs = new StreamWriter(FileName);
       for (Year = 2001; Year <= EndDataYear; Year++)
       {
     for (Mon = 1; Mon <= 12; Mon++)
     {
       if (Year == 2001 && Mon < 9) continue;        //Start on 30 Sept. 2001.
       if (Year == EndDataYear && Mon >= 4) break;
       int MaxDays = DaysInMon[Mon];                          //Edit 11-18-13
       if (Mon == 2 && (Year / 4) * 4 == Year) MaxDays = 29;      //leap year day
       for (Day = 1; Day <= MaxDays; Day++)                  //31  Limit to DaysInMon.
       {
     if (Year == 2001 && Mon == 9 && Day < 30) continue;        //Start on 30 Sept. 2001.
     for (j = 1; j <= 7; j++)
     {
       Today.Year = Year;
       Today.Mon = Mon;
       Today.Day = Day;
       Today.DateShift(Today.Year, Today.Mon, Today.Day, j);  //Normal is stored j days ahead.
       if (Today.Year > EndDataYear) { break; }
       if (Var[Today.Year, Today.Mon, Today.Day] == null)
       {
         //  9-9-14:  This is not happening, but w/ a 1-sec hesitation it will be
         //  apparent if it ever does.
         //
         Console.WriteLine("In HDD dev, object created for " + Today.Year + " " + Today.Mon
           + " " + Today.Day);
         Var[Today.Year, Today.Mon, Today.Day] = new VarClass();
         Hesitate.ThisLong(1000);
       }
       double XNorm = Var[Today.Year, Today.Mon, Today.Day].NormHDD;
       if (XNorm == -9999 && (Mon <= 3 || Mon >= 10))              // 9-22-15
       {
         log.WriteLine("Missing input for normal HDD at " + Year + "-" + Mon + "-" + Day
           + "-" + j);
         HDDDevs.WriteLine("Missing input for normal HDD at " + Year + "-" + Mon + "-" + Day
           + "-" + j + " XNorm = " + XNorm + " ForeAct = "
           + Var[Year, Mon, Day].HDDForeAct[j]);
       }
       //
       //  Because HDD projections are stored by the day they are made rather
       //  than the day they are received, you have to grab yesterday's actual, and
       //  the normal temp is one day off from the day-zero projection.
       //
       if (Var[Year, Mon, Day].HDDForeAct[j] == -9999 && (Mon <= 3 || Mon >= 10))  // 9-22-15
       {
         log.WriteLine("Missing input for HDD Dev at " + Year + "-" + Mon + "-" + Day + "-" + j);
         HDDDevs.WriteLine("Missing input for HDD Dev at " + Year + "-" + Mon + "-" + Day
           + "-" + j + " XNorm = " + XNorm + " ForeAct = " + Var[Year, Mon, Day].HDDForeAct[j]);
       }
       else
       {
         Var[Year, Mon, Day].HDDForeDev[j] = Var[Year, Mon, Day].HDDForeAct[j] - XNorm;  //Edit, deleted prefix L.
         HDDDevs.WriteLine(Year + "-" + Mon + "-" + Day + " " + j + " "
           + " XNorm = " + string.Format("{0,10:###0.00000}", XNorm)
           + " ForeAct = " + string.Format("{0,10:###0.00000}", Var[Year, Mon, Day].HDDForeAct[j])
           + string.Format("{0,10:###0.00000}", Var[Year, Mon, Day].HDDForeDev[j]));
       }
       if (Day == 20 && j == 1)
       {
         log.WriteLine("HDDForeDev = " + Year + " " + Mon + " " + Day + " "
          + Var[Year, Mon, Day].HDDForeDev[j]);
         //Console.ReadKey();
       } //4
     } //3
       } //2
     } //1
       } //0
       HDDFore.Close();
       //
       //  Add DaysInto for March 31 in leap years.
       //
       Var[1992, 3, 31].DaysInto = 151;
       Var[1996, 3, 31].DaysInto = 151;
       Var[2000, 3, 31].DaysInto = 151;
       Var[2004, 3, 31].DaysInto = 151;
       Var[2008, 3, 31].DaysInto = 151;
       Var[2012, 3, 31].DaysInto = 151;
       Var[2016, 3, 31].DaysInto = 151;
       //*****************************************************************
       //
       //  Top of loop by season
       //
       //for (i = StartSampleYear; i <= EndSampleYear; i++)
       for (i = 1999; i <= EndSampleYear; i++)
       {
     log.WriteLine("Season = " + i);
     Console.WriteLine("Season = " + i);
     Today.Season = i;
     Today.Year = Today.Season;
     Today.Day = 4;         //  Start on the 1st Fri. in Oct. on or after the 4th.
     Today.Mon = 10;
     //
     //  Go thru day by day until you have a Friday.
     //
     while (Var[Today.Year, Today.Mon, Today.Day].DoW != 6)
     {
       Today.Day = Today.Day + 1;
       if (Today.Day > 12)
     Warning.Message("Error finding 1st Fri. in Oct.", "Terminate", 1);
     }
     Load load = new Load();
     //****************************************************************************
     //               B E G I N   W E E K L Y   S T E P S
     //
     //  In this routine:
     //    Today.xxx indicates the run day today, which steps forward 7 days AAT.
     //  Limit is the date packed into a single interger, YYYYMMDD.
     //
     int Limit = 10000 * (Today.Season + 1) + 331;
     while (10000 * Today.Year + 100 * Today.Mon + Today.Day < Limit)
     {
       int ConcatDate = 10000 * Today.Year + 100 * Today.Mon + Today.Day;
       //
       //  Load up the Factor & X matrices.  Set the unused MinYear variable to
       //  the now year.  Note that the Today is advanced 7 days in this subr.
       //  for (not process observations w/ missing HDD.
       //
       int MinYear = Today.Year;
       load.Matrices(MinYear, Factor, Var, Today, wahdd, log);
       if (Today.Mon > 3 && Today.Mon < 10) continue;
       //
       //  Skip if current or forecast WAHDD is missing:
       //
       if (Factor[1, 1, 1] == -9999 || Factor[1, 2, 1] == -9999)
       {
     Console.WriteLine(Today.Year + "-" + Today.Mon + "-" + Today.Day + " Warning, Missing MAHDD");
     continue; //Skip missing.  9-1-14
       }
       //
       //  Factor[i,j,k] is i=0,3 for ActHDD, MAHDD, LagSprd, & actual stock;
       //                   j=1,2 for currrent & forecast Fri.;
       //                   k=1,2 for Now & Then.
       //  "Then" was a past year used in pattern matching, which has been retired.
       //
       ID = Var[Today.Year, Today.Mon, Today.Day].DaysInto;
       int[,] YrDummy = new int[20, 500];                       // Heating-season dummies
       //
       //  Move the factor matrix into the B (ind) & Z (dep) matrices for the
       //  weekly stock regression if this season is between the limits set
       //  by the user.
       //  12-16-15:  Always include 3 obs from 2000 as priors for high spreads that
       //    have not occurred since then.
       //
       if ((Today.Season >= StartSampleYear && Today.Season <= EndSampleYear)
     || (Today.Year == 2000 && Today.Mon == 1 && Today.Day == 21)
     || (Today.Year == 2000 && Today.Mon == 1 && Today.Day == 28)
     || (Today.Year == 2000 && Today.Mon == 2 && Today.Day == 4))
       {
     if (Factor[3, 2, 1] == -9999) continue;      // Missing dep. var.
     NObs = NObs + 1;
     log.WriteLine("NObs = " + NObs);
     //
     //  B holds the dep. var.
     //  Factor[3, 2, 1] is actual stocks, forecast, Now.
     //
     B[NObs] = Factor[3, 2, 1];
     //
     //  Fill in Z, the ind. var. array.
     //  12-21-15:  WAHDD is insignificant in this model, so move it to the end of the array.
     //    That way, it can be dropped from the regession in this program, but still provide
     //    the option to be written out to the SAS file, so that the SAS program can continue
     //    to check whether it is still insig. in future seasons.
     //
     //for (j = 1; j <= 25; j++)          // 25 = intercept, categories, & DiS dummies
     for (j = 1; j <= 31; j++)      // 31 = intercept, categories, DiS dummies, & seasonal dummies
       Z[NObs, j] = 0;                          // Initialize.
     Z[NObs, 1] = 1;                            //Intercept
     Z[NObs, 32] = Factor[1, 2, 1];    //wahdd.DevForStocks CN  12-21-15 is insig. so move to end.
     Spread[NObs] = Factor[2, 2, 1];
     //
     // Find the interval number for Factor[2,2,1], lagged spread, forecast, Now.
     //
     double[] Boundary = new double[6] { 1000, .5, .25, 0.10, 0.05, -0.05 };
     int cat = 0;
     //
     //  Find the category of this obs.
     //
     for (j = 1; j <= 5; j++)
     {
       if (Today.Season == 2002 && j == 1)    // Special check on this season; prob. pointless now.
       {
         log.WriteLine("2002-" + Today.Mon + " " +
           Today.Day + " " + "Spread = " + Factor[2, 2, 1]);
       }
       if (Factor[2, 2, 1] > Boundary[j])
       {
         cat = j;
         log.WriteLine(Today.Mon + " " + Today.Day + " " + "cat = " + cat);
         break;
       }
     }
     if (cat == 0) cat = 6;   // Spread was <= -0.05.
     //
     //  Spread dummies at intervals selected by examination of a
     //  plot of the data.  Accumulate totals to get mean spreads within group.
     //
     switch (cat)               // Branch according to category.
     {
       case 1:
         Z[NObs, 2] = 1;    //Sprd1 *** 12-21-15:  Here & below reducing index by 1.
         MeanSprdByGroup[2] = MeanSprdByGroup[2] + Factor[2, 2, 1];
         CountByGroup[2] = CountByGroup[2] + 1;
         break;
       //
       case 2:
         Z[NObs, 3] = 1;                             //Sprd2
         MeanSprdByGroup[3] = MeanSprdByGroup[3] + Factor[2, 2, 1];
         CountByGroup[3] = CountByGroup[3] + 1;
         break;
       //
       case 3:
         Z[NObs, 4] = 1;                             //Sprd3
         MeanSprdByGroup[4] = MeanSprdByGroup[4] + Factor[2, 2, 1];
         CountByGroup[4] = CountByGroup[4] + 1;
         break; ;
       //
       case 4:
         Z[NObs, 5] = 1;                             //Sprd4
         MeanSprdByGroup[5] = MeanSprdByGroup[5] + Factor[2, 2, 1];
         CountByGroup[5] = CountByGroup[5] + 1;
         break; ;
       //
       case 5:
         Z[NObs, 6] = 1;                             //Sprd5
         MeanSprdByGroup[6] = MeanSprdByGroup[6] + Factor[2, 2, 1];
         CountByGroup[6] = CountByGroup[6] + 1;
         break; ;
       //
       case 6:
         Z[NObs, 7] = 1;                             //Sprd6
         MeanSprdByGroup[7] = MeanSprdByGroup[7] + Factor[2, 2, 1];
         CountByGroup[7] = CountByGroup[7] + 1;
         break;
     }  // end switch
     //
     //  Accumulate a count & total for all obs & store in element 0.
     //
     CountByGroup[0] = CountByGroup[0] + 1;
     MeanSprdByGroup[0] = MeanSprdByGroup[0] + Factor[2, 2, 1];
     //
     //  Dummies for normal stocks every 10 days thru the season.
     //
     int IDays = -30;
     for (j = 8; j <= 25; j++)
     {
       IDays = IDays + 10;
       double ten = 10;
       if (Math.Abs(ID - IDays) < 10) Z[NObs, j] = 1.0 - (double)Math.Abs(ID - IDays) / ten;
     }
     //
     //  Heating-season (year) dummies
     //
     //Z[NObs, 26 + Today.Season - 2009] = 1;
     Z[NObs, 26 + Today.Season - StartSampleYear] = 1;
     //
     //  Write file to use in regression.
     //
     WriteSAS.Line(SASOut, Today, ID, B, Z, NObs, Spread, NVar);  // 9-23-15 added spread
       }   // End if; checks season.
       //
       NFri = NFri + 1;
     }   // End while
     //
     NSeasons = NSeasons + 1;
       }  // End  for i, StartSampleYear, EndYear
       //*************************************************************
       //  Get means within spread groups before adding in the priors.
       //
       for (i = 2; i <= 7; i++)
     MeanSprdByGroup[i] = MeanSprdByGroup[i] / CountByGroup[i];
       MeanSprdByGroup[0] = MeanSprdByGroup[0] / CountByGroup[0];
       //
       //  Read in smoothness priors for DiS dummies.
       //
       FileName = @"c:\\CSharp\\HeatingOil\\StockAdjReg15\\Priors.txt";
       StreamReader priors = new StreamReader(FileName);
       string Type;  // Type of constraint goes in 1st 3 cols.   Edited
       while (!priors.EndOfStream)
       {
     input = priors.ReadLine();
     NObs = NObs + 1;
     Type = input.Substring(0, 3);
     switch (Type)
     {
       case "DiS":
     for (j = 8; j <= 25; j++)
       Z[NObs, j] = Convert.ToDouble(input.Substring(3 + (j - 8) * 5, 5));
     break;
       case "Cat":
     for (j = 2; j <= 7; j++)
       Z[NObs, j] = Convert.ToDouble(input.Substring(3 + (j - 2) * 5, 5));
     break;
       default:
     Console.WriteLine("Key word " + Type);
     Console.WriteLine("Is invalid.  Hit return to stop.");
     Console.ReadKey();
     Environment.Exit(-1);
     break;
     }
     //
     // Write priors to bottom of SAS file.
     //
     WriteSAS.Line(SASOut, Today, ID, B, Z, NObs, Spread, NVar);
       }  // End while
       //
       //  Finally, add 3 constraints to make the spread cats, DiS dummies, & season
       //  dummies have zero means.
       //
       NObs = NObs + 1;
       for (j = 2; j <= 7; j++)
     Z[NObs, j] = CountByGroup[j];            // 12-22-15:  6 Spread dummies set to counts.
       //
       WriteSAS.Line(SASOut, Today, ID, B, Z, NObs, Spread, NVar);  // 9-23-15 Added Spread
       //
       NObs = NObs + 1;
       for (j = 8; j <= 25; j++)
     Z[NObs, j] = 1;                 //DiS dummies set to 1.
       WriteSAS.Line(SASOut, Today, ID, B, Z, NObs, Spread, NVar);
       //
       NObs = NObs + 1;
       for (j = 26; j <= 26 + EndSampleYear - StartSampleYear; j++)
       {
     Z[NObs, j] = CountBySeason[j - 26 + 2009];             // 12-22-15:  Heating-season dummies set to num obs.
       }
       WriteSAS.Line(SASOut, Today, ID, B, Z, NObs, Spread, NVar);
       SASOut.Close();
       //**********************************
       //  Call regression routines.
       //
       Piecewise piecewise = new Piecewise();
       piecewise.Reg(regResults, NObs, Z, Beta, NVar, DepVarMean, B, StkSprdPLOut,
     CoefLabel);
       //
       //  Add means within spread groups to the bottom of the output file.
       //
       StkSprdPLOut.WriteLine();                             // Inserted 12-19-14
       StkSprdPLOut.WriteLine("Mean Spreads within Interval");
       StkSprdPLOut.WriteLine("----------------------------");
       StkSprdPLOut.WriteLine();                             // Inserted 12-19-14
       StkSprdPLOut.WriteLine("  Interval Count      Mean");
       StkSprdPLOut.WriteLine("  -------- ----- ---------");
       for (i = 2; i <= 7; i++)
     StkSprdPLOut.WriteLine(" " + string.Format("{0,9:#########0}", i - 1)
       + string.Format("{0,6:#####0}", CountByGroup[i])
       + string.Format("{0,10:###0.00000}", MeanSprdByGroup[i]));
       //
       StkSprdPLOut.WriteLine("  -------- ----- ---------");
       StkSprdPLOut.WriteLine("     Total" + string.Format("{0,6:#####0}", CountByGroup[0])
     + string.Format("{0,10:###.00000}", MeanSprdByGroup[0]));
       //
       //  Compute the intercepts & slopes of linear pieces.
       //
       StkSprdPLOut.WriteLine();                             // Inserted 12-19-14
       StkSprdPLOut.WriteLine();
       StkSprdPLOut.WriteLine("Intercepts & slopes of linear pieces");
       StkSprdPLOut.WriteLine("------------------------------------");
       StkSprdPLOut.WriteLine("    Interval Intercept     Slope");
       StkSprdPLOut.WriteLine("    -------- --------- ---------");
       //
       for (i = 3; i <= 7; i++)
       {
     double Slope = (Beta[i - 1] - Beta[i]) / (MeanSprdByGroup[i - 1] - MeanSprdByGroup[i]);
     Intercept = Beta[i - 1] - Slope * MeanSprdByGroup[i - 1];
     StkSprdPLOut.WriteLine(string.Format(" " + "{0,11:###########0}", i - 2)
       + string.Format("{0,10:###0.00000}", Intercept)
       + string.Format("{0,10:####0.0000}", Slope));
       }
       //
       //  12-4-13:  Add starting & ending years to improve audit trail.
       //
       StkSprdPLOut.WriteLine();
       StkSprdPLOut.WriteLine(" Span of Input Years:  "
     + string.Format("{0,4:###0}", StartSampleYear)
     + "-"
     + string.Format("{0,4:###0}", EndSampleYear));
       StkSprdPLOut.Close();
       //
       //  Termination message
       //
       Console.WriteLine("See the output file:\n"
     + "  StockSpreadPiecewiseLinearCoefs*.txt");
       regResults.Close();
       log.Close();
       HDDOut.Close();
       HDDDevs.Close();
       Console.ReadKey();
 }