De novato a experto: Noticias animadas utilizando MQL5 (I)
Contenido:
Introducción
Hoy, nos proponemos abordar una limitación común en la forma en que se accede a las noticias económicas y a los eventos del calendario dentro de la terminal MetaTrader 5, específicamente, durante el análisis de gráficos activos.
En MetaTrader 5, las pestañas Noticias y Calendario económico están disponibles en la ventana Caja de herramientas. Estas pestañas proporcionan información importante procedente de proveedores de noticias acreditados. Sin embargo, es esencial comprender la diferencia entre ambos:
- Pestaña Noticias: muestra titulares y actualizaciones que ya se han publicado.
- Calendario económico: proporciona un cronograma de los próximos eventos económicos, categorizados por fecha, hora e importancia, útil para planificar con anticipación.
Ambas herramientas son vitales para el análisis del mercado. Los traders experimentados saben que algunas publicaciones económicas (como las decisiones sobre las tasas de interés o las nóminas no agrícolas) pueden mover significativamente el mercado. Con la preparación adecuada, estos eventos ofrecen oportunidades comerciales rentables. Sin embargo, también conllevan un riesgo sustancial si las transacciones van en contra de las expectativas.

Acceder a las noticias y al Calendario en MetaTrader 5.
En la captura de pantalla compartida anteriormente, verás que MetaTrader 5 proporciona acceso tanto a las noticias como al calendario económico dentro de un único entorno integrado. Sin embargo, se hace evidente una limitación clave: para ver cualquiera de estas funciones, el usuario debe navegar manualmente hasta la ventana Caja de herramientas.
Una vez dentro de la Caja de herramientas, la información se presenta en forma de tabla: las filas y columnas muestran diversas noticias y eventos programados, junto con detalles relevantes. Los usuarios pueden desplazarse por el servicio de noticias para leer los titulares o explorar el calendario para ver los próximos comunicados económicos. Si bien el panel Caja de herramientas se puede expandir para mostrar más contenido, hacerlo implica reducir el tamaño de la ventana del gráfico, lo que potencialmente obstruye la acción del precio, los indicadores o los objetos gráficos en el gráfico.
Nuestra solución propuesta aborda esta limitación al proyectar titulares de noticias y eventos del calendario directamente en el gráfico, manteniendo una visibilidad completa sin invadir el espacio del gráfico ni interferir con los objetos comerciales. El objetivo es mejorar la accesibilidad y el conocimiento de la situación preservando al mismo tiempo un entorno gráfico limpio y funcional.
En esta sección introductoria de nuestra miniserie, comenzaremos principalmente implementando el calendario económico MQL5 para mostrar un titular de los próximos eventos noticiosos. La solución aquí se inspira en cómo se muestran normalmente los titulares de las noticias en la parte inferior de la pantalla de un televisor, o en cómo se transmiten normalmente los anuncios de esa manera en los vídeos de las redes sociales.
En la siguiente sección, presentaremos el enfoque que se utilizará para construir el EA de titulares de noticias utilizando MQL5. Describiremos la estrategia de diseño, repasaremos las decisiones de implementación clave y luego profundizaremos en la base del código en detalle.
Finalmente, concluiremos con los resultados de las pruebas y las observaciones, proporcionando una vista completa de principio a fin del ciclo de vida del desarrollo de este sistema de visualización de noticias en tiempo real en MetaTrader 5.
Concepto
Para hacer realidad esta idea, aprovecharemos la Biblioteca estándar MQL5, que proporciona herramientas robustas para el desarrollo de interfaces gráficas. En concreto, utilizaremos la clase CCanvas, ubicada en el archivo MQL5\Include\Canvas\Canvas.mqh. Esta clase nos permite crear superficies de dibujo rectangulares y transparentes, ideales para superponer contenido dinámico, como titulares de noticias y actualizaciones de eventos económicos, directamente sobre el gráfico.
Nuestra implementación se centra en un sistema de ticker desplazable que muestra continuamente información relevante sin interrumpir la funcionalidad de los gráficos. Este concepto está inspirado en las interfaces del mundo real que se ven en las transmisiones de noticias de televisión, sitios web financieros e incluso en el contenido de video de las redes sociales, donde los titulares que llaman la atención se mueven por la pantalla para brindar actualizaciones en tiempo real.

Fragmento de la definición de "titular" en Buscar en Google.
En este punto, usted podría preguntarse por qué lo llamamos específicamente Asesor Experto de “Titulares de noticias”. El término titular se refiere a un resumen breve y destacado de información clave, diseñado para ser visto fácilmente y comprendido rápidamente. En nuestro caso, sirve como una forma compacta de transmitir datos de mercado sensibles al tiempo (por ejemplo, eventos noticiosos o comunicados económicos) en un formato accesible y visualmente atractivo.

El concepto: recuperar datos del calendario económico utilizando la API MQL5 y mostrar los próximos eventos directamente en el gráfico a través de nuestro EA de titulares de noticias personalizado.
Para simplificar esta etapa de desarrollo, comenzaremos centrándonos en dos componentes principales:
- Comprender y utilizar la clase CCanvas en MQL5, que permite realizar dibujos gráficos personalizados en el gráfico.
- Implementación del Calendario Económico MQL5, utilizando funciones integradas para recuperar eventos próximos y mostrarlos usando un efecto de desplazamiento horizontal.
Este diseño de desplazamiento horizontal es intencional: conserva un valioso espacio vertical en el gráfico y ofrece una visualización en línea y no intrusiva de información sensible al tiempo.
Como mejora con visión de futuro, también planeamos integrar una API de noticias externa en iteraciones futuras. Esto nos permitirá mostrar noticias del mercado en tiempo real en una línea de desplazamiento separada debajo de los eventos del calendario. Por ahora, sentaremos las bases insertando un texto de marcador de posición para representar el servicio de noticias.
De un vistazo, un comerciante que utilice este sistema podrá:- Identifique instantáneamente los próximos eventos importantes.
- Vea qué tan pronto ocurrirán (por ejemplo, en horas o minutos).
- Reconocer su nivel de impacto esperado, lo que permite al comerciante adoptar una estrategia más cautelosa o informada.
Habiendo cubierto los conceptos centrales, ahora pasamos a una exploración más profunda de los detalles de implementación.
Implementación
Entendiendo el encabezado de Canvas
La clase CCanvas en MQL5 es una utilidad potente y versátil diseñada para crear y gestionar interfaces gráficas personalizadas y elementos visuales directamente en los gráficos de MetaTrader 5. En esencia, CCanvas permite a los desarrolladores crear superficies de mapas de bits en memoria que se representan a través de objetos de gráficos como OBJ_BITMAP y OBJ_BITMAP_LABEL. Esto permite el dibujo dinámico de contenido gráfico (incluidas líneas, formas, polígonos y texto) sobre los gráficos sin interferir con los elementos nativos del gráfico. La clase proporciona control de bajo nivel sobre la representación a través de un búfer de píxeles (m_pixels[]), junto con funciones como CreateBitmapLabel() para la inicialización y Update() para actualizar la salida.
CCanvas ofrece una potente gestión de recursos: los desarrolladores pueden cargar o guardar mapas de bits, adjuntar o separar lienzos de gráficos y manipular píxeles directamente usando PixelSet() o PixelGet(), lo que lo hace ideal para aplicaciones sensibles al rendimiento. Su flexibilidad se extiende a formatos de color (ARGB, XRGB, con transparencia), representación de polígonos (incluidos rellenos no convexos) e interfaces de gráficos en capas.
En la práctica, CCanvas abre la puerta al desarrollo de una interfaz de usuario sofisticada en MetTrader 5. Se utiliza comúnmente para indicadores personalizados (como superposiciones suavizadas o sombreadas), herramientas interactivas (como líneas de tendencia con límites personalizados), paneles de visualización de operaciones y paneles en gráficos con todas las funciones, botones, controles deslizantes o incluso tickers de noticias desplazables. Aunque la renderización limitada por la CPU lo limita en contextos de resolución ultra alta, su precisión a nivel de píxel y su completa capacidad de personalización lo hacen indispensable para interfaces de gráficos de alta gama.
Comprender el Calendario económico
Cuando se trabaja con el calendario económico de MetaTrader 5, lo primero que hay que entender es que cada evento está vinculado a un país particular (o unión económica) a través de un identificador de país único. En MQL5 esto está representado por la estructura MqlCalendarCountry, que incluye campos como id (el código ISO 3166-1), el nombre del país, el código de dos letras, el código y símbolo de la moneda e incluso el nombre del país compatible con URL. Al consultar la lista de entradas MqlCalendarCountry del calendario una vez, obtendrá acceso a todos los atributos que necesita para filtrar o agrupar eventos por región. Luego, cada evento del calendario hace referencia a su país a través del campo country_id en la estructura MqlCalendarEvent.
Esa estructura en sí describe las características generales de un tipo de evento recurrente: su nombre, importancia, sector de la economía (PIB, empleos, precios, etc.), su periodicidad (diaria, mensual, trimestral) y las unidades en que se informan sus valores. Fundamentalmente, no representa una ocurrencia única sino más bien la “plantilla” o definición de un evento (por ejemplo, “publicación del IPC de EE. UU.”), que el servicio de calendario puede programar muchas veces a lo largo de su historial publicado.
Las ocurrencias programadas reales de esos tipos de eventos (con marcas de tiempo, valores reales y pronosticados y cualquier revisión) se guardan en una tabla separada de estructuras MqlCalendarValue. Cada registro MqlCalendarValue lleva un event_id (que enlaza a la plantilla en MqlCalendarEvent), una hora y un período precisos, además de cuatro campos numéricos (valor_actual, valor_pronóstico, valor_anterior, valor_anterior_revisado) que pueden o no estar completados todavía. Los métodos auxiliares como HasActualValue() y GetActualValue() facilitan la verificación y recuperación de valores del mundo real (escalados automáticamente a partir de la representación interna "ppm" del calendario).
Este diseño relacional (países, tipos de eventos y luego ocurrencias de eventos) garantiza que los datos nunca se dupliquen innecesariamente: las entradas trimestrales del IPC, por ejemplo, apuntan todas a una única definición del IPC que incluye su nivel de importancia, unidades y frecuencia. Al comprender estas estructuras y cómo se relacionan entre sí, podemos filtrar, formatear y mostrar con precisión solo los próximos eventos que nos interesan, al tiempo que mantenemos nuestro código eficiente y mantenible.
El EA de titulares de noticias
Configuración de controles de usuario
Primero, decidimos qué parámetros deberían poder ajustar los traders. Exponemos las velocidades de desplazamiento para cada carril de importancia (InpSpeedHigh, InpSpeedMed, InpSpeedLow), la velocidad del teletipo de noticias (InpNewsSpeed) y el intervalo de cuadros (InpTimerMs). También permitimos que el usuario elija si el ticker se encuentra en la parte superior o inferior (InpPositionTop), a qué distancia debe ubicarse del borde del gráfico (InpTopOffset) y qué carriles mostrar (ShowHigh, ShowMed, ShowLow). Al aislarlos en un bloque ordenado de “Entradas de usuario”, cualquiera puede ajustar rápidamente el comportamiento sin tener que profundizar en los detalles de implementación.
//+------------------------------------------------------------------+ //| 1) USER INPUTS | //+------------------------------------------------------------------+ input int InpSpeedHigh = 4; // px/frame for High-impact lane input int InpSpeedMed = 2; // px/frame for Medium-impact lane input int InpSpeedLow = 1; // px/frame for Low-impact lane input int InpNewsSpeed = 5; // px/frame for news ticker row input int InpTimerMs = 50; // ms between frames (~20 fps) input bool InpPositionTop = true; // true=top, false=bottom input int InpTopOffset = 50; // px offset from chart edge input bool ShowHigh = true; // toggle High lane input bool ShowMed = true; // toggle Medium lane input bool ShowLow = true; // toggle Low lane
Definición de constantes del diseño
A continuación, establecemos reglas de espaciado fijas que rigen el diseño visual: cuántos píxeles separan la etiqueta de tiempo restante del símbolo de moneda (GapTimeToSym), cuánto relleno damos alrededor de nuestro cuadro de importancia en línea (GapSymToRect, GapRectToName) y el tamaño de ese cuadro (RectSize). Al centralizar estos valores, podemos ajustar la apariencia en un solo lugar, en lugar de tener que buscar en el código de dibujo.
//+------------------------------------------------------------------+ //| 2) DEVELOPER CONSTANTS | //+------------------------------------------------------------------+ static const int GapTimeToSym = 10; // px gap after “[1h]” static const int GapSymToRect = 5; // px gap before inline box static const int RectSize = 8; // width & height of inline box static const int GapRectToName= 10; // px gap after inline box
Almacenamiento de estado y búferes de dibujo
Luego declaramos variables globales para contener las dimensiones del gráfico (canvW), la altura de la fila (lineH), el texto de marcador de posición para la línea de noticias y una marca de tiempo para evitar consultas repetidas del calendario (lastReloadDay). También instanciamos dos objetos CCanvas: uno para los tres carriles de eventos y otro para el teletipo de noticias. Finalmente, definimos nuestra clase CEvent y tres matrices dinámicas (highArr, medArr, lowArr) para almacenar eventos de calendario entrantes por importancia. El desplazamiento actual de cada carril (offHigh, etc.) completa el estado que mantenemos mientras se ejecuta el EA.
//+------------------------------------------------------------------+ //| 3) GLOBALS | //+------------------------------------------------------------------+ int lineH = 16; // row height in px int canvW; // chart width string placeholder = // news ticker text "News feed coming soon – stay tuned with the calendar"; datetime lastReloadDay = 0; // daily reload guard CCanvas eventsCanvas, newsCanvas; // two layers // Event struct and arrays class CEvent : public CObject { public: datetime time; string sym, name; int imp; CEvent(datetime t,const string &S,const string &N,int I) { time=t; sym=S; name=N; imp=I; } }; CEvent *highArr[], *medArr[], *lowArr[]; int offHigh, offMed, offLow, offNews;
Ayudantes de posicionamiento y clasificación
Para mantener limpia nuestra lógica principal, factorizamos dos pequeñas funciones auxiliares. SetCanvas() coloca un objeto de lienzo en la parte superior o inferior del gráfico, según la configuración del usuario. SortArr() es un sistema de ordenamiento de burbuja simple que ordena cada matriz de importancia por tiempo de evento, garantizando que nuestros carriles siempre muestren los próximos eventos en la secuencia correcta.
//+------------------------------------------------------------------+ //| Helper: position a canvas label | //+------------------------------------------------------------------+ void SetCanvas(string name,bool top,int yDist) { ObjectSetInteger(0,name,OBJPROP_CORNER, top?CORNER_LEFT_UPPER:CORNER_LEFT_LOWER); ObjectSetInteger(0,name,OBJPROP_XDISTANCE, 0); ObjectSetInteger(0,name,OBJPROP_YDISTANCE, yDist); } //+------------------------------------------------------------------+ //| Helper: sort events by time | //+------------------------------------------------------------------+ void SortArr(CEvent* &arr[]) { int n=ArraySize(arr); for(int i=0;i<n-1;i++) for(int j=i+1;j<n;j++) if(arr[i].time > arr[j].time) { CEvent *tmp=arr[i]; arr[i]=arr[j]; arr[j]=tmp; } }
Obteniendo los eventos de hoy
La función ReloadEvents() es fundamental para la forma en que extraemos y filtramos los datos. Consulta el calendario económico de MetaTrader en busca de eventos programados entre la medianoche de hoy y 24 horas después. Omitimos cualquier evento cuya marca de tiempo ya haya pasado. Cada evento válido se envuelve en un objeto CEvent y luego se coloca en la matriz alta/media/baja según su importancia. Al final, ordenamos cada carril para que el evento más antiguo aparezca primero en el desplazamiento de ese carril.
//+------------------------------------------------------------------+ //| ReloadEvents: load only *future* events for *today* | //+------------------------------------------------------------------+ void ReloadEvents() { datetime srv = TimeTradeServer(); // midnight today MqlDateTime dt; TimeToStruct(srv, dt); MqlDateTime m0 = {dt.year, dt.mon, dt.day,0,0,0}; datetime today = StructToTime(m0); if(today == lastReloadDay) return; lastReloadDay = today; // clear previous for(int i=0;i<ArraySize(highArr);i++) delete highArr[i]; for(int i=0;i<ArraySize(medArr); i++) delete medArr[i]; for(int i=0;i<ArraySize(lowArr); i++) delete lowArr[i]; ArrayResize(highArr,0); ArrayResize(medArr,0); ArrayResize(lowArr,0); // fetch events [today, today+24h) MqlCalendarValue vals[]; int cnt = CalendarValueHistory(vals, today, today+86400); for(int i=0;i<cnt;i++) { if(vals[i].time <= srv) continue; // skip past MqlCalendarEvent e; if(!CalendarEventById(vals[i].event_id, e)) continue; MqlCalendarCountry c; if(!CalendarCountryById(e.country_id, c)) continue; string sym = "[" + c.currency + "]"; CEvent *ev = new CEvent(vals[i].time, sym, e.name, e.importance); // classify if(e.importance==CALENDAR_IMPORTANCE_HIGH) { int s=ArraySize(highArr)+1; ArrayResize(highArr,s); highArr[s-1]=ev; } else if(e.importance==CALENDAR_IMPORTANCE_MODERATE) { int s=ArraySize(medArr)+1; ArrayResize(medArr,s); medArr[s-1]=ev; } else { int s=ArraySize(lowArr)+1; ArrayResize(lowArr,s); lowArr[s-1]=ev; } } SortArr(highArr); SortArr(medArr); SortArr(lowArr); }
En concreto, cuando se ejecuta ReloadEvents(), obtiene una lista completa de las entradas del calendario de hoy a través de CalendarValueHistory(), pero cada entrada sin procesar solo nos indica un event_id y un country_id. Al unirnos a quienes se oponen a la tabla MqlCalendarEvent, en la que cada tipo de evento se define con su nombre, frecuencia, sector y, lo que es más importante, su importancia, podemos presentar solo los elementos que realmente influyen en el mercado. La estructura MqlCalendarCountry garantiza que etiquetemos cada título con la moneda correcta (por ejemplo, [USD] para Estados Unidos), extraída de su código ISO y símbolo. Esta búsqueda de dos pasos (valor → tipo de evento → país) hace que nuestro EA aprenda (extrayendo solo lo necesario) y sea preciso, ya que nunca codificamos detalles de países o eventos, sino que confiamos en la base de datos sincronizada constantemente de MetaTrader.
Las constantes de importancia (CALENDAR_IMPORTANCE_HIGH, ..._MODERATE, ..._LOW) se encuentran en el corazón de nuestra lógica de carriles. Al seleccionar los niveles de importancia que se incluirán (ShowHigh/ShowMed/ShowLow) y colorear cada cuadro en línea en rojo, naranja o blanco, le damos al operador una señal visual inmediata: el rojo indica los datos de mayor impacto (como las decisiones de la Fed sobre los tipos de interés o las nóminas no agrícolas), el naranja los de impacto medio (IPC, ventas minoristas) y el blanco los de menor impacto (discursos menores, datos de menor importancia).
En la práctica, esto ayuda al operador a evaluar de un vistazo si necesita ajustar los stops o incluso pausar las estrategias automatizadas a medida que se acerca un evento de gran importancia. Sin ese filtro y el etiquetado codificado por colores, impulsado por el campo de importancia en MqlCalendarEvent, una lista desplazable con docenas de entradas se convertiría rápidamente en ruido en lugar de señal.
Representación de un carril de desplazamiento
DrawLane() encapsula la lógica para una franja horizontal. Elegimos una fuente monoespaciada (“Courier New”) para que cada carácter, incluidos corchetes y dígitos, tenga el mismo ancho, lo que garantiza una alineación perfecta. Luego dibujamos:
- Etiqueta de tiempo restante (horas o minutos).
- Símbolo de moneda.
- Cuadro de importancia en línea (de color rojo/naranja/blanco).
- Nombre del evento, seguido de un separador si siguen más eventos.
Por último, reducimos el desplazamiento del carril según la velocidad del carril y, si toda la fila se ha desplazado fuera del borde izquierdo, la volvemos a envolver hacia la derecha.
//+------------------------------------------------------------------+ //| DrawLane: scroll one lane with inline importance box | //+------------------------------------------------------------------+ void DrawLane(CEvent* &arr[], int &offset, int y, int speed) { int n=ArraySize(arr); if(n==0) return; // monospaced for alignment eventsCanvas.FontNameSet("Courier New"); eventsCanvas.FontSizeSet(-100); int x = offset; datetime srv = TimeTradeServer(); for(int i=0;i<n;i++) { CEvent *e = arr[i]; // time-left “[1h]” or “[45m]” long diff = (long)e.time - (long)srv; string tl = (diff>=3600 ? IntegerToString(diff/3600)+"h" : IntegerToString(diff/60)+"m"); string part = "[" + tl + "]"; eventsCanvas.TextOut(x,y,part,XRGB(255,255,255),ALIGN_LEFT); x += eventsCanvas.TextWidth(part) -20; // symbol “[USD]” eventsCanvas.TextOut(x,y,e.sym,XRGB(255,255,255),ALIGN_RIGHT); x += eventsCanvas.TextWidth(e.sym) + GapSymToRect; // inline importance box uint col = (e.imp==CALENDAR_IMPORTANCE_HIGH ? XRGB(255,0,0) : e.imp==CALENDAR_IMPORTANCE_MODERATE? XRGB(255,165,0): XRGB(255,255,255)); eventsCanvas.FillRectangle(x, y + (lineH-RectSize)/2, x+RectSize, y + (lineH-RectSize)/2 + RectSize, col); x += RectSize + GapRectToName; // event name + separator eventsCanvas.TextOut(x,y,e.name,XRGB(255,255,255),ALIGN_RIGHT); x += eventsCanvas.TextWidth(e.name)+60; if(i+1<n) { eventsCanvas.TextOut(x,y,"|",XRGB(180,180,180),ALIGN_RIGHT); x += eventsCanvas.TextWidth("|") + 20; } } // scroll + wrap int totalW = x - offset; offset -= speed; if(offset + totalW < 0) offset = canvW; }
Orquestando todos los carriles y la fila de noticias
En DrawAll(), colocamos las tres líneas de eventos en capas verticalmente y, a continuación, el marcador de posición de noticias debajo (o encima, dependiendo de la posición). Después de dibujar eventos en eventsCanvas, llamamos a Update(false) para enviarlos al objeto gráfico. La barra de noticias utiliza su propio newsCanvas, con un dibujo más sencillo solo de texto seguido de Update(true) para actualizar de forma sincrónica.
//+------------------------------------------------------------------+ //| DrawAll: render lanes + news row | //+------------------------------------------------------------------+ void DrawAll() { // clear events eventsCanvas.Erase(ARGB(180,0,0,0)); int y=0; if(ShowHigh) { DrawLane(highArr, offHigh, y, InpSpeedHigh); y += lineH; } if(ShowMed) { DrawLane(medArr, offMed, y, InpSpeedMed); y += lineH; } if(ShowLow) { DrawLane(lowArr, offLow, y, InpSpeedLow); y += lineH; } eventsCanvas.Update(false); // news placeholder newsCanvas.Erase(ARGB(170,0,0,0)); newsCanvas.FontNameSet("Tahoma"); newsCanvas.FontSizeSet(-120); int yOff = (lineH - newsCanvas.TextHeight(placeholder)) / 2; newsCanvas.TextOut(offNews, yOff, placeholder, XRGB(255,255,255), ALIGN_LEFT); offNews -= InpNewsSpeed; if(offNews + newsCanvas.TextWidth(placeholder) < -20) offNews = canvW; newsCanvas.Update(true); }
Inicialización, temporizador y limpieza
Por último, en OnInit() creamos y configuramos nuestros lienzos, llamamos a ReloadEvents() por primera vez, establecemos todos los desplazamientos en canvW y posicionamos los dos lienzos basándonos en InpPositionTop e InpTopOffset. A continuación, dibujamos el primer fotograma y ponemos en marcha el temporizador de milisegundos.
OnTimer() simplemente reposiciona los lienzos (para que los usuarios puedan voltear InpPositionTop en vivo), recarga los eventos una vez al día, ajusta el tamaño del gráfico y vuelve a llamar a DrawAll(). OnDeinit() limpia los lienzos y elimina cualquier objeto CEvent asignado.
//+------------------------------------------------------------------+ //| OnInit: setup canvases, initial load & position | //+------------------------------------------------------------------+ int OnInit() { // force reload Today lastReloadDay = 0; // clear arrays ArrayResize(highArr,0); ArrayResize(medArr,0); ArrayResize(lowArr,0); // chart width canvW = (int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS); // create events canvas (4 rows tall) eventsCanvas.CreateBitmapLabel("EvCanvas",0,0,canvW,4*lineH,COLOR_FORMAT_ARGB_RAW); eventsCanvas.TransparentLevelSet(150); // create news canvas (1 row tall) newsCanvas.CreateBitmapLabel("NwCanvas",0,0,canvW,lineH,COLOR_FORMAT_ARGB_RAW); newsCanvas.TransparentLevelSet(0); // load data + init offsets ReloadEvents(); offHigh = offMed = offLow = offNews = canvW; // initial positioning { int rows = (ShowHigh?1:0)+(ShowMed?1:0)+(ShowLow?1:0); int yOff = InpTopOffset + (InpPositionTop ? 0 : rows*lineH); SetCanvas("EvCanvas", InpPositionTop, InpTopOffset); SetCanvas("NwCanvas", InpPositionTop, yOff + (InpPositionTop ? rows*lineH : 0)); } // first draw & timer DrawAll(); EventSetMillisecondTimer(InpTimerMs); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| OnTimer: reposition, daily reload, redraw | //+------------------------------------------------------------------+ void OnTimer() { // reposition every tick int rows = (ShowHigh?1:0)+(ShowMed?1:0)+(ShowLow?1:0); if(InpPositionTop) { SetCanvas("EvCanvas", true, InpTopOffset); SetCanvas("NwCanvas", true, InpTopOffset + rows*lineH); } else { SetCanvas("EvCanvas", false, InpTopOffset); SetCanvas("NwCanvas", false, InpTopOffset + lineH); } // reload once per day ReloadEvents(); // adapt width int wNew = (int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS); if(wNew != canvW) { canvW = wNew; ObjectSetInteger(0,"EvCanvas",OBJPROP_WIDTH,canvW); ObjectSetInteger(0,"NwCanvas",OBJPROP_WIDTH,canvW); } // redraw DrawAll(); } //+------------------------------------------------------------------+ //| OnDeinit: cleanup | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { EventKillTimer(); eventsCanvas.Destroy(); ObjectDelete(0,"EvCanvas"); newsCanvas.Destroy(); ObjectDelete(0,"NwCanvas"); for(int i=0;i<ArraySize(highArr);i++) delete highArr[i]; for(int i=0;i<ArraySize(medArr); i++) delete medArr[i]; for(int i=0;i<ArraySize(lowArr); i++) delete lowArr[i]; }
Con esta etapa completada, ahora podemos proceder a probar nuestro código en el gráfico. Durante el desarrollo, resolví muchos de los errores de compilación, dando como resultado una versión final limpia y bien estructurada. Al compilar los componentes anteriores, ahora tenemos un EA de titulares de noticias completamente funcional listo para implementarse en el gráfico. Explora mi experiencia de pruebas en la siguiente sección.
Pruebas
En la terminal MetaTrader 5, navegue hasta la sección Asesores Expertos y arrastre el EA News Headline EA.mq5 al gráfico. Una vez agregado correctamente, el EA aparece de forma predeterminada en la parte superior del gráfico con un desplazamiento vertical de 50 píxeles. Este desplazamiento evita que se superponga a los botones de Profundidad de mercado y Panel de comercio, así como al nombre del EA en la esquina superior derecha.
Puede ajustar este desplazamiento para posicionar el lienzo del título en cualquier ubicación vertical deseada en el gráfico. EA cuenta con cuatro carriles, cada uno de ellos capaz de alcanzar una velocidad máxima optimizada y funcionar a una velocidad de cuadros de 20 FPS. Los próximos eventos noticiosos se muestran en rectángulos codificados por colores que indican su nivel de importancia.

Prueba del EA
La imagen de arriba muestra una implementación exitosa del EA. Aparece como estaba previsto, mostrando todos los próximos eventos noticiosos con una animación fluida y sin interrupciones.
Conclusión
Esto marca el final de otra interesante discusión sobre desarrollo, que culmina en una herramienta práctica y reveladora tanto para comerciantes como para desarrolladores. Aprovechamos con éxito el poder de la clase Canvas para lograr una representación eficiente y claridad visual, un enfoque que también sirve como un valioso atajo en el desarrollo de interfaces.
A lo largo de este proyecto, aprendimos cómo recuperar datos del calendario económico y mostrarlos en un formato significativo y amigable para los comerciantes. El resultado es una vista limpia y minimalista de los próximos eventos noticiosos, directamente en el gráfico, lo que resuelve un desafío de larga data en las herramientas de negociación basadas en noticias.
De cara al futuro, la segunda versión de este EA incorporará acceso API para feeds de noticias en tiempo real, lo que permitirá actualizaciones aún más dinámicas. Además, el Canvas se puede reutilizar para mostrar otros datos relevantes para el trading, lo que hace que este enfoque sea muy versátil.
Con noticias de alto impacto claramente visibles en el gráfico, los operadores pueden tomar decisiones mejor informadas, eligiendo si participar en el mercado o permanecer al margen. Como práctica recomendada, generalmente se recomienda evitar operar unas horas antes y después de los comunicados de prensa más importantes para reducir el riesgo y evitar picos de volatilidad.
Eres bienvenido a compartir tus pensamientos o hacer preguntas en la sección de comentarios. También puedes encontrar los archivos adjuntos justo debajo de este artículo.
| Nombre del archivo | Descripción |
|---|---|
| NewsTicker.mq5 | Fuente principal del Asesor Experto que implementa el calendario económico desplazable de tres carriles y el ticker de marcador de posición de noticias directamente en el gráfico usando la clase CCanvas, con velocidades por carril, cuadros de importancia en línea y cuentas regresivas en tiempo real. |
Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/18299
Advertencia: todos los derechos de estos materiales pertenecen a MetaQuotes Ltd. Queda totalmente prohibido el copiado total o parcial.
Este artículo ha sido escrito por un usuario del sitio web y refleja su punto de vista personal. MetaQuotes Ltd. no se responsabiliza de la exactitud de la información ofrecida, ni de las posibles consecuencias del uso de las soluciones, estrategias o recomendaciones descritas.
Utilizando redes neuronales en MetaTrader
Introducción a MQL5 (Parte 17): Creación de asesores expertos para reversiones de tendencias
Particularidades del trabajo con números del tipo double en MQL4
Modelo matricial de pronóstico basado en cadenas de Márkov
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso