English Русский 中文 Deutsch 日本語 Português
preview
Gestionando el Horario (Parte 2): Funciones

Gestionando el Horario (Parte 2): Funciones

MetaTrader 5Ejemplos | 2 noviembre 2021, 08:53
1 112 1
Carl Schreiber
Carl Schreiber

Las variables globales

En lugar de pedir ayuda a su bróker, de quien probablemente recibirá una respuesta insuficiente (quién estaría dispuesto a explicar dónde se ha metido la hora faltante), simplemente nos fijaremos en cómo estos calculan sus precios en las semanas de cambio horario, pero evitando engorrosos cálculos manuales: un programa se encargará de ello, después de todo, ¿para qué tenemos un PC?

Antes de las funciones en el archivo de inclusión DealingWithTime.mqh (y después de la sustitución de la macros), declararemos las variables necesarias como variables globales:

//--- global variables for time switches
int      DST_USD=0,                             // act time shift USD
         DST_EUR=0,                             // act time shift EU
         DST_AUD=0,                             // act time shift Australia
         DST_RUS=0;                             // D'2014.10.26 02:00', -10800,

Estas variables DST_USD, DST_EUR... contendrán el cambio horario real de los EE.UU., la UE, etcétera, y serán actualizados y configurados por nuestras funciones. En el horario de invierno, que es el horario normal, serán iguales a cero: la hora no se cambia en ese periodo.

Después de ello, tendremos las variables para la próxima vez que se produzca el cambio de hora. Se necesitarán principalmente para saber cuándo requerimos un nuevo cálculo para ahorrar los recursos de la CPU:

datetime nxtSwitch_USD,                         // date of next switch
         nxtSwitch_EUR,                         // date of next switch
         nxtSwitch_AUD,                         // date of next switch
         nxtSwitch_RUB = D'2014.10.26 02:00';   // Russia s different :(

Analizaremos la situación rusa más adelante en este mismo artículo.

Esta estructura y su variable global son el corazón de todo. :)

struct _OffsetBroker
  {
   int   USwinEUwin,                            // US=Winter & EU=Winter
         USsumEUsum,                            // US=Summer & EU=Summer
         USsumEUwin,                            // US=Summer & EU=Winter
         actOffset,                             // actual time offset of the broker
         secFxWiWi,                             // duration of FX in sec
         secFxSuSu,                             // duration of FX in sec
         secFxSuWi,                             // duration of FX in sec
         actSecFX;                              // actual duration of FX in sec
   bool  set;                                   // are all set?
  };
_OffsetBroker OffsetBroker;

Asignaremos las compensaciones del bróker para los tres periodos relevantes y la duración del mercado fórex estará abierta en estos periodos, tanto para el valor real como para un conjunto de sencilla verificación, si los valores han sido asignados. La variable global se llama OffsetBroker, y la encontraremos varias veces.


Función central para determinar los cambios horarios del bróker

Llamando esta función:

setBokerOffset();

un asesor, indicador o script podrá determinar por sí mismo cuándo y cómo maneja el bróker los cambios horarios. Se coloca al comienzo del código en el script adjunto después de Start(). La función determinará los valores relevantes del bróker para los periodos relevantes (horario de verano, horario de invierno y horario intermedio), que luego se podrán utilizar para determinar los demás horarios necesarios a través de GMT. Como todo lo demás, se encuentra en el archivo de inclusión adjunto DealingWithTime.mqh, que también contiene las partes necesarias del primer artículo. Después, se declara la variable, se realizan las inicializaciones y se ponen a cero las variables globales relevantes:

   datetime dateEUR,dateUSD,dateAUD,dateNxt,                   // switch date for EU, AU, & US
            arrTme[];                                          // array to copy time
   int b;
   OffsetBroker.USsumEUwin =
      OffsetBroker.USsumEUsum =
         OffsetBroker.USwinEUwin = INT_MIN;
   nxtSwitch_USD = nxtSwitch_EUR = nxtSwitch_AUD = 0;          // reset variables

encontramos los fines de semana de cambio:

//--- AU, EU & US switches to winter time in 2020
   if(IS_DEBUG_MODE)
      Print("\n2nd half-year 2020 for ",AccountInfoString(ACCOUNT_COMPANY), "DebugMode: ",IS_DEBUG_MODE);

   nextDST("EUR", D'2020.06.21 14:00');                        // EUR: get DST and set next change
   b = CopyTime("EURUSD",PERIOD_H1,nxtSwitch_EUR,1,arrTme);    // get time last 1h bar before switch in EU
   dateEUR = arrTme[0];                                        // last hour on Friday before the weekend

   nextDST("USD", D'2020.06.21 14:00');                        // USD: get DST and set next change
   b = CopyTime("EURUSD",PERIOD_H1,nxtSwitch_USD,1,arrTme);    // get time last 1h bar before switch in USA
   dateUSD = arrTme[0];                                        // last hour on Friday before the weekend

   nextDST("AUD", D'2020.06.21 14:00');                        // AUD: get DST and set next change
   b = CopyTime("EURUSD",PERIOD_H1,nxtSwitch_AUD,1,arrTme);    // get time last 1h bar before switch in AU
   dateAUD = arrTme[0];                                        // last hour on Friday before the weekend

   dateNxt = fmax(nxtSwitch_EUR,nxtSwitch_USD)+WeekInSec;      // get the next weekend
   b = CopyTime("EURUSD",PERIOD_H1,dateNxt,1,arrTme);          // get time last 1h bar before the weekend
   dateNxt = arrTme[0];                                        // last hour on Friday before the weekend

Para mayor comodidad, la mayoría de las impresiones se realizan automáticamente en el modo de depuración: if(IS_DEBUG_MODE). Entonces, al iniciar, por ejemplo, el script adjunto en el depurador (F5), podremos ver todos los detalles; pero si iniciamos el mismo script directamente en un gráfico, obtendremos solo las cosas importantes.

