Inicio Trading Sistemático Publicación

Cómo Integrar Eventos de Alto Impacto en tu EA de MetaTrader 4

Archivos adjuntos
15505.zip (2.86 KB, Descargar 2 veces)

Hola, traders. Hoy quiero compartir cómo integrar eventos de alto impacto en tu Asesor Experto (EA) de MetaTrader 4, especialmente si trabajas con petróleo crudo y Brent. Por ejemplo, el informe de inventarios de petróleo crudo se publica generalmente los miércoles a las 10:30 a.m. hora del Este. Sin embargo, si hay un festivo, la fecha de publicación puede cambiar. Por eso, es fundamental validar la fecha de lanzamiento utilizando un servicio en línea como ForexFactory.

Primero, debes añadir en la pestaña de OPCIONES | ASESOR EXPERTO la URL que utilizarás para hacer la WebRequest, que es http://www.forexfactory.com/. (ver imagen 1)

A continuación, necesitas definir una estructura en tu código para almacenar los eventos. Esta declaración se coloca al principio de tu código y declara DailyEvents como una variable global, con un número máximo de eventos almacenados definido por la variable MaxDailyEvents.

// Definir la estructura del evento
struct EVENTOS
{
   string   tiempo;
   string   titulo;
   string   moneda;
   bool     mostrado;
};

#define     MaxDailyEvents       20    // Si crees que tendrás más de 20 eventos de alto impacto, incrementa este número.
EVENTOS      DailyEvents[MaxDailyEvents];

Ahora necesitamos recuperar el código HTML de ForexFactory.com y analizarlo. Si no entiendes el código HTML, ¡no te preocupes! Te guiaré paso a paso.

Primero, construimos la URL para la WebRequest. Si solo queremos su calendario para el día y no el de toda la semana, podemos hacerlo configurando el parámetro day de la solicitud a la fecha de hoy y enviando la solicitud.

string   url="http://www.forexfactory.com/calendar.php?day="; url += MthName(Month()) + DoubleToStr(Day(), 0) + "." + DoubleToStr(Year(), 0);

Luego, enviamos la solicitud, verificamos el código de error (si hay alguno) y convertimos el array de caracteres devuelto a una cadena. Esto facilita el análisis del código HTML.

// Enviar solicitud web
   ResetLastError();
   res = WebRequest("GET", url, cookie, NULL, timeout, post, 0, result, headers);

   // Verificar errores
   if(res == -1)
   {
      Print("Error en WebRequest. Código de error = ", GetLastError());
      MessageBox("Agrega la dirección 'http://forexfactory.com/' en la
lista de URL permitidas en" +
        " la pestaña 'Asesores Expertos'", "Error", MB_ICONINFORMATION);
      return(false);
   }

Si no hay error, convertimos el array de caracteres result a una cadena para facilitar su análisis.

// Convertir array de caracteres a cadena
HTML = CharArrayToString(result);

Ahora que tenemos una cadena, podemos usar la función StringFind para localizar elementos HTML. Lo primero es asegurarnos de que el HTML devuelto es efectivamente para la fecha de hoy y cortar cualquier cosa antes de esta etiqueta HTML. La función GetHTMLElement se utiliza para analizar el código HTML y devolver el valor entre las etiquetas HTML especificadas. A continuación, te muestro su definición.

// Calendario cargado, asegurarnos de que es para la fecha de hoy
int i = StringFind(HTML, "<span class=\"date\">");
if(i == -1) return(false);
HTML = StringSubstr(HTML, i);
string fecha = GetHTMLElement(HTML, "<span>", "</span>");
if(fecha != MthName(Month()) + " " + DoubleToStr(Day(), 0)) return(false);

A continuación, vamos a analizar cada fila de la tabla y extraer los elementos que necesitamos: hora del evento, moneda del evento, impacto y título del evento. Haremos esto para cada fila de la tabla hasta que se alcance el final del calendario o el MaxDailyEvents.

