Hora local y del servidor

Siempre hay dos tipos de tiempo en la plataforma MetaTrader 5: local (cliente) y servidor (broker).

La hora local corresponde a la hora del ordenador en el que se ejecuta el terminal, y aumenta continuamente, al mismo ritmo que en el mundo real.

El tiempo de los servidores fluye de forma diferente. La base para ello la establece la hora en el ordenador del broker; sin embargo, el cliente recibe información al respecto sólo junto con los siguientes cambios de precio, que se empaquetan en estructuras especiales llamadas ticks (véase la sección sobre MqlTick) y se pasan a los programas MQL mediante eventos.

Así, la hora actualizada del servidor sólo se conoce en el terminal como resultado de un cambio en el precio de al menos un instrumento financiero en el mercado, es decir, de entre los seleccionados en la ventana de Observación de Mercado. La última hora conocida del servidor se muestra en la barra de título de esta ventana. Si no hay ticks, la hora del servidor en el terminal permanece fija. Esto se nota especialmente los fines de semana y días festivos, cuando todas las bolsas y plataformas de Forex están cerradas.

En concreto, en un domingo, lo más probable es que la hora del servidor sea la del viernes por la tarde. Las únicas excepciones son las instancias de MetaTrader 5 que ofrecen instrumentos de negociación continua, como las criptodivisas. No obstante, incluso en este caso, durante los periodos de baja volatilidad la hora del servidor puede retrasarse notablemente con respecto a la hora local.

Todas las funciones de esta sección operan con la hora con una precisión de hasta un segundo (la precisión de la representación de la hora en el tipo datetime.

Para obtener la hora local y del servidor, la API de MQL5 proporciona tres funciones: TimeLocal, TimeCurrent y TimeTradeServer. Las tres funciones tienen dos versiones del prototipo: la primera devuelve el tiempo como un valor del tipo datetime, y la segunda acepta adicionalmente por referencia y rellena la estructura MqlDateTime con componentes de tiempo.

datetime TimeLocal()

datetime TimeLocal(MqlDateTime &dt)

La función devuelve la hora local del ordenador en el formato datetime.

Es importante tener en cuenta que la hora incluye el horario de verano si está activado. Es decir, TimeLocal es igual a la hora estándar de la zona horaria del ordenador, menos la corrección TimeDaylightSavings. Condicionalmente, la fórmula puede representarse del siguiente modo:

TimeLocal summer() = TimeLocal winter() - TimeDaylightSavings()

Aquí TimeDaylightSavings suele equivaler a -3600, es decir, adelantar el reloj 1 hora (se pierde 1 hora). Así pues, el valor estival de TimeLocal es mayor que el valor invernal (con igual hora astronómica del día) con respecto a UTC. Por ejemplo, si en invierno TimeLocal equivale a UTC+2, en verano es UTC+3. UTC puede obtenerse utilizando la función TimeGMT.

datetime TimeCurrent()

datetime TimeCurrent(MqlDateTime &dt)

La función devuelve la última hora conocida del servidor en el formato datetime. Esta es la hora de llegada de la última cotización de la lista de todos los instrumentos financieros de Observación de Mercado. La única excepción es el manejador de eventos OnTick en los Asesores Expertos, donde esta función devolverá la hora del tick procesado (incluso si ya han aparecido ticks con una hora más reciente en Observación de Mercado).

Además, tenga en cuenta que la hora en el eje horizontal de todos los gráficos en MetaTrader 5 corresponde a la hora del servidor (en la historia). La última barra (la actual, más a la derecha) contiene TimeCurrent. Consulte los detalles en la sección Gráficos.

datetime TimeTradeServer()

datetime TimeTradeServer(MqlDateTime &dt)

La función devuelve la hora actual estimada del servidor de trading. A diferencia de TimeCurrent, cuyos resultados pueden no cambiar si no hay nuevas cotizaciones, TimeTradeServer permite obtener una estimación del tiempo de servidor en continuo aumento. El cálculo se basa en la última diferencia conocida entre las zonas horarias del cliente y del servidor, que se añade a la hora local actual.

En el comprobador, el valor TimeTradeServer es siempre igual a TimeCurrent.

En el script TimeCheck.mq5 se ofrece un ejemplo de cómo funcionan las funciones.

La función principal tiene un bucle infinito que registra todos los tipos de tiempo cada segundo hasta que el usuario detiene el script.

void OnStart()
{
   while(!IsStopped())
   {
      PRTF(TimeLocal());
      PRTF(TimeCurrent());
      PRTF(TimeTradeServer());
      PRTF(TimeTradeServerExact());
      Sleep(1000);
   }
}

Además de las funciones estándar, aquí se aplica una función personalizada TimeTradeServerExact.

datetime TimeTradeServerExact()
{
   enum LOCATION
   {
      LOCAL
      SERVER
   };
   static datetime now[2] = {}, then[2] = {};
   static int shiftInHours = 0;
   static long shiftInSeconds = 0;
   
   // constantly detect the last 2 timestamps here and there
   then[LOCAL] = now[LOCAL];
   then[SERVER] = now[SERVER];
   now[LOCAL] = TimeLocal();
   now[SERVER] = TimeCurrent();
   
   // at the first call we don't have 2 labels yet,
   // needed to calculate the stable difference
   if(then[LOCAL] == 0 && then[SERVER] == 0return 0;
 
   // when the time course is the same on the client and on the server,
   // and the server is not "frozen" due to weekends/holidays,
   // updating difference
   if(now[LOCAL] - now[SERVER] == then[LOCAL] - then[SERVER]
   && now[SERVER] != then[SERVER])
   {
      shiftInSeconds = now[LOCAL] - now[SERVER];
      shiftInHours = (int)MathRound(shiftInSeconds / 3600.0);
      // debug print
      PrintFormat("Shift update: hours: %d; seconds: %lld"shiftInHoursshiftInSeconds);
   }
   
   // NB: The built-in function TimeTradeServer calculates like this:
   //                TimeLocal() - shiftInHours * 3600
   return (datetime)(TimeLocal() - shiftInSeconds);
}

Era necesario porque el algoritmo de la función integrada TimeTradeServer puede no convenirle a todo el mundo. La función integrada encuentra la diferencia entre la hora local y la del servidor en horas (es decir, la diferencia de zona horaria), y luego obtiene la hora del servidor como una corrección de la hora local para esta diferencia. Como resultado, si los minutos y segundos van en el cliente y el servidor de forma no sincrónica (lo que es muy probable), la aproximación estándar de la hora del servidor mostrará los minutos y segundos del cliente, no del servidor.

Lo ideal sería que los relojes locales de todos los ordenadores estuvieran sincronizados con la hora mundial, pero en la práctica se producen desviaciones. Así, si se produce algún desplazamiento, por pequeño que sea, en uno de los lados, TimeTradeServer ya no puede repetir la hora en el servidor con la máxima precisión.

En nuestra implementación de la misma función en MQL5 no redondeamos la diferencia entre la hora del cliente y la del servidor a husos horarios. En lugar de ello se utiliza en el cálculo la diferencia exacta en segundos. Por eso TimeTradeServerExact devuelve la hora en la que los minutos y segundos van exactamente igual que en el servidor.

A continuación se muestra un ejemplo de registro generado por el script.

TimeLocal()=2021.09.02 16:03:34 / ok
TimeCurrent()=2021.09.02 15:59:39 / ok
TimeTradeServer()=2021.09.02 16:03:34 / ok
TimeTradeServerExact()=1970.01.01 00:00:00 / ok

Puede verse que las zonas horarias del cliente y del servidor son las mismas, pero hay una ausencia de sincronización de varios minutos (para mayor claridad). En la primera llamada, TimeTradeServerExact devolvió 0. Además, los datos para calcular la diferencia ya llegarán, y veremos los cuatro tipos de tiempo, «caminando» uniformemente con un intervalo de unos pocos segundos.

TimeLocal()=2021.09.02 16:03:35 / ok
TimeCurrent()=2021.09.02 15:59:40 / ok
TimeTradeServer()=2021.09.02 16:03:35 / ok
Shift update: hours: 0; seconds: 235
TimeTradeServerExact()=2021.09.02 15:59:40 / ok
TimeLocal()=2021.09.02 16:03:36 / ok
TimeCurrent()=2021.09.02 15:59:41 / ok
TimeTradeServer()=2021.09.02 16:03:36 / ok
Shift update: hours: 0; seconds: 235
TimeTradeServerExact()=2021.09.02 15:59:41 / ok
TimeLocal()=2021.09.02 16:03:37 / ok
TimeCurrent()=2021.09.02 15:59:41 / ok
TimeTradeServer()=2021.09.02 16:03:37 / ok
TimeTradeServerExact()=2021.09.02 15:59:42 / ok
TimeLocal()=2021.09.02 16:03:38 / ok
TimeCurrent()=2021.09.02 15:59:43 / ok
TimeTradeServer()=2021.09.02 16:03:38 / ok
TimeTradeServerExact()=2021.09.02 15:59:43 / ok