Para las tres zonas horarias, la llamada de la función (por ejemplo, nextDST ("EUR", D'2020.06.21 14:00 ') se usa en primer lugar para calcular las diferencias horarias aplicables para la UE y, en segundo lugar, para el siguiente cambio. En junio, se trata del horario de verano, y el próximo fin de semana de cambio será al horario de invierno. En la línea inmediatamente posterior, obtenemos la hora de apertura de la última barra h1 el viernes anterior a ese fin de semana, ya que será el punto de referencia para nuestro cálculo. Eche un vistazo al punto 4 de los supuestos del final del primer artículo:

          4. Si faltan horas entre el viernes a las 17:00 y el domingo a las 17:00, luego faltarán cotizaciones el domingo hasta la primera cotización, y no el viernes después de la última cotización recibida.

He decidido usar las horas de h1 y "EURUSD". Probablemente, este símbolo es el que tiene la historia más larga, no solo en MQ. Pero esto también significa que si el mercado de divisas cierra a las 17:00 hora de Nueva York, la última hora o la última barra de 1 hora comenzará a las 16:00, y esta será la hora en la que estaremos particularmente interesados más adelante. La primera hora después de un fin de semana es las 17:00 del domingo en Nueva York. En aras de una mayor exhaustividad, el cambio de Australia también se determina, pero no se usará en el futuro (ver más abajo). Después de eso, aún se determina el primer fin de semana posterior al cambio de ambas zonas horarias, para calcular así la diferencia horaria del bróker del próximo periodo de diferencia.

Luego, para las tres horas del viernes, se calculan las diferencias horarias respectivas relacionadas con el periodo del bróker con la función chckFriday(...), usando como base la hora 16:00 de Nueva York. Esta función forma parte del archivo de inclusión y la analizaremos a continuación.

   chckFriday(dateEUR,"EUR");                                  // function to determine broker offset for the Friday given
   chckFriday(dateUSD,"USD");                                  // function to determine broker offset for the Friday given
   chckFriday(dateNxt,"NXT");                                  // function to determine broker offset for the Friday given

Después de eso, se utiliza el mismo principio para calcular los demás cambios de hora en la otra mitad del año, que (mire arriba) realmente no necesitamos y que podrían comentarse así:

   if(IS_DEBUG_MODE)
      Print("\n1st half-year 2021 for ",AccountInfoString(ACCOUNT_COMPANY), "DebugMode: ",IS_DEBUG_MODE);
   nxtSwitch_USD = nxtSwitch_EUR = nxtSwitch_AUD = 0;

   nextDST("AUD", D'2021.01.21 14:00');                        // AUD: get DST and set next change
   b = CopyTime("EURUSD",PERIOD_H1,nxtSwitch_AUD,1,arrTme);    // get time last 1h bar before switch in EU
   dateAUD = arrTme[0];                                        // last hour on Friday before the weekend

...
   chckFriday(dateUSD,"USD");                                  // function to determin broker offset for the Friday given
   chckFriday(dateEUR,"EUR");                                  // function to determin broker offset for the Friday given
   chckFriday(dateNxt,"NXT");                                  // function to determin broker offset for the Friday given

Finalmente, una vez se han detectado las compensaciones del bróker y se han asignado estas a los campos correspondientes, las horas de cambio decisivas (nxtSwitch_USD = nxtSwitch_EUR = nxtSwitch_AUD = 0) se ponen a cero para su uso posterior. Como el recálculo debe realizarse solo si se "ha pasado" un fin de semana con cambio de hora durante el curso histórico, la hora posterior puede impedir que se efectúen los cálculos correctos, por consiguiente, será mejor reiniciar una vez de más, que una de menos. Luego se verifica si se han asignado todos los valores; el resultado se imprime en el diario del experto y se retorna la comprobación:

   nxtSwitch_USD = nxtSwitch_EUR = nxtSwitch_AUD = 0;          // reset variables for use by a user
   if(OffsetBroker.USsumEUwin != INT_MIN
      && OffsetBroker.USsumEUsum != INT_MIN
      && OffsetBroker.USwinEUwin != INT_MIN
     )
      OffsetBroker.set = true;
   else
      OffsetBroker.set = false;
   if(OffsetBroker.set)
      Print("\nTime Offset of ",AccountInfoString(ACCOUNT_COMPANY),": ",
            "\nUS=Winter & EU=Winter (USwinEUwin) = ",OffsetBroker.USwinEUwin,
            "\nUS=Summer & EU=Summer (USsumEUsum) = ",OffsetBroker.USsumEUsum,
            "\nUS=Summer & EU=Winter (USsumEUwin) = ",OffsetBroker.USsumEUwin,
            "\n");
   else
      Print(__FILE__,"[",__LINE__,"] Assigning the broker offset went wrong - somehow.");
   return(OffsetBroker.set);

Si todo está bien, veremos unas líneas, por ejemplo, así:

Time Offset of MetaQuotes Software Corp.:
US=Winter & EU=Winter (USwinEUwin)       =   -7200
US=Summer & EU=Summer (USsumEUsum) = -10800
US=Summer & EU=Winter (USsumEUwin)    =   -7200

Esto permite que cualquier usuario use estos valores para las variables de entrada en lugar de la función que se ejecutará antes de que el asesor comience a funcionar, ya sea en el simulador de estrategias o en vivo en un gráfico. Le ofrecemos un ejemplo al final del artículo.


Determinando y estableciendo las diferencias horarias del bróker

Vamos a analizar ahora la función chckFriday(...). Determina la compensación horaria del bróker respectivo para los diferentes periodos y la asigna al campo correspondiente de la variable global OffsetBroker del Tpy de la estructura _OffsetBroker. La estructura conoce estos tres campos:

   int   USwinEUwin,                            // US=Winter & EU=Winter
         USsumEUsum,                            // US=Summer & EU=Summer
         USsumEUwin,                            // US=Summer & EU=Winter

Son asignados a la diferencia horaria correspondiente del bróker del periodo respectivo. Los periodos son:

  • el mismo en ambas regiones, ya sea en invierno (o en la hora estándar) o en verano, o
  • EE.UU. ya (todavía) en verano y la UE todavía (ya) en invierno.

La situación inversa, cuando los Estados Unidos ya (todavía) están en invierno, pero la UE todavía (ya) está en verano, no existe. Aquí nos surgen varias preguntas: ¿por qué no existe una cuarta categoría? ¿Y qué pasa con Australia o el AUD, es que faltan aquí?

Estas son las reglas para cambiar:

  • UE: último domingo de octubre y último domingo de marzo
  • EE.UU.: primer domingo de noviembre y segundo domingo de marzo y
  • AU: primer domingo de noviembre y último domingo de marzo


Respecto a la primera pregunta: la UE cambia al horario de invierno una o dos semanas antes que los EE.UU., pues allí todavía es verano, mientras que en la UE ya es invierno. Por ello, el valor se asigna al campo USsumEUwin de la variable OffsetBroker. Luego, en primavera, los EE.UU. cambian al horario de verano antes que la UE; después es nuevamente verano en los EE.UU. durante una semana o dos, mientras que aún es invierno en la UE. Nuevamente, el valor se asigna al campo USsumEUwin de la variable OffsetBroker. Esto deja claro que el caso inverso (en la UE ya (todavía) es verano, pero en los EE. UU. todavía (ya) es invierno) no ocurre en absoluto. En realidad, esto elimina la necesidad de calcular las compensaciones horarias del bróker para ambos periodos de cambio en otoño y primavera. Sin embargo, se ejecuta, simplemente para mayor integridad y control.

Sobre la segunda pregunta: Australia cambia en noviembre como los EE.UU. y en primavera como la UE. Por ello, no hay fines de semana diferentes adicionales para el cambio. No obstante, el reloj en Australia se adelanta 1 hora cuando es invierno en la UE y los EE. UU., porque allí la Navidad y el Año Nuevo caen en verano.

Ahora, si ya calculamos el cambio de tiempo para un periodo especial, también podremos calcular la duración actual de la apertura del mercado de divisas en estas semanas. Estos valores se guardan en los campos secFxWiWi, secFxSuSu, secFxSuWi y el valor válido actual en actSecFX. Al final del artículo, en el capítulo Aplicación, mostraremos cómo gestionar esto.

Pero antes de poder asignar los valores, deberemos determinarlos. Después de la declaración de la variable y el restablecimiento de las variables globales, las diferencias horarias para EU y USD se calcularán para la hora tB (time Broker) dada:

//+------------------------------------------------------------------+
//| auxiliary function to determine time offset of the broker        |
//+------------------------------------------------------------------+
int chckFriday(
   datetime tB,                                                // time Broker: the last hour on Friday
   string cmt=""                                               // text to start the line
)
  {

   int hNY, hGMT, hTC, hDiff;
   nxtSwitch_AUD = nxtSwitch_USD = nxtSwitch_EUR = 0;          // reset to be save
   nextDST("EUR",tB);                                          // get the offset for EUR of the time tB given
   nextDST("USD",tB);                                          // get the offset for USD of the time tB given

Aquí, tB será el comienzo de la última hora del viernes, es decir, cuando son las 16:00 en Nueva York. Esta suposición será la base del cálculo adicional, porque podremos calcular GMT para este tiempo:

tGMT = tNY + (NYShift + DST_USD)

y por lo tanto la compensación del bróker a GMT. Determinamos la compensación de esta manera: restamos de la última hora del viernes del bróker tB los últimos segundos de este día, SoB (tB). Obtenemos la hora 00:00 para el día y luego añadimos los segundos hasta las 16:00 (16*3600). Ahora conocemos la hora de Nueva York, de la cual obtenemos GMT añadiendo NYShift + DST_USD. Así, podemos determinar fácilmente la compensación horaria del bróker a partir de GMT y luego asignarla al campo correspondiente de OffsetBroker.
En la función, todo esto se realiza en horas (en lugar de en segundos) con la macrosustitución HoD() (Hora del Día), para ceñirse mejor a la documentación y que la verificación de la impresión resulte más sencilla:

   hNY   = HoD(tB - SoD(tB) + 16*3600);                        // get the hour of New York time
   hGMT  = HoD(tB - SoD(tB) + 16*3600 + NYShift + DST_USD);    // get the hour of GMT
   hTC   = HoD(tB);                                            // get the hour of the time given
   hDiff = hGMT - HoD(tB);                                     // get the difference between GMT and the broker

Después de todo, no resulta tan complicado. ;)

Por motivos de seguridad, insertaremos lo siguiente: Se encarga de comprobar si la situación no esperada (EE.UU. en verano y UE en invierno), no tiene lugar:

   if(DST_USD==0 && DST_EUR!=0)                                // this should not occur
      Alert(__LINE__," ",TOSTR(DST_USD),TOSTR(DST_EUR),"  USwin && EUsum");

Ahora podemos asignar la diferencia hallada y la duración de la apertura del mercado FX:

//--- set the broker offset for the various time situations:
   if(DST_USD+DST_EUR==0)                                      // both in winter (normal) time
     {
      OffsetBroker.actOffset = OffsetBroker.USwinEUwin = hDiff*3600;
      OffsetBroker.actSecFX  = OffsetBroker.secFxWiWi = SoW(tB);
     }
   else
      if(DST_USD == DST_EUR)                                   // else both in summer time
        {
         OffsetBroker.actOffset = OffsetBroker.USsumEUsum = hDiff*3600;
         OffsetBroker.actSecFX  = OffsetBroker.secFxSuSu = SoW(tB);
        }
      else
         if(DST_USD!=0 && DST_EUR==0)                          // US:summer EU:winter
           {
            OffsetBroker.actOffset = OffsetBroker.USsumEUwin = hDiff*3600;
            OffsetBroker.actSecFX  = OffsetBroker.secFxSuWi = SoW(tB);
           }

Finalmente, imprimimos todos los valores encontrados y retornamos la última compensación real:

//--- calc the ring of times NY->GMT->Broker->GMT->NY <= the last NY must always be 16!!
   Print(cmt,": ",DoWs(tB),TimeToString(tB),": ",TOSTR(hNY),TOSTR(hGMT),TOSTR(hTC),TOSTR(hDiff),
         " BrokerTime => GMT: ",TimeToString(tB+OffsetBroker.actOffset),
         " => tNY: ",TimeToString((tB + OffsetBroker.actOffset)-(NYShift + DST_USD)),
         "  End-FX after: ",OffsetBroker.actSecFX/3600,"h"
        );
   return(OffsetBroker.actOffset);

Esto tiene el aspecto siguiente:

EUR: Fr.2020.10.23 23:00: hNY:16  hGMT:20  hTC:23  hDiff:-3   BrokerTime => GMT: 2020.10.23 20:00 => tNY: 2020.10.23 16:00  End FX in: 143h
USD: Fr.2020.10.30 22:00: hNY:16  hGMT:20  hTC:22  hDiff:-2   BrokerTime => GMT: 2020.10.30 20:00 => tNY: 2020.10.30 16:00  End FX in: 142h
NXT: Fr.2020.11.06 23:00: hNY:16  hGMT:21  hTC:23  hDiff:-2   BrokerTime => GMT: 2020.11.06 21:00 => tNY: 2020.11.06 16:00  End FX in: 143h

Aquí se muestran algunas cosas interesantes que vale la pena discutir. La UE cambia primero el 25/10. Una semana después, los Estados Unidos, el 1/11. En este periodo intermedio, la última hora del viernes en MQ comienza a las 22:00, en lugar de a las 23:00, y la semana termina con esta barra después de 142horas, en lugar de las 143 horas habituales. ¿143 o 142 horas? La semana de FX tiene solo 120 horas: 5*24=120 Los segundos de la semana (SoW()) y las otras funciones comparables se refieren a la semana calendárica, que comienza el domingo a las 00:00. Pero del domingo a las 00:00 al viernes a las 23:00, ahora hay 6* 24-1 = 143. Este valor se usa a continuación para calcular en cualquier momento de una semana el tiempo restante que permanece abierto el mercado Fórex.

Estas tres líneas también se usan para verificar la lógica y el cálculo, y también como ejemplo de cómo un usuario puede determinar una hora local requerida a partir de GMT. Comenzando desde la izquierda, a la marca temporal del bróker le sigue la hora supuesta en Nueva York, hNY: 16, luego la hora GMT basada en la hora de Nueva York, la hora del bróker y su diferencia horaria: - 2 o 3. En la segunda parte, más a la derecha, GMT se calcula a partir de la hora del bróker (tB+OffsetBroker.actOffset) y después de GMT vemos nuevamente la hora en Nueva York ((tB+OffsetBroker.actOffset)-(NYShift + DST_USD)). Aquí siempre debemos tener 16:00 para tNY, y así es. A continuación, se realiza una segunda verificación de horas arbitrarias en la historia, y, además, de otros brókeres.


Cálculo de los fines de semana del cambio de horario

Pero antes de llegar a la verificación, donde revisaremos la historia de horas para "EURUSD", tendremos que discutir la esencia del cálculo, la función nextDST(...).
La función se llama con el parámetro zone para la zona horaria "USD", "EUR" o "AUD" (donde "AUD" no es realmente necesario) y t, el parámetro para la hora actual, generalmente la hora actual del bróker TimeCurrent(). Primero se verifica si es necesario un nuevo cálculo (aquí para "EUR"):

void nextDST(string zone, datetime t)
  {
   if((zone == "EUR") && t < nxtSwitch_EUR)
     {
      if(IS_DEBUG_MODE)
         Print("no change as time < nxtSwitch_EUR");
      return;
     }
...

Esto también muestra por qué resulta importante restablecer los valores de nxtSwitch_EUR a cero al inicio de la prueba, porque, de lo contrario, podría no realizarse un nuevo cálculo durante toda la prueba.

Luego, después de declararse e inicializarse la variable, llegamos al corazón de la función, que no es mío. Hace bastante tiempo, encontré en algún lugar de la red un algoritmo que determina un día determinado del mes. Se usa para determinar el horario de verano o invierno en un momento concreto. El algoritmo no es tan complicado:

  1. Determine el día del mes, un domingo, en el que se realiza el cambio.
  2. Cree una fecha a partir de ella.
  3. Encuentre el domingo de cambio futuro más cercano.
  4. Establezca el cambio horario, 0h o -1h, y el próximo domingo de cambio.

La magia de este algoritmo está en la línea de código que determina el día en el mes del cambio de hora. Para la UE, es el último domingo de marzo, y se calcula así (como ya he dicho, la idea de la fórmula no es mía):

d = (int)(31 - MathMod((4 + MathFloor(5*y/4)), 7));         // determing the last Sunday in March for the EU switch
Para los resultados del año 2021, para el último domingo de marzo, aquí tenemos la fórmula EXCEL, como d=25:

31 - MOD(ROUNDDOWN(5*2021/4);7) = 25.


A partir de ahí, se forma la marca temporal en la que la UE cambia al horario de verano: el 25 de marzo de 2021, último domingo de marzo:
spr = StringToTime(""+(string)y+".03."+(string)d+" 03:00"); // convert to datetime format

El procedimiento para todas las demás fechas es similar, y no necesita una explicación aparte.
Aquí, vemos ahora una sección más grande del código, que determina el horario actual de verano o invierno y la próxima fecha de cambio en la UE para una fecha determinada. Necesitamos tres secciones en un año: antes del primer cambio horario, entre el primer cambio y el segundo, y después del segundo. El siguiente cambio horario ya se encuentra en el próximo año, y esto debe tenerse en cuenta:

   if(zone == "EUR")
     {
      d = (int)(31 - MathMod((4 + MathFloor(5*y/4)), 7));         // determing the last Sunday in March for the EU switch
      spr = StringToTime(""+(string)y+".03."+(string)d+" 03:00"); // convert to datetime format
      if(t < spr)
        {
         DST_EUR = 0;                                             // no time offset
         nxtSwitch_EUR = spr;                                     // set the next time switch
         if(IS_DEBUG_MODE)
            Print(zone,"-DST for ",TimeToString(t)," DST: ",StringFormat("% 5i",DST_EUR),"  nxtSwitch: ",DoWs(nxtSwitch_EUR)," ",TimeToString(nxtSwitch_EUR));
         return;
        }
      d = (int)(31 - MathMod((1 + MathFloor(5*y/4)), 7));         // determing the last Sunday in October for the EU switch
      aut = StringToTime(""+(string)y+".10."+(string)d+" 03:00"); // convert to datetime format
      if(t < aut)
        {
         DST_EUR =-3600;                           // = +1h => 09:00 London time = GMT+05h+DST_EU = GMT+0+1 = GMT+1;
         nxtSwitch_EUR = aut;                                     // set the next time switch
         if(IS_DEBUG_MODE)
            Print(zone,"-DST for ",TimeToString(t)," DST: ",StringFormat("% 5i",DST_EUR),"  nxtSwitch: ",DoWs(nxtSwitch_EUR)," ",TimeToString(nxtSwitch_EUR));
         return;
        }
      y++;                                                        // re-calc the spring switch for the next year
      d = (int)(31 - MathMod((4 + MathFloor(5*y/4)), 7));         // determing the last Sunday in March for the EU switch
      spr = StringToTime(""+(string)y+".03."+(string)d+" 03:00"); // convert to datetime format
      if(t < spr)
        {
         DST_EUR = 0;                                             // no time offset
         nxtSwitch_EUR = spr;                                     // set the next time switch
         if(IS_DEBUG_MODE)
            Print(zone,"-DST for ",TimeToString(t)," DST: ",StringFormat("% 5i",DST_EUR),"  nxtSwitch: ",DoWs(nxtSwitch_EUR)," ",TimeToString(nxtSwitch_EUR));
         return;
        }
      Print("ERROR for ",zone," @ ",TimeToString(t)," DST: ",StringFormat("% 5i",DST_EUR),"  nxtSwitch: ",DoWs(nxtSwitch_EUR)," ",TimeToString(nxtSwitch_EUR),"  winter: ",TimeToString(aut),"  spring: ",TimeToString(spr));
      return;
     }

Se pueden ver tres secciones en un año:

  1. Antes del cambio al horario de verano en marzo.
  2. Antes del cambio al horario de invierno en octubre/noviembre.
  3. En el horario de invierno, el cambio al horario de verano del próximo año.

Esto se repite para EUR, USD y AUD.

Llamadas únicas de la función nextDST(..) como

nextDST("EUR", D'2019.02.05 20:00');
nextDST("EUR", D'2019.06.05 20:00');
nextDST("EUR", D'2019.11.20 20:00');
        
nextDST("USD", D'2019.02.05 20:00');
nextDST("USD", D'2019.06.05 20:00');
nextDST("USD", D'2019.11.20 20:00');
        
nextDST("AUD", D'2019.02.05 20:00');
nextDST("AUD", D'2019.06.05 20:00');
nextDST("AUD", D'2019.11.20 20:00');

pondrán a prueba los tres momentos relevantes del año para las tres regiones. Este es el resultado:

EU: último domingo de marzo y último domingo de octubre:
    EUR-DST for 2019.02.05 20:00 DST:        0   nxtSwitch: Su. 2019.03.31 03:00
    EUR-DST for 2019.06.05 20:00 DST: -3600   nxtSwitch: Su. 2019.10.27 03:00
    EUR-DST for 2019.11.20 20:00 DST:        0   nxtSwitch: Su. 2020.03.29 03:00

US: segundo domingo de marzo y primer domingo de noviembre:
    USD-DST for 2019.02.05 20:00 DST:        0   nxtSwitch: Su. 2019.03.10 03:00
    USD-DST for 2019.06.05 20:00 DST: -3600   nxtSwitch: Su. 2019.11.03 03:00
    USD-DST for 2019.11.20 20:00 DST:        0   nxtSwitch: Su. 2020.03.08 03:00

AU: primer domingo de noviembre y último domingo de marzo:
    AUD-DST for 2019.02.05 20:00 DST: -3600   nxtSwitch: Su. 2019.03.31 03:00
    AUD-DST for 2019.06.05 20:00 DST:        0   nxtSwitch: Su. 2019.11.03 03:00
    AUD-DST for 2019.11.20 20:00 DST: -3600   nxtSwitch: Su. 2020.03.29 03:00

Quizás el cambio de hora en Australia sea confuso, pero Australia, a diferencia de los EE.UU. y Europa, se encuentra en el hemisferio sur, donde el cambio de año se da en mitad del verano y, por consiguiente, es de esperar que su horario de verano sea en el invierno europeo.


El cambio en Rusia

Una pequeña nota: dado que MQ tiene raíces rusas y hay muchos usuarios rusos, también se incluyen los cambios de horario rusos. No obstante, debido a la gran cantidad de cambios, y cuándo y cómo se cambian los relojes en Rusia, he decidido usar una matriz bidimensional en la que se han introducido las horas y las diferencias correspondientes, y que el lector podrá consultar con esta función:

long RussiaTimeSwitch[][2] =
  {
   D'1970.01.00 00:00', -10800,
   D'1980.01.00 00:00', -10800,
   D'1981.04.01 00:00', -14400,
...
   D'2012.01.00 00:00', -14400,
   D'2014.10.26 02:00', -10800,
   D'3000.12.31 23:59', -10800
  };
int SzRussiaTimeSwitch = 67;                    // ArraySize of RussiaTimeSwitch

//+------------------------------------------------------------------+
//| Russian Time Switches                                            |
//+------------------------------------------------------------------+
void offsetRubGMT(const datetime t)
  {
   int i = SzRussiaTimeSwitch; //ArrayRange(RussiaTimeSwitch,0); 66
   while(i-->0 && t < RussiaTimeSwitch[i][0])
      continue;
// t >= RussiaTimeSwitch[i][0]
   nxtSwitch_RUB  = (datetime)RussiaTimeSwitch[fmin(SzRussiaTimeSwitch-1,i+1)][0];
   DST_RUS        = (int)RussiaTimeSwitch[fmin(SzRussiaTimeSwitch-1,i+1)][1];
   return;
  }
//+------------------------------------------------------------------+


La función que mantiene los tiempos actualizados

Ahora llegamos a la última función de este proyecto, encargada de mantener actualizados los valores cruciales:

//+------------------------------------------------------------------+
//| function to determin broker offset for the time tB given         |
//+------------------------------------------------------------------+
void checkTimeOffset(datetime tB)
  {
   if(tB < nxtSwitch_USD && tB < nxtSwitch_EUR && tB < nxtSwitch_AUD)
      return;                                                  // nothing has changed, return

También pregunta primero desde el principio si se debe establecer la compensación horaria (y la próxima fecha de cambio). De lo contrario, saldremos inmediatamente de la función.

Si no, los valores de "EUR", "USD", "AUD" y "RUB" se calcularán con la función nextDST() descrita anteriormente:

   if(tB>nxtSwitch_USD)
      nextDST("USD", tB);                                      // US has switched
   if(tB>nxtSwitch_EUR)
      nextDST("EUR", tB);                                      // EU has switched
   if(tB>nxtSwitch_AUD)
      nextDST("AUD", tB);                                      // AU has switched
   if(tB>nxtSwitch_RUB)
      nextDST("RUB", tB);                                      // RU has switched

"USD" y "EUR" se necesitan para determinar la compensación del bróker. "AUD" y "RUB" solo son necesarios si el usuario quiere conocerlos, de lo contrario, se podrán desactivar simplemente con //.

Luego, dependiendo del periodo, le asignaremos al campo OffsetBroker.actOffset la compensación horaria del bróker válida desde ese momento y OffsetBroker.actSecFX, el periodo actual de apertura del mercado de divisas:

   if(DST_USD+DST_EUR==0)                                      // both in winter (normal) time
     {
      OffsetBroker.actOffset = OffsetBroker.USwinEUwin;
      OffsetBroker.actSecFX  = OffsetBroker.secFxWiWi;
     }
   else
      if(DST_USD == DST_EUR)                                   // else both in summer time
        {
         OffsetBroker.actOffset = OffsetBroker.USsumEUsum;
         OffsetBroker.actSecFX  = OffsetBroker.secFxSuSu;
        }
      else
         if(DST_USD != DST_EUR)                                // US:summer EU:winter
           {
            OffsetBroker.actOffset = OffsetBroker.USsumEUwin;
            OffsetBroker.actSecFX  = OffsetBroker.secFxSuWi;
           }

Eso es todo. Estas son todas las funciones que debemos usar: una para determinar las compensaciones horarias del bróker partiendo de una cotización y otra que siempre determina la compensación horaria actual, a partir de la cual podemos averiguar fácilmente la hora GMT y, por consiguiente, cualquier otra hora local, incluso en el simulador de estrategias.

A continuación, vamos a mostrar dos formas de usar todo.


Script que muestra la configuración y el uso

Al principio, lo pusimos en el script (adjunto) DealingWithTimeScript.mq5:

#include <DealingWithTime.mqh>
//+------------------------------------------------------------------+
//| Finding the broker offsets                                       |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- step 1: set the broker time offsets in winter, summer and in between
   bool isTimeSet = setBokerOffset();
   if(!isTimeSet)
     {
      Alert("setBokerOffset failed");
      return;
     }

Esto se imprimirá en el diario de expertos:

EUR: Fr.2020.10.23 23:00: hNY:16  hGMT:20  hTC:23  hDiff:-3   BrokerTime => GMT: 2020.10.23 20:00 => tNY: 2020.10.23 16:00  End-FX after: 143h
USD: Fr.2020.10.30 22:00: hNY:16  hGMT:20  hTC:22  hDiff:-2   BrokerTime => GMT: 2020.10.30 20:00 => tNY: 2020.10.30 16:00  End-FX after: 142h
NXT: Fr.2020.11.06 23:00: hNY:16  hGMT:21  hTC:23  hDiff:-2   BrokerTime => GMT: 2020.11.06 21:00 => tNY: 2020.11.06 16:00  End-FX after: 143h
USD: Fr.2021.03.12 23:00: hNY:16  hGMT:21  hTC:23  hDiff:-2   BrokerTime => GMT: 2021.03.12 21:00 => tNY: 2021.03.12 16:00  End-FX after: 143h
EUR: Fr.2021.03.26 22:00: hNY:16  hGMT:20  hTC:22  hDiff:-2   BrokerTime => GMT: 2021.03.26 20:00 => tNY: 2021.03.26 16:00  End-FX after: 142h
NXT: Fr.2021.04.02 23:00: hNY:16  hGMT:20  hTC:23  hDiff:-3   BrokerTime => GMT: 2021.04.02 20:00 => tNY: 2021.04.02 16:00  End-FX after: 143h

Compensación horaria de MetaQuotes Software Corp.: 
US=Winter & EU=Winter (USwinEUwin)      =  -7200
US=Summer & EU=Summer (USsumEUsum) = -10800
US=Summer & EU=Winter (USsumEUwin)   =   -7200

Esto ya permite asignar las compensaciones encontradas a las variables de entrada. Este es el ejemplo del próximo capítulo. Lo que vemos aquí ya está explicado, así que avanzaremos al siguiente paso de este script. Simulamos una ruta desde el pasado hasta la hora real del bróker y calculamos e imprimimos los valores de GMT Nueva York y el tiempo restante que el mercado de divisas permanece abierto para marcas temporales seleccionadas al azar.

Obtenemos la historia completa de las marcas temporales de 1h de "EURUSD" con la función CopyTime("EURUSD",PERIOD_H1,datetime(0),TimeCurrent(),arr1h).

No obstante, para no ahogarnos en toneladas de datos y en una expresión larga para este gran periodo, solo mostraremos los datos de barras determinadas al azar. Para ello, seleccionaremos cuántos datos debe haber. Con el 5 dado serán aproximadamente 10, porque en el promedio aleatorio, la distancia de salto es aproximadamente la mitad de sz/5:

//--- step 2: get the quotes (here only 1h time stamps)
   datetime arr1h[], tGMT, tNY, tLeft;
   CopyTime("EURUSD",PERIOD_H1,datetime(0),TimeCurrent(),arr1h);
   int b       = 0,
       sz      = ArraySize(arr1h)-1,                  // oldest time stamp
       nChecks = sz/5,                                // ~2*5+1 randomly chosen bars
       chckBar = MathRand()%nChecks;                  // index of the first bar to check

Ahora, vamos a pasar por todas las barras, desde la más antigua hasta la actual, como en una prueba u optimización en el simulador de estrategias: while(++b<=sz). Lo primero que haremos es comprobar la situación de la hora para cada nueva barra: checkTimeOffset(arr1h[b]). Recordemos que en esta función lo primero que se comprueba es la necesidad de realizar un recálculo, por lo que, a pesar de su frecuencia, esta llamada no consume muchos recursos:

//---  step 3: simulate an EA or an indicator go through the time from the past to now
   while(++b<=sz)
     {
      //--- check the time situation, normally do it at the first bar after the weekend
      checkTimeOffset(arr1h[b]);

Ahora, realizaremos los cálculos (solo) para la barra determinada por el valor aleatorio GMT (tGMT), la hora de Nueva York (tNY) y tLeft el resto tiempo hasta que se cierre el mercado de divisas. Entonces, esto es imprimido, y luego se calcula el índice de la siguiente barra:

      //--- for a randomly selected bar calc. the times of GMT, NY & tLeft and print them
      if(b>=chckBar || b==sz)
        {
         tGMT  = arr1h[b] + OffsetBroker.actOffset;         // GMT
         tNY   = tGMT - (NYShift+DST_USD);                  // time in New York
         tLeft = OffsetBroker.actSecFX - SoW(arr1h[b]);     // time till FX closes
         PrintFormat("DST_EUR:%+ 6i  DST_EUR:%+ 6i  t[%6i]  tBrk: %s%s  "+
                     "GMT: %s%s  NY: %s%s  End-FX: %2ih => left: %2ih ",
                     DST_EUR,DST_USD,b,
                     DoWs(arr1h[b]),TimeToString(arr1h[b],TIME_DATE|TIME_MINUTES),
                     DoWs(tGMT),TimeToString(tGMT,TIME_DATE|TIME_MINUTES),
                     DoWs(tNY),TimeToString(tNY,TIME_DATE|TIME_MINUTES),
                     OffsetBroker.actSecFX/3600,tLeft/3600
                    );
         chckBar += MathRand()%nChecks;               // calc. the index of the next bar to check
        }

Aquí tenemos ahora la impresión completa de este script para una cuenta demo de Metaquotes:

EUR: Fr.2020.10.23 23:00: hNY:16  hGMT:20  hTC:23  hDiff:-3   BrokerTime => GMT: 2020.10.23 20:00 => tNY: 2020.10.23 16:00  End-FX after: 143h
USD: Fr.2020.10.30 22:00: hNY:16  hGMT:20  hTC:22  hDiff:-2   BrokerTime => GMT: 2020.10.30 20:00 => tNY: 2020.10.30 16:00  End-FX after: 142h
NXT: Fr.2020.11.06 23:00: hNY:16  hGMT:21  hTC:23  hDiff:-2   BrokerTime => GMT: 2020.11.06 21:00 => tNY: 2020.11.06 16:00  End-FX after: 143h
USD: Fr.2021.03.12 23:00: hNY:16  hGMT:21  hTC:23  hDiff:-2   BrokerTime => GMT: 2021.03.12 21:00 => tNY: 2021.03.12 16:00  End-FX after: 143h
EUR: Fr.2021.03.26 22:00: hNY:16  hGMT:20  hTC:22  hDiff:-2   BrokerTime => GMT: 2021.03.26 20:00 => tNY: 2021.03.26 16:00  End-FX after: 142h
NXT: Fr.2021.04.02 23:00: hNY:16  hGMT:20  hTC:23  hDiff:-3   BrokerTime => GMT: 2021.04.02 20:00 => tNY: 2021.04.02 16:00  End-FX after: 143h

Compensación horaria de MetaQuotes Software Corp.: 
US=Winter & EU=Winter (USwinEUwin)      =  -7200
US=Summer & EU=Summer (USsumEUsum) = -10800
US=Summer & EU=Winter (USsumEUwin)   =   -7200

DST_EUR: -3600  DST_EUR: -3600  t[ 28194]  tBrk: Mo.2002.05.20 22:00  GMT: Mo.2002.05.20 19:00  NY: Mo.2002.05.20 15:00  End-FX: 143h => left: 97h 
DST_EUR: -3600  DST_EUR: -3600  t[ 40805]  tBrk: We.2004.05.26 06:00  GMT: We.2004.05.26 03:00  NY: Tu.2004.05.25 23:00  End-FX: 143h => left: 65h 
DST_EUR: -3600  DST_EUR: -3600  t[ 42882]  tBrk: Th.2004.09.23 19:00  GMT: Th.2004.09.23 16:00  NY: Th.2004.09.23 12:00  End-FX: 143h => left: 28h 
DST_EUR:      +0  DST_EUR:     +0  t[ 44752]  tBrk: Tu.2005.01.11 17:00  GMT: Tu.2005.01.11 15:00  NY: Tu.2005.01.11 10:00  End-FX: 143h => left: 78h 
DST_EUR:      +0  DST_EUR: -3600  t[ 64593]  tBrk: We.2008.03.26 03:00  GMT: We.2008.03.26 01:00  NY: Tu.2008.03.25 21:00  End-FX: 142h => left: 67h 
DST_EUR:      +0  DST_EUR:     +0  t[ 88533]  tBrk: Tu.2012.02.07 13:00  GMT: Tu.2012.02.07 11:00  NY: Tu.2012.02.07 06:00  End-FX: 143h => left: 82h 
DST_EUR:      +0  DST_EUR:     +0  t[118058]  tBrk: We.2016.11.16 06:00  GMT: We.2016.11.16 04:00  NY: Tu.2016.11.15 23:00  End-FX: 143h => left: 65h 
DST_EUR: -3600  DST_EUR: -3600  t[121841]  tBrk: Mo.2017.06.26 05:00  GMT: Mo.2017.06.26 02:00  NY: Su.2017.06.25 22:00  End-FX: 143h => left: 114h 
DST_EUR:      +0  DST_EUR: -3600  t[144995]  tBrk: Mo.2021.03.22 06:00  GMT: Mo.2021.03.22 04:00  NY: Mo.2021.03.22 00:00  End-FX: 142h => left: 112h 
DST_EUR: -3600  DST_EUR: -3600  t[148265]  tBrk: Tu.2021.09.28 15:00  GMT: Tu.2021.09.28 12:00  NY: Tu.2021.09.28 08:00  End-FX: 143h => left: 80h 

Ya hemos analizado los dos primeros bloques. La tercera y última parte muestra para los puntos temporales elegidos aleatoriamente las respectivas diferencias de tiempo de la UE y los EE.UU., el índice del punto temporal seguido de las horas del bróker, GMT y Nueva York, seguidas de la hora de apertura del mercado de divisas en este momento y en el tiempo restante; para mayor claridad, se convierten en horas, en lugar de en segundos. Esto se puede verificar rápidamente ahora mismo: el 20/5/2002, la hora del bróker (MQ) es 22:00; se aplica el horario de verano, GMT = bróker-3h = 19:00 y NY = GMT - (5h-1h) = 15:00, y el mercado de divisas cierra en 97 horas. 97 = 4*24 (Mon.22:00-Fri.22:00 = 96h) +1h (Fri.22:00-23:00) - qed.

Entonces, un asesor o indicador que solo requiera las diversas compensaciones, necesitará apenas dos llamadas de función:

   bool isTimeSet = setBokerOffset();
   if(!isTimeSet)
     {
      Alert("setBokerOffset failed");
      return;
     }
..
   checkTimeOffset(TimeCurrent());


Alternativa usando las Variables de Entrada

Finalmente, vamos a ver un ejemplo en el que un asesor puede usar esto en sus variables de entrada. Con el script de arriba hemos obtenido la expresión:

Time Offset of MetaQuotes Software Corp.:
US=Winter & EU=Winter (USwinEUwin)      =  -7200
US=Summer & EU=Summer (USsumEUsum) = -10800
US=Summer & EU=Winter (USsumEUwin)   =   -7200

Sabiendo esto, el asesor (no está adjunto, podrá copiarlo de aquí) tendría el aspecto siguiente:

#include <DealingWithTime.mqh>
// offsets of MetaQuotes demo account: DO NOT USE THEM FOR DIFFERENT BROKERS!!
input int   USwinEUwin=  -7200;    // US=Winter & EU=Winter
input int   USsumEUsum= -10800;    // US=Summer & EU=Summer
input int   USsumEUwin=  -7200;    // US=Summer & EU=Winter

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   OffsetBroker.USwinEUwin = USwinEUwin;
   OffsetBroker.USsumEUsum = USsumEUsum;
   OffsetBroker.USsumEUwin = USsumEUwin;
   OffsetBroker.actOffset  = WRONG_VALUE; 
   
   nxtSwitch_USD = nxtSwitch_EUR = nxtSwitch_AUD = 0;
   //--- Just a simple test if not ste or changed
   if(OffsetBroker.USwinEUwin+OffsetBroker.USsumEUsum+OffsetBroker.USsumEUwin==0)
      OffsetBroker.set     = false;
   else
      OffsetBroker.set     = true;
   //...
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   checkTimeOffset(TimeCurrent());
   tGMT  = TimeCurrent() + OffsetBroker.actOffset;    // GMT
   tNY   = tGMT - (NYShift+DST_USD);                  // time in New York
   tLon  = tGMT - (LondonShift+DST_EUR);              // time in London
   tSyd  = tGMT - (SidneyShift+DST_AUD);              // time in Sidney
   tMosc = tGMT - (MoskwaShift+DST_RUS);              // time in Moscow
   tTok  = tGMT - (TokyoShift);                       // time in Tokyo - no DST

   //...
   
  }

Aquí hemos utilizado las compensaciones de Metaquotes. ¡Asegúrese de usar las compensaciones de su bróker!

En OnTick(), en primer lugar, se calculan las compensaciones horarias y, a continuación, la hora GMT y las horas locales de Nueva York, Londres, Sydney, Moscú y Tokio para mostrar lo simple que resulta ahora. No se olvide: fíjese en los paréntesis.


Conclusión

A modo de conclusión, solo expondremos los resultados de la función setBokerOffset() aplicada a las cuentas demo de varios brókeres:

EUR: Fr.2020.10.23 23:00: hNY:16  hGMT:20  hTC:23  hDiff:-3   BrokerTime => GMT: 2020.10.23 20:00 => tNY: 2020.10.23 16:00  End-FX after: 143h
USD: Fr.2020.10.30 22:00: hNY:16  hGMT:20  hTC:22  hDiff:-2   BrokerTime => GMT: 2020.10.30 20:00 => tNY: 2020.10.30 16:00  End-FX after: 142h
NXT: Fr.2020.11.06 23:00: hNY:16  hGMT:21  hTC:23  hDiff:-2   BrokerTime => GMT: 2020.11.06 21:00 => tNY: 2020.11.06 16:00  End-FX after: 143h
USD: Fr.2021.03.12 23:00: hNY:16  hGMT:21  hTC:23  hDiff:-2   BrokerTime => GMT: 2021.03.12 21:00 => tNY: 2021.03.12 16:00  End-FX after: 143h
EUR: Fr.2021.03.26 22:00: hNY:16  hGMT:20  hTC:22  hDiff:-2   BrokerTime => GMT: 2021.03.26 20:00 => tNY: 2021.03.26 16:00  End-FX after: 142h
NXT: Fr.2021.04.02 23:00: hNY:16  hGMT:20  hTC:23  hDiff:-3   BrokerTime => GMT: 2021.04.02 20:00 => tNY: 2021.04.02 16:00  End-FX after: 143h

Time Offset of MetaQuotes Software Corp.: 
US=Winter & EU=Winter (USwinEUwin) = -7200
US=Summer & EU=Summer (USsumEUsum) = -10800
US=Summer & EU=Winter (USsumEUwin) = -7200



EUR: Fr.2020.10.23 23:00: hNY:16  hGMT:20  hTC:23  hDiff:-3   BrokerTime => GMT: 2020.10.23 20:00 => tNY: 2020.10.23 16:00  End-FX after: 143h
USD: Fr.2020.10.30 22:00: hNY:16  hGMT:20  hTC:22  hDiff:-2   BrokerTime => GMT: 2020.10.30 20:00 => tNY: 2020.10.30 16:00  End-FX after: 142h
NXT: Fr.2020.11.06 23:00: hNY:16  hGMT:21  hTC:23  hDiff:-2   BrokerTime => GMT: 2020.11.06 21:00 => tNY: 2020.11.06 16:00  End-FX after: 143h
USD: Fr.2021.03.12 23:00: hNY:16  hGMT:21  hTC:23  hDiff:-2   BrokerTime => GMT: 2021.03.12 21:00 => tNY: 2021.03.12 16:00  End-FX after: 143h
EUR: Fr.2021.03.26 22:00: hNY:16  hGMT:20  hTC:22  hDiff:-2   BrokerTime => GMT: 2021.03.26 20:00 => tNY: 2021.03.26 16:00  End-FX after: 142h
NXT: Fr.2021.04.02 23:00: hNY:16  hGMT:20  hTC:23  hDiff:-3   BrokerTime => GMT: 2021.04.02 20:00 => tNY: 2021.04.02 16:00  End-FX after: 143h

Time Offset of RoboForex Ltd: 
US=Winter & EU=Winter (USwinEUwin) = -7200
US=Summer & EU=Summer (USsumEUsum) = -10800
US=Summer & EU=Winter (USsumEUwin) = -7200


EUR: Fr.2020.10.23 23:00: hNY:16  hGMT:20  hTC:23  hDiff:-3   BrokerTime => GMT: 2020.10.23 20:00 => tNY: 2020.10.23 16:00  End-FX after: 143h
USD: Fr.2020.10.30 22:00: hNY:16  hGMT:20  hTC:22  hDiff:-2   BrokerTime => GMT: 2020.10.30 20:00 => tNY: 2020.10.30 16:00  End-FX after: 142h
NXT: Fr.2020.11.06 23:00: hNY:16  hGMT:21  hTC:23  hDiff:-2   BrokerTime => GMT: 2020.11.06 21:00 => tNY: 2020.11.06 16:00  End-FX after: 143h
USD: Fr.2021.03.12 23:00: hNY:16  hGMT:21  hTC:23  hDiff:-2   BrokerTime => GMT: 2021.03.12 21:00 => tNY: 2021.03.12 16:00  End-FX after: 143h
EUR: Fr.2021.03.26 22:00: hNY:16  hGMT:20  hTC:22  hDiff:-2   BrokerTime => GMT: 2021.03.26 20:00 => tNY: 2021.03.26 16:00  End-FX after: 142h
NXT: Fr.2021.04.02 23:00: hNY:16  hGMT:20  hTC:23  hDiff:-3   BrokerTime => GMT: 2021.04.02 20:00 => tNY: 2021.04.02 16:00  End-FX after: 143h

Time Offset of Alpari International: 
US=Winter & EU=Winter (USwinEUwin) = -7200
US=Summer & EU=Summer (USsumEUsum) = -10800
US=Summer & EU=Winter (USsumEUwin) = -7200


EUR: Fr.2020.10.23 23:00: hNY:16  hGMT:20  hTC:23  hDiff:-3   BrokerTime => GMT: 2020.10.23 20:00 => tNY: 2020.10.23 16:00  End-FX after: 143h
USD: Fr.2020.10.30 23:00: hNY:16  hGMT:20  hTC:23  hDiff:-3   BrokerTime => GMT: 2020.10.30 20:00 => tNY: 2020.10.30 16:00  End-FX after: 143h
NXT: Fr.2020.11.06 23:00: hNY:16  hGMT:21  hTC:23  hDiff:-2   BrokerTime => GMT: 2020.11.06 21:00 => tNY: 2020.11.06 16:00  End-FX after: 143h
USD: Fr.2021.03.12 23:00: hNY:16  hGMT:21  hTC:23  hDiff:-2   BrokerTime => GMT: 2021.03.12 21:00 => tNY: 2021.03.12 16:00  End-FX after: 143h
EUR: Fr.2021.03.26 23:00: hNY:16  hGMT:20  hTC:23  hDiff:-3   BrokerTime => GMT: 2021.03.26 20:00 => tNY: 2021.03.26 16:00  End-FX after: 143h
NXT: Fr.2021.04.02 23:00: hNY:16  hGMT:20  hTC:23  hDiff:-3   BrokerTime => GMT: 2021.04.02 20:00 => tNY: 2021.04.02 16:00  End-FX after: 143h

Time Offset of Pepperstone Group Limited: 
US=Winter & EU=Winter (USwinEUwin) = -7200
US=Summer & EU=Summer (USsumEUsum) = -10800
US=Summer & EU=Winter (USsumEUwin) = -10800


EUR: Fr.2020.10.23 23:00: hNY:16  hGMT:20  hTC:23  hDiff:-3   BrokerTime => GMT: 2020.10.23 20:00 => tNY: 2020.10.23 16:00  End-FX after: 143h
USD: Fr.2020.10.30 23:00: hNY:16  hGMT:20  hTC:23  hDiff:-3   BrokerTime => GMT: 2020.10.30 20:00 => tNY: 2020.10.30 16:00  End-FX after: 143h
NXT: Fr.2020.11.06 23:00: hNY:16  hGMT:21  hTC:23  hDiff:-2   BrokerTime => GMT: 2020.11.06 21:00 => tNY: 2020.11.06 16:00  End-FX after: 143h
USD: Fr.2021.03.12 23:00: hNY:16  hGMT:21  hTC:23  hDiff:-2   BrokerTime => GMT: 2021.03.12 21:00 => tNY: 2021.03.12 16:00  End-FX after: 143h
EUR: Fr.2021.03.26 23:00: hNY:16  hGMT:20  hTC:23  hDiff:-3   BrokerTime => GMT: 2021.03.26 20:00 => tNY: 2021.03.26 16:00  End-FX after: 143h
NXT: Fr.2021.04.02 23:00: hNY:16  hGMT:20  hTC:23  hDiff:-3   BrokerTime => GMT: 2021.04.02 20:00 => tNY: 2021.04.02 16:00  End-FX after: 143h

Time Offset of Eightcap Pty Ltd: 
US=Winter & EU=Winter (USwinEUwin) = -7200
US=Summer & EU=Summer (USsumEUsum) = -10800
US=Summer & EU=Winter (USsumEUwin) = -10800

EUR: Fr.2020.10.23 23:00: hNY:16  hGMT:20  hTC:23  hDiff:-3   BrokerTime => GMT: 2020.10.23 20:00 => tNY: 2020.10.23 16:00  End-FX after: 143h
USD: Fr.2020.10.30 22:00: hNY:16  hGMT:20  hTC:22  hDiff:-2   BrokerTime => GMT: 2020.10.30 20:00 => tNY: 2020.10.30 16:00  End-FX after: 142h
NXT: Fr.2020.11.06 23:00: hNY:16  hGMT:21  hTC:23  hDiff:-2   BrokerTime => GMT: 2020.11.06 21:00 => tNY: 2020.11.06 16:00  End-FX after: 143h
USD: Fr.2021.03.12 23:00: hNY:16  hGMT:21  hTC:23  hDiff:-2   BrokerTime => GMT: 2021.03.12 21:00 => tNY: 2021.03.12 16:00  End-FX after: 143h
EUR: Fr.2021.03.26 22:00: hNY:16  hGMT:20  hTC:22  hDiff:-2   BrokerTime => GMT: 2021.03.26 20:00 => tNY: 2021.03.26 16:00  End-FX after: 142h
NXT: Fr.2021.04.02 23:00: hNY:16  hGMT:20  hTC:23  hDiff:-3   BrokerTime => GMT: 2021.04.02 20:00 => tNY: 2021.04.02 16:00  End-FX after: 143h

Time Offset of InstaForex Companies Group: 
US=Winter & EU=Winter (USwinEUwin) = -7200
US=Summer & EU=Summer (USsumEUsum) = -10800
US=Summer & EU=Winter (USsumEUwin) = -7200


EUR: Fr.2020.10.23 21:00: hNY:16  hGMT:20  hTC:21  hDiff:-1   BrokerTime => GMT: 2020.10.23 20:00 => tNY: 2020.10.23 16:00  End-FX after: 141h
USD: Fr.2020.10.30 21:00: hNY:16  hGMT:20  hTC:21  hDiff:-1   BrokerTime => GMT: 2020.10.30 20:00 => tNY: 2020.10.30 16:00  End-FX after: 141h
NXT: Fr.2020.11.06 21:00: hNY:16  hGMT:21  hTC:21  hDiff: 0   BrokerTime => GMT: 2020.11.06 21:00 => tNY: 2020.11.06 16:00  End-FX after: 141h
USD: Fr.2021.03.12 21:00: hNY:16  hGMT:21  hTC:21  hDiff: 0   BrokerTime => GMT: 2021.03.12 21:00 => tNY: 2021.03.12 16:00  End-FX after: 141h
EUR: Fr.2021.03.26 21:00: hNY:16  hGMT:20  hTC:21  hDiff:-1   BrokerTime => GMT: 2021.03.26 20:00 => tNY: 2021.03.26 16:00  End-FX after: 141h
NXT: Fr.2021.04.02 21:00: hNY:16  hGMT:20  hTC:21  hDiff:-1   BrokerTime => GMT: 2021.04.02 20:00 => tNY: 2021.04.02 16:00  End-FX after: 141h

Time Offset of JFD Group Ltd: 
US=Winter & EU=Winter (USwinEUwin) = 0
US=Summer & EU=Summer (USsumEUsum) = -3600
US=Summer & EU=Winter (USsumEUwin) = -3600

Que el comercio le enriquezca. :)



Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/9929

Archivos adjuntos |
DealingWithTime.mqh (52.89 KB)
Carl Schreiber
Carl Schreiber | 5 jul. 2023 en 18:58

La versión de DealingWithTime.mqh v. 1.01 del artículo "Gestionando el Horario (Parte 2): Funciones" ( https://www.mql5.com/es/articles/9929 ) dejó de funcionar porque MetaQuotes cambió el comportamiento de CopyTime() y ahora ya no funcionan algún tiempo después de la publicación de este artículo. Ahora esta función ya no devuelve valores de tiempo futuros si son mayores que TimeCurrent() especificado para los parámetros start_time y/o stop_time. En su lugar, el tiempo de apertura de la última barra actual se devuelve como el mayor valor posible.

Dado que el final de la sesión de FX se determinó de esta manera para determinar la compensación de tiempo del corredor, ¡esto ahora conduce a valores incorrectos!

Este cálculo se modificó en la versión 2.03. Esta versión ya está disponible en CodeBase aquí: https://www.mql5.com/en/code/45287 .

Pero también se cambió por completo el cálculo del cambio de hora, por lo que ahora se cubren los tiempos complicados del cambio de hora desde Sídney (Australia) hasta los años 70.

También se adjunta la tabla DST 1975 - 2030.xlsx como archivo zip con todos los cambios de hora desde los años 70 para que todos puedan verificar el correcto funcionamiento de las fórmulas, aquí hay una serie de ejemplos de la tabla:

El 1 de enero de 1982 es la hora estándar en EE. UU. (DST==0) y el próximo cambio será el 25 de abril de 1982, el último (25 del mes) domingo de abril (4). La tabla ya está ordenada por zona horaria geográfica (columna A), luego por zona horaria del año (columna L, spr=primavera, aut=otoño) y finalmente por fecha de consulta (columna C). La tabla puede ser creada automáticamente por el EA incluido (un script no puede ejecutarse en modo de depuración). Test_DST 2.mq5 si lo ejecuta en modo de depuración y copia las líneas del registro diario en el depurador y las pega en una hoja de cálculo; El separador de celdas sería el espacio.

Además, ahora hay una función nueva y simple, SecTillClose(), que le brinda el tiempo restante en segundos (la moneda de tiempo de MetaQuotes) hasta que se cierre el mercado de divisas, sin CopyTime(). Esto es interesante para aquellos que quieren cerrar sus posiciones antes del fin de semana o no quieren abrir una nueva posición en un período definido antes del fin de semana.

El indicador incluido DealingWithTime_TestIndi.mq5, como comentario en el gráfico, muestra no solo el horario de verano en Europa, EE.UU. y Australia (Sídney), sino también la hora actual y la diferencia horaria de varias ciudades. Aquí puede encontrar una tabla con diferentes horas locales de las principales ciudades para comparar: https://www.timeanddate.com/worldclock/ . Por lo tanto, puede comprobar los valores en cualquier momento. Este indicador también muestra cómo se determinan y usan estos valores (qué resta o agrega), lo que facilita su uso: copiar y pegar, la forma más rápida de programación.

Las dos últimas líneas también muestran el último segundo de la sesión FX actual y el tiempo restante en horas (que es más fácil de juzgar) y en segundos. En Nueva York, cuando la sesión de FX cierra a las 5:00 p.m., hora local, un viernes, no hay una barra válida abierta a las 5:00 p.m., hora de Nueva York. Por lo tanto, en esta función, se resta 1 segundo para obtener el último tiempo de apertura válido de la última barra en el tiempo del corredor. Sin embargo, algunos corredores finalizan su sesión de FX unos minutos antes y ya no brindan precios ni aceptan órdenes comerciales.

Cómo ser un mejor programador (parte 06): 9 hábitos que conducen a una codificación eficaz Cómo ser un mejor programador (parte 06): 9 hábitos que conducen a una codificación eficaz
La escritura de código no siempre redunda en el dominio de una codificación efectiva. Hay ciertos hábitos que he desarrollado gracias a la experiencia, y que nos ayudan a codificar con mayor eficacia. En el presente artículo, analizaremos con detalle algunos de ellos. Este es un artículo de lectura obligada para aquellos programadores que quieran lograr escribir algoritmos complejos con menos molestias.
Gráficos en la biblioteca DoEasy (Parte 84): Clases herederas del objeto gráfico abstracto estándar Gráficos en la biblioteca DoEasy (Parte 84): Clases herederas del objeto gráfico abstracto estándar
En este artículo, analizaremos la creación de las clases herederas del objeto gráfico abstracto estándar del terminal. El objeto de esta clase describirá las propiedades comunes para todos los objetos gráficos, es decir, se tratará simplemente de un cierto objeto gráfico. Para aclarar su pertenencia a un objeto gráfico real, necesitaremos heredar de él, y en la clase del objeto heredado, escribir las propiedades inherentes a ese objeto gráfico en particular.
Gráficos en la biblioteca DoEasy (Parte 85): Colección de objetos gráficos - añadiendo los objetos nuevamente creados Gráficos en la biblioteca DoEasy (Parte 85): Colección de objetos gráficos - añadiendo los objetos nuevamente creados
En este artículo, finalizaremos la creación de las clases herederas de la clase de objeto gráfico abstracto y comenzaremos a implementar el almacenamiento de estos objetos en la clase de colección. En concreto, crearemos la funcionalidad necesaria para añadir los objetos gráficos estándar recién creados a la clase de colección.
Gestionando el Horario (Parte 1): Fundamentos Gestionando el Horario (Parte 1): Fundamentos
Funciones y fragmentos de código que simplifican y aclaran el manejo del tiempo, la diferencia con el bróker y los cambios en el horario de verano o invierno. La sincronización precisa puede ser un elemento crucial en el trading. A la hora actual, ¿la bolsa de valores de Londres o Nueva York está ya abierta o sigue cerrada? ¿Cuándo comienza y finaliza el horario comercial para el trading en Fórex? Para un tráder que comercia de forma manual y en vivo, esto no supone un gran problema.