Una vez extraídos los datos de cada fila, los añadimos a la estructura DailyEvents.

// Ahora obtener filas de tabla para cada evento
lasttime = NULL;
cnrt = 0;
date = DoubleToStr(Year(), 0) + ". " + DoubleToStr(Month(), 0) + ". " + DoubleToStr(Day(), 0) + " ";
do
{
   // Obtener información del evento
   time = GetHTMLElement(HTML, "<td class=\"calendar__cell calendar__time time\">", "</td>");
   if(StringFind(time, "<a name=\"upnext\"") == 0) time = GetHTMLElement(time, "class=\"upnext\">", "</span>");
   if(StringLen(time) != 0) lasttime = time;
   if(StringLen(time) == 0) time = lasttime; 
   time = date + time;
   currency = GetHTMLElement(HTML, "<td class=\"calendar__cell calendar__currency currency\">", "</td>");
   impact = GetHTMLElement(HTML, "<span title=\"", "\" class=\"");
   i = StringFind(impact, " Impact");
   if(i != -1) impact = StringSubstr(impact, 0, i);
   title = GetHTMLElement(HTML, "\"calendar__event-title\">", "</span>");
         
   // ¿Es este un evento de alto impacto?
   if(StringFind(Symbol(), currency) != -1 && impact == "Alto")
   {
      // Añadir a la estructura de eventos diarios
      DailyEvents[cntr].mostrado = false;
      DailyEvents[cntr].tiempo = time;
      DailyEvents[cntr].titulo = title;
      DailyEvents[cntr++].moneda = currency;
   }
                  
   // Cortar cadena HTML a la siguiente fila de la tabla
   i = StringFind(HTML, "</tbody> </table> </td> </tr> ");
   if(i != -1) HTML = StringSubstr(HTML, i+30);
   if(StringFind(HTML, "</table> <div class=\"foot\">") == 0) i = -1;
} while(i != -1 || cntr == MaxDailyEvents);

Una vez que hayamos analizado todas las filas de la tabla y alcanzado el final del calendario, necesitamos mostrar los eventos en el gráfico. Si el evento es en el futuro, quiero que se muestre una línea vertical y si es en el pasado, no se mostrará ninguna línea.

// Mostrar los eventos de alto impacto, si hay alguno
lasttime = NULL;
for(cntr = 0; cntr < MaxDailyEvents; cntr++)
{
   if(StringLen(DailyEvents[cntr].tiempo) == 0) break;
      
   // Crear marcador de evento en el gráfico si el último mercado no fue a la misma hora
   if(lasttime != DailyEvents[cntr].tiempo)
   {
      res = cntr;
      // Si tenemos un 'pm' en la cadena, agrega 12 horas a la hora
      if(StringFind(DailyEvents[cntr].tiempo, "pm") != -1) DailyEvents[cntr].tiempo = TimeToStr(StrToTime(DailyEvents[cntr].tiempo) + 43200);
      if(ObjectCreate(0, Event + cntr, OBJ_EVENT, 0, StrToTime(DailyEvents[cntr].tiempo), 0))
      {
         ObjectSetString(0, Event + cntr, OBJPROP_TEXT, DailyEvents[cntr].titulo + " (" + DailyEvents[cntr].moneda + ")");
         ObjectSetInteger(0, Event + cntr, OBJPROP_COLOR, Red);
         ObjectSetInteger(0, Event + cntr, OBJPROP_WIDTH, 2);
         ObjectSetInteger(0, Event + cntr, OBJPROP_BACK, true);
         ObjectSetInteger(0, Event + cntr, OBJPROP_SELECTABLE, false);
         ObjectSetInteger(0, Event + cntr, OBJPROP_SELECTED, false);
         ObjectSetInteger(0, Event + cntr, OBJPROP_HIDDEN, true);
         ObjectSetString(0, Event + cntr, OBJPROP_TOOLTIP, DailyEvents[cntr].titulo + " (" + DailyEvents[cntr].moneda + ")");
      }
      
      // Crear línea vertical si el evento es en el futuro
      if(TimeCurrent() < TimeOffset(DailyEvents[cntr].tiempo, 0))
      {
         if(ObjectCreate(0, VLine + cntr, OBJ_VLINE, 0, TimeOffset(DailyEvents[cntr].tiempo, 0), 0))
         {
            ObjectSetInteger(0, VLine + cntr, OBJPROP_COLOR, Red);
            ObjectSetInteger(0, VLine + cntr, OBJPROP_WIDTH, 1);
            ObjectSetInteger(0, VLine + cntr, OBJPROP_BACK, true);
            ObjectSetInteger(0, VLine + cntr, OBJPROP_SELECTABLE, false);
            ObjectSetInteger(0, VLine + cntr, OBJPROP_SELECTED, false);
            ObjectSetInteger(0, VLine + cntr, OBJPROP_HIDDEN, true);
            ObjectSetString(0, VLine + cntr, OBJPROP_TOOLTIP, DailyEvents[cntr].titulo + " (" + DailyEvents[cntr].moneda + ")");
         }
      }
      else
         DailyEvents[cntr].mostrado = true;
}      
  else
   {
      title = ObjectGetString(0, Event + res, OBJPROP_TOOLTIP);            
      title += "\n" + DailyEvents[cntr].titulo + " (" + DailyEvents[cntr].moneda + ")";
      ObjectSetString(0, Event + res, OBJPROP_TOOLTIP, title);
      if(TimeCurrent() < TimeOffset(DailyEvents[cntr].tiempo, 0)) ObjectSetString(0, VLine + res, OBJPROP_TOOLTIP, title);
  }
   lasttime = DailyEvents[cntr].tiempo;
}

