Obtener el último tick de un símbolo

En el capítulo sobre series temporales, en la sección Trabajar con arrays de ticks reales, introdujimos la estructura MqlTick integrada que contiene campos con valores de precio y volumen para un símbolo concreto, conocidos en el momento de cada cambio en las cotizaciones. En modo online, un programa MQL puede consultar los últimos precios y volúmenes recibidos utilizando la función SymbolInfoTick que adopta la misma estructura.

bool SymbolInfoTick(const string symbol, MqlTick &tick)

Para un símbolo con un nombre dado symbol, la función rellena la estructura tick pasada por referencia. Si tiene éxito, devuelve true.

Como sabe, los indicadores y Asesores Expertos son llamados automáticamente por el terminal a la llegada de un nuevo tick si contienen la descripción de los manejadores correspondientes OnCalculate y OnTick. No obstante, la información sobre el significado de los cambios de precios, el volumen de la última operación y la hora de generación del tick no se transfieren directamente a los manejadores. Se puede obtener información más detallada con la función SymbolInfoTick.

Los eventos de ticks se generan sólo para un símbolo del gráfico, por lo que ya hemos considerado la opción de obtener nuestro propio evento multisímbolo para ticks basado en eventos personalizados. En este caso, SymbolInfoTick permite leer información sobre ticks en símbolos de terceros acerca de la recepción de notificaciones.

Tomemos el indicador EventTickSpy.mq5 y convirtámoslo en SymbolTickSpy.mq5, que solicitará la estructura MqlTick para el símbolo correspondiente en cada tick «multidivisa» y luego calculará y mostrará todos los diferenciales en el gráfico.

Vamos a añadir un nuevo parámetro de entrada Index. Será necesario para una nueva forma de enviar notificaciones: enviaremos sólo el índice del símbolo cambiado en el evento de usuario (ver más adelante).

#define TICKSPY 0xFEED // 65261
 
input string SymbolList = 
   "EURUSD,GBPUSD,XAUUSD,USDJPY,USDCHF"// List of symbols, comma separated (example)
input ushort Message = TICKSPY;          // Custom message id
input long Chart = 0;                    // Receiving chart id (do not edit)
input int Index = 0;                     // Index in symbol list (do not edit)

Además, añadimos el array Spreads para almacenar diferenciales por símbolos y la variable SelfIndex para recordar la posición del símbolo del gráfico actual en la lista (si está incluido en la lista, que suele ser así). Esto último es necesario para llamar a nuestra nueva función de manejo de ticks desde OnCalculate en la copia original del indicador. Es más fácil y más correcto tomar un índice ya hecho para _Symbol de forma explícita y no devolvérnoslo en un evento a nosotros mismos.

int Spreads[];
int SelfIndex = -1;

Las estructuras de datos introducidas se inicializan en OnInit. Por lo demás, OnInit se ha mantenido sin cambios, incluido el lanzamiento de instancias subordinadas del indicador en símbolos de terceros (estas líneas se omiten aquí).

void OnInit()
{
   ...
         const int n = StringSplit(SymbolList, ',', Symbols);
         ArrayResize(Spreadsn);
         for(int i = 0i < n; ++i)
         {
            if(Symbols[i] != _Symbol)
            {
               ...
            }
            else
            {
               SelfIndex = i;
            }
            Spreads[i] = 0;
         }
   ...
}

En el manejador OnCalculate generamos un evento personalizado en cada tick si la copia del indicador funciona en el otro símbolo (al mismo tiempo, el ID del gráfico Chart al que deben enviarse las notificaciones no es igual a 0). Tenga en cuenta que el único parámetro rellenado en el evento es lparam, que es igual a Index (dparam es 0, y sparam es NULL). Si Chart es igual a 0, significa que estamos en la copia principal del indicador trabajando sobre el símbolo gráfico _Symbol, y si se encuentra en la lista de símbolos de entrada, llamamos directamente a OnSymbolTick con el índice SelfIndex correspondiente.

int OnCalculate(const int rates_totalconst int prev_calculatedconst intconst double &price[])
{
   if(prev_calculated)
   {
      if(Chart > 0)
      {
         EventChartCustom(ChartMessageIndex0NULL);
      }
      else if(SelfIndex > -1)
      {
         OnSymbolTick(SelfIndex);
      }
   }
  
   return rates_total;
}

En la parte receptora del algoritmo de eventos en OnChartEvent, también llamamos a OnSymbolTick, pero esta vez obtenemos el número de símbolo de la lista en lparam (lo que se envió como el parámetro Index desde otra copia del indicador).

void OnChartEvent(const int idconst long &lparamconst double &dparamconst string &sparam)
{
   if(id == CHARTEVENT_CUSTOM + Message)
   {
      OnSymbolTick((int)lparam);
   }
}

La función OnSymbolTick solicita la información completa de los ticks utilizando SymbolInfoTick y calcula el diferencial como la diferencia entre los precios de Ask y Bid dividida por el tamaño del punto (la propiedad SYMBOL_POINT se abordará más adelante).

void OnSymbolTick(const int index)
{
   const string symbol = Symbols[index];
   
   MqlTick tick;
   if(SymbolInfoTick(symboltick))
   {
      Spreads[index] = (int)MathRound((tick.ask - tick.bid)
         / SymbolInfoDouble(symbolSYMBOL_POINT));
      string message = "";
      for(int i = 0i < ArraySize(Spreads); ++i)
      {
         message += Symbols[i] + "=" + (string)Spreads[i] + "\n";
      }
      
      Comment(message);
   }
}

El nuevo diferencial actualiza la celda correspondiente del array Spreads, tras lo cual el array entero se muestra en el gráfico del comentario. He aquí el aspecto que tiene:

Diferenciales actuales para la lista de símbolos solicitada
Diferenciales actuales para la lista de símbolos solicitada

Puede comparar en tiempo real la correspondencia de la información en el comentario y en la ventana Observación de Mercado.