Trying to make datetime check for Daylight Savings more more efficient, any ideas?

To add comments, please log in or register
Raiden
9
Raiden  
#property strict
#property script_show_inputs

extern datetime TimeNowTest = D'2015.01.10';

datetime DayLightShifts[9] = {D'2014.11.02 02:00', //0
                              D'2015.03.08 02:00', //1
                              D'2015.11.01 02:00', //0
                              D'2016.03.13 02:00', //1
                              D'2016.11.06 02:00', //0
                              D'2017.03.12 02:00', //1
                              D'2017.11.05 02:00', //0
                              D'2018.03.11 02:00', //1
                              D'2018.11.04 02:00'}; //0

void OnStart(){

   int GMTOffset_ = -1;
   
   int arraySize = ArraySize(DayLightShifts);
   for(int i = 0; i < arraySize; i++){
      if(TimeNowTest >= DayLightShifts[i] && TimeNowTest < DayLightShifts[i+1]){
         GMTOffset_ = (int)MathMod(i, 2);
         break;
      }
   }

   Print("GMTOffset: ", GMTOffset_);

}

This is my test script, I'm looking to backtest on GMT+0 historical data and to run it per minute in an EA, replacing the extern TimeNowTest with Time[0].

It returns 0 or 1 depending on the TimeNowTest/Time[0].

Any ideas on how this could be more efficient?

rod178
276
rod178  
Raiden:

This is my test script, I'm looking to backtest on GMT+0 historical data and to run it per minute in an EA, replacing the extern TimeNowTest with Time[0].

It returns 0 or 1 depending on the TimeNowTest/Time[0].

Any ideas on how this could be more efficient?

Use a formula for each city dst


datetime CheckDSTStartUS(int cityYear)
{
   datetime dstStartUS=0;
   if(cityYear<1987) return(0);
   int DSTstring_start_dom = 0;
      if (cityYear >= 1987 && cityYear <= 2006) 
   {
      dstStartUS=CheckdstDate(0,1,2,4,cityYear);   // first Sunday in April
   }
   else if (cityYear >= 2007) 
   {
      dstStartUS=CheckdstDate(DSTdayStartUS,DSTweekStartUS,DSThourStartUS,DSTmonthStartUS,cityYear);   // second Sunday in March
   } 
   PrintX(5,PrintTagMax,"dstStartUS->",DateStringA(dstStartUS));
   return(dstStartUS);  
}

datetime CheckDSTEndUS(int cityYear)
{
   datetime dstEndUS=0;
   if(cityYear<1987) return(0);
      if (cityYear >= 1987 && cityYear <= 2006) 
   {
       dstEndUS=CheckdstDate(0,5,2,10,cityYear);      // last Sunday in October
   }
   else if (cityYear >= 2007) 
   {
      dstEndUS=CheckdstDate(DSTdayEndUS,DSTweekEndUS,DSThourEndUS,DSTmonthEndUS,cityYear);     // first Sunday in November
   } 
   PrintX(5,PrintTagMax,"dstEndUS->",DateStringA(dstEndUS));
   return(dstEndUS);  
}



datetime CheckdstDate(int dayOfWeekNum, int dayOfWeekCount, double dayHour, int dayMonthNum, int cityYear)
{ 
   int count=0;
   int weekCount=1;
   datetime dstDate=StringToTime(StringConcatenate(IntegerToString(cityYear),".",IntegerToString(dayMonthNum),".","01"));
   datetime lastdstDate;
   while(dstDate<=TimeCurrent()+PERIOD_MN1*12*60)
   {   
      // Print("TimeDayOfWeek(dstDate)->",TimeDayOfWeek(dstDate));
      if(dayOfWeekNum==TimeDayOfWeek(dstDate)) 
      { 
         lastdstDate=dstDate+dayHour*60*60;
         weekCount=weekCount+1;
      }
      if((dayOfWeekNum==TimeDayOfWeek(dstDate) && weekCount>dayOfWeekCount) ||  TimeMonth(dstDate+24*60*60)!=TimeMonth(dstDate))
      { 
         return(lastdstDate);
      }
      dstDate=dstDate+24*60*60; //Print("dstDate->",dstDate);
   }
   Print("ERROR  ","dstDate->",DateStringA(dstDate));
   return(0);
}
Raiden
9
Raiden  
rod178:

Use a formula for each city dst


Thanks for the suggestion. It's however very costly to use any string to datetime conversion and other time functions. (I'm just using US shift for the moment. Can easily add another array for EUR shift if necessary.)

I've whittled it down to:

#property strict
#property script_show_inputs

extern datetime TimeNowTest = D'2015.01.10';

datetime DayLightShiftDates[36] = {D'2003.04.06 02:00', //1 //NB: 1st date in array must start with 1 for the loop below to work properly (2003.04.06 02:00 to 2003.10.26 02:00 must have GMTOffset = 1)
                                   D'2003.10.26 02:00', //0
                                   D'2004.04.04 02:00', //1
                                   D'2004.10.31 02:00', //0
                                   D'2005.04.03 02:00', //1
                                   D'2005.10.30 02:00', //0
                                   D'2006.04.02 02:00', //1
                                   D'2006.10.29 02:00', //0
                                   D'2007.03.11 02:00', //1
                                   D'2007.11.04 02:00', //0
                                   D'2008.03.09 02:00', //1
                                   D'2008.11.02 02:00', //0
                                   D'2009.03.08 02:00', //1
                                   D'2009.11.01 02:00', //0
                                   D'2010.03.14 02:00', //1
                                   D'2010.11.07 02:00', //0
                                   D'2011.03.13 02:00', //1
                                   D'2011.11.06 02:00', //0
                                   D'2012.03.11 02:00', //1
                                   D'2012.11.04 02:00', //0
                                   D'2013.03.10 02:00', //1
                                   D'2013.11.03 02:00', //0
                                   D'2014.03.09 02:00', //1
                                   D'2014.11.02 02:00', //0
                                   D'2015.03.08 02:00', //1
                                   D'2015.11.01 02:00', //0
                                   D'2016.03.13 02:00', //1
                                   D'2016.11.06 02:00', //0
                                   D'2017.03.12 02:00', //1
                                   D'2017.11.05 02:00', //0
                                   D'2018.03.11 02:00', //1
                                   D'2018.11.04 02:00', //0
                                   D'2019.03.10 02:00', //1
                                   D'2019.11.03 02:00', //0
                                   D'2020.03.08 02:00', //1
                                   D'2020.11.01 02:00'  //0
                                  };

void OnStart(){

   int DSTOffset = 0;
   
   int arraySize = ArraySize(DayLightShiftDates);
   for(int i = 0; i < arraySize; i=i+2){
      if(TimeNowTest >= DayLightShiftDates[i] && TimeNowTest < DayLightShiftDates[i+1]){
         DSTOffset = 1;
         Print(TimeNowTest, " is between ", DayLightShiftDates[i], " and ", DayLightShiftDates[i+1]);
         break;
      }
   }

   Print("DSTOffset: ", DSTOffset);

}

DSTOffset defaults to 0, the loop only checks half of the elements, MathMod() is done away with. (Naturally get rid of the Print() statement in production)

rod178
276
rod178  
Raiden:

Thanks for the suggestion. It's however very costly to use any string to datetime conversion and other time functions. (I'm just using US shift for the moment. Can easily add another array for EUR shift if necessary.)

I've whittled it down to:

DSTOffset defaults to 0, the loop only checks half of the elements, MathMod() is done away with. (Naturally get rid of the Print() statement in production)



if you do no want to continuously perform the calculations, they could be loaded into an array(s) at initialization

ie  US dst 

 Starts second Sunday in March

 Ends  first Sunday in November

JC
1646
JC  
Raiden:

Any ideas on how this could be more efficient?

Surely it depends on the context you need it for? I haven't checked, but this code will presumably execute in microseconds. I can't imagine that you will see any benefit in real trading from trying to improve its efficiency; there'll only be a point if you need to run it in backtesting/optimisation.

If you are going to be (a) doing the DST check frequently and (b) in backtesting, then the obvious way to increase efficiency is to cache the last date for which the function was called and its result, and to return that value if the time hasn't ticked over into a new day.

To add comments, please log in or register