Si los eventos son en el futuro, quiero notificar al usuario sobre un evento inminente si está dentro de los 5 minutos actuales y eliminar la línea vertical. Esto se hace añadiendo un poco de código en tu función start() del EA o indicador.

//+------------------------------------------------------------------+
//| Función de inicio del Asesor Experto                                             |
//+------------------------------------------------------------------+
void start()
{
   string   evento = NULL;
   
   // ¿Hay un evento de alto impacto en los próximos 5 minutos?
   for(int i = 0; i < MaxDailyEvents; i++)
   {
      if(StringLen(DailyEvents[i].tiempo) == 0) break;
      if(TimeCurrent() >= StrToTime(DailyEvents[i].tiempo) - 300 && TimeCurrent() < StrToTime(DailyEvents[i].tiempo) && !DailyEvents[i].mostrado)
      {
         // Evento en 5 minutos...
         evento += DailyEvents[i].titulo + " (" + DailyEvents[i].moneda + "), ";
         DailyEvents[i].mostrado = true;
         
         // Eliminar la línea vertical asociada al evento
         if(ObjectFind("VLine" + DoubleToStr(i, 0)) >= 0) ObjectDelete("VLine" + DoubleToStr(i, 0));
      }  
   }
   
   // ¿Algo para mostrar?
   if(StringLen(evento) != 0)
   {
      evento += "en 5 minutos.";
      Alert(evento);
   }
}

Y finalmente, necesitamos obtener los eventos diarios. Esto se hace añadiendo una línea en tu función OnInit().

//+------------------------------------------------------------------+
//| Función de inicialización del Asesor Experto                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   // Obtener los eventos de hoy
   GetHighImpactEvents();
   
   return(INIT_SUCCEEDED);
}

Fácil y sencillo. Por supuesto, puedes modificar el código para mostrar todos los eventos para el par de divisas o añadir parámetros de entrada a tu indicador o EA para especificar qué impacto mostrar (alto, medio o bajo). Y, por supuesto, añadir una verificación para el cambio de medianoche para obtener una nueva lista de eventos diarios, pero te dejaré jugar con eso :)

¡Saludos!

-Tu amigo trader.

Publicaciones relacionadas

Comentarios (0)