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
- Crea tu Asesor Experto con MQL5: Señales de Trading Basadas en Estrellas de la Mañana/Atardecer y CCI
- Cómo Crear un Asesor Experto con MQL5: Señales de Trading Basadas en Estrellas y Estocástico
- Señales de Trading con MQL5: Patrones de Estrellas y MFI
- Crea tu Asesor Experto con MQL5: Señales de Trading Basadas en Harami y Estocástico
- Crea tu Asesor Experto con MQL5: Señales de Bullish Harami/Bearish Harami y RSI