English Русский 中文 Español Deutsch 日本語
preview
Do iniciante ao especialista: criação de um EA animado para notícias em MQL5 (I)

Do iniciante ao especialista: criação de um EA animado para notícias em MQL5 (I)

MetaTrader 5Exemplos |
42 0
Clemence Benjamin
Clemence Benjamin

Sumário:


Introdução

Hoje, buscamos eliminar uma limitação comum no acesso a notícias econômicas e eventos do calendário econômico no terminal MetaTrader 5, especialmente durante a análise de gráficos ativos.

No terminal MetaTrader 5, as abas "Notícias" (News) e "Calendário Econômico" (Economic Calendar) ficam disponíveis na janela Caixa de Ferramentas. Essas abas apresentam informações importantes obtidas de provedores de notícias confiáveis. No entanto, é muito importante entender a diferença entre elas:

  • Aba "Notícias": exibe manchetes e atualizações que já foram publicadas.
  • "Calendário Econômico": contém a programação dos próximos eventos econômicos, distribuídos por data, horário e importância, o que é útil para o planejamento futuro.

As duas ferramentas são essenciais para a análise de mercado. Traders experientes sabem que algumas notícias econômicas, como decisões sobre taxas de juros ou dados de emprego fora do setor agrícola, podem afetar significativamente o mercado. Com a preparação adequada, esses eventos abrem oportunidades lucrativas de negociação. No entanto, eles também envolvem risco considerável quando o resultado diverge do cenário esperado.

Accessing News and Calendar on MetaTrader 5

Acesso às notícias e ao Calendário Econômico no MetaTrader 5

Na captura de tela publicada anteriormente, é possível observar que o MetaTrader 5 oferece acesso tanto às "Notícias" quanto ao Calendário Econômico em um único ambiente integrado. No entanto, uma limitação importante se torna evidente: para visualizar qualquer uma dessas funções, o usuário precisa acessar manualmente a janela Caixa de Ferramentas.

Dentro da Caixa de Ferramentas, as informações são apresentadas em forma de tabela, com linhas e colunas que mostram diferentes notícias, eventos programados e seus respectivos detalhes. Os usuários podem percorrer o feed de notícias para ler as manchetes ou consultar o calendário para visualizar as próximas divulgações econômicas. Embora a Caixa de Ferramentas possa ser expandida para exibir mais conteúdo, isso reduz o tamanho da janela do gráfico, o que pode prejudicar a visualização do movimento do preço, dos indicadores ou dos objetos gráficos.

A solução que propomos elimina essa limitação ao exibir manchetes de notícias e eventos do Calendário Econômico diretamente no gráfico, preservando a visibilidade total, sem invadir a área do gráfico e sem interferir nos objetos de negociação. O objetivo é melhorar o acesso à informação e a consciência situacional, preservando ao mesmo tempo um ambiente gráfico limpo e funcional.

Nesta seção introdutória da nossa minissérie, vou começar me concentrando na implementação do Calendário Econômico do MQL5 para exibir manchetes dos próximos eventos do calendário. A solução se inspira na forma como manchetes costumam aparecer na parte inferior da tela da televisão e também no modo como anúncios são exibidos em vídeos de redes sociais.

Na seção seguinte, apresentaremos a abordagem que será usada para criar o EA "Manchetes de Notícias" usando MQL5. Vamos apresentar a estratégia de desenvolvimento, examinar as principais decisões de implementação e, em seguida, analisar a base de código em detalhes.

Por fim, na conclusão, apresentaremos os resultados dos testes e as observações, oferecendo uma visão completa do ciclo de desenvolvimento desse sistema de exibição de notícias em tempo real no MetaTrader 5.


Conceito

Para dar vida a essa ideia, usaremos a Biblioteca Padrão do MQL5, que fornece ferramentas confiáveis para o desenvolvimento de interface gráfica. Especificamente, usaremos a classe CCanvas, localizada no arquivo MQL5\Include\Canvas\Canvas.mqh. Essa classe nos permite criar superfícies gráficas retangulares e transparentes, ideais para sobrepor conteúdo dinâmico, como manchetes de notícias e atualizações de eventos econômicos, diretamente no gráfico.

Nossa implementação se baseia em uma faixa rolante de notícias, que exibe continuamente informações relevantes sem atrapalhar a análise dos gráficos. Esse conceito vem de interfaces reais vistas em telejornais, sites financeiros e até mesmo em conteúdos de vídeo de redes sociais, onde manchetes chamativas se movem pela tela, fornecendo atualizações em tempo real.

Fragmento da definição de manchete da Google search.

Neste ponto, você pode estar se perguntando por que chamamos especificamente este EA de "Manchetes de Notícias". O termo "manchete" se refere a um título curto e visualmente destacado que resume as informações principais, concebido para ser fácil de ver e rápido de entender. No nosso caso, trata-se de uma forma compacta de transmitir dados de mercado relevantes, como notícias ou divulgações econômicas, em um formato acessível e visualmente atraente.

The news headline concept

Conceito: extrair dados do Calendário Econômico usando a API MQL5 e exibir os próximos eventos diretamente no gráfico com a ajuda do nosso EA personalizado "Manchetes de Notícias".

Para simplificar esta etapa do desenvolvimento, começaremos nos concentrando em dois componentes principais:

  • Entender e usar a classe CCanvas em MQL5, o que permite desenhar elementos gráficos personalizados no gráfico.
  • Implementar o Calendário Econômico do MQL5 usando funções nativas para buscar eventos futuros e exibi-los com um efeito de rolagem horizontal.

Esse formato de rolagem horizontal foi concebido especificamente para preservar espaço vertical valioso no gráfico e fornecer uma exibição integrada e discreta das informações relevantes.

Como aprimoramento futuro, também planejamos integrar uma API externa de notícias. Isso nos permitirá exibir notícias do mercado em tempo real em uma faixa rolante separada abaixo dos eventos do calendário. Por enquanto, vamos estabelecer a base inserindo um indicador placeholder para representar o feed de notícias.

Em um primeiro momento, o trader que usar esse sistema poderá:
  • Identificar instantaneamente eventos importantes futuros.
  • Acompanhar quanto tempo falta para que eles ocorram, por exemplo, em horas ou minutos.
  • Reconhecer o nível esperado de impacto, o que permite ao trader adotar uma estratégia mais cautelosa ou mais bem fundamentada.

Depois de examinar os principais conceitos, passamos a analisar com mais detalhes a implementação.


Implementação

Dominando a manchete com Canvas

A classe CCanvas em MQL5 é um utilitário poderoso e versátil, projetado para criar interfaces gráficas personalizadas e elementos visuais diretamente nos gráficos do MetaTrader 5, bem como gerenciá-los. Em sua essência, a CCanvas permite que os desenvolvedores criem superfícies de bitmap na memória, que são exibidas por meio de objetos do gráfico, como OBJ_BITMAP e OBJ_BITMAP_LABEL. Isso permite exibir dinamicamente conteúdo gráfico, incluindo linhas, formas, polígonos e texto, sobre os gráficos, sem interferir no funcionamento dos elementos nativos do gráfico. A classe oferece controle de baixo nível sobre a renderização por meio do buffer de pixels (m_pixels[]), além de funções como CreateBitmapLabel() para inicialização e Update() para atualizar a saída visual.

 CCanvas oferece gestão eficiente de recursos: os desenvolvedores podem carregar ou salvar imagens bitmap, vincular ou desvincular áreas Canvas dos gráficos e manipular pixels diretamente com PixelSet() ou PixelGet(), o que a torna ideal para aplicações sensíveis ao desempenho. Sua flexibilidade se estende aos formatos de cor (ARGB, XRGB com transparência), à renderização de polígonos (incluindo preenchimentos não convexos) e a interfaces gráficas multicamadas.

Na prática, CCanvas abre caminho para o desenvolvimento sofisticado de interfaces personalizadas no MetaTrader 5. Ela é comumente usada para criar indicadores personalizados, como sobreposições suavizadas ou sombreadas, ferramentas interativas, como linhas de tendência com extremidades personalizadas, painéis de visualização de trading e painéis gráficos completos com botões, controles deslizantes ou até mesmo uma faixa rolante de notícias. Embora a renderização limitada à CPU restrinja os recursos gráficos em cenários de resolução extremamente alta, a precisão em nível de pixel e a personalização completa a tornam indispensável para interfaces gráficas avançadas.

Dominando a aba Calendário Econômico

Ao trabalhar com o Calendário Econômico do MetaTrader 5, a primeira coisa a entender é que cada evento está vinculado a um país específico (ou a uma união econômica) por meio de um identificador único de país. Em MQL5, isso é representado pela estrutura MqlCalendarCountry, que inclui campos como id (código ISO 3166-1), nome do país, código de duas letras, código e símbolo da moeda, e até um nome do país adequado para URL. Ao consultar uma única vez a lista de registros MqlCalendarCountry no Calendário Econômico, você obtém acesso a todos os atributos necessários para filtrar ou agrupar eventos por região. Em seguida, cada evento do Calendário Econômico faz referência ao seu país por meio do campo country_id na estrutura MqlCalendarEvent.

Essa estrutura descreve as características gerais de um tipo de evento recorrente: seu nome, importância, setor da economia (PIB, mercado de trabalho, preços etc.), periodicidade (diária, mensal, trimestral) e as unidades de medida em que seus valores são apresentados. É importante observar que ela não representa uma ocorrência isolada, mas sim um "modelo" ou uma definição de evento, por exemplo, "divulgação do índice de preços ao consumidor dos EUA", que o serviço do Calendário Econômico pode programar várias vezes ao longo do histórico publicado.

As ocorrências efetivamente programadas desses tipos de evento, com timestamps, valores divulgados e previstos, além de eventuais revisões, são armazenadas em uma tabela separada de estruturas MqlCalendarValue. Cada registro MqlCalendarValue contém event_id (referência ao modelo em MqlCalendarEvent), o horário e o período exatos, além de quatro campos numéricos (actual_value, forecast_value, prev_value, revised_prev_value), que podem já estar preenchidos ou ainda não. Métodos auxiliares, como HasActualValue() e GetActualValue(), simplificam a verificação e a extração dos valores divulgados, automaticamente escalonados a partir da representação interna em "ppm" usada pelo calendário.

Essa estrutura relacional, composta por países, tipos de evento e seus respectivos valores, garante que os dados nunca sejam duplicados sem necessidade: por exemplo, todos os registros trimestrais do índice de preços ao consumidor apontam para uma única definição desse índice, que contém o nível de importância, as unidades de medida e a frequência. Ao entender essas estruturas e como elas se relacionam entre si, podemos filtrar, formatar e exibir com precisão apenas os próximos eventos que nos interessam, mantendo ao mesmo tempo a eficiência e a facilidade de manutenção do nosso código.

EA "Manchetes de Notícias"

Configuração de controles personalizados

Primeiro, decidimos quais parâmetros os traders devem poder configurar. Expomos a velocidade de rolagem de cada faixa de importância (InpSpeedHigh, InpSpeedMed, InpSpeedLow), a velocidade de rolagem de notícias (InpNewsSpeed) e o intervalo entre quadros (InpTimerMs). Também permitimos que o usuário escolha se o ticker ficará na parte superior ou inferior (InpPositionTop), a que distância ele deve ficar da borda do gráfico (InpTopOffset) e quais faixas serão exibidas (ShowHigh, ShowMed, ShowLow). Ao reunir tudo isso em um bloco organizado de "Entradas do usuário" (User Inputs), qualquer pessoa pode ajustar rapidamente o comportamento sem precisar entrar nos detalhes da implementação.

//+------------------------------------------------------------------+
//| 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

Definição das constantes de layout

Em seguida, definimos as regras de espaçamento fixo que determinam o layout visual: quantos pixels separam o rótulo com o tempo restante do da sigla da moeda (GapTimeToSym), quais espaçamentos mantemos ao redor de nossa caixa de importância integrada (GapSymToRect, GapRectToName) e o tamanho desse campo (RectSize). Ao agrupar esses valores, podemos ajustar com precisão a aparência em um único lugar, em vez de alterar a rotina de desenho.

//+------------------------------------------------------------------+
//| 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

Preservação do estado e dos buffers de renderização

Em seguida, declaramos variáveis globais para armazenar as dimensões do gráfico (canvW), a altura da linha (lineH), o texto de preenchimento da faixa de notícias e o timestamp usado para evitar consultas repetidas ao Calendário Econômico (lastReloadDay). Também instanciamos dois objetos CCanvas, um para as três faixas de eventos e outro para a faixa rolante de notícias. Por fim, definimos nossa classe CEvent e três arrays dinâmicos (highArr, medArr, lowArr) para armazenar os eventos recebidos do Calendário Econômico por importância. O deslocamento atual de rolagem de cada faixa (offHigh etc.) define o estado que mantemos durante a execução do 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;

Funções auxiliares de posicionamento e ordenação

Para manter nossa lógica principal limpa, separamos duas pequenas funções auxiliares. A função SetCanvas() posiciona o objeto canvas na parte superior ou inferior do gráfico, de acordo com as configurações do usuário. SortArr() é um bubble sort simples que organiza cada array de importância pelo horário do evento, garantindo que nossas faixas sempre exibam os próximos eventos na sequência correta.

//+------------------------------------------------------------------+
//| 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;
      }
}

Obtenção dos eventos de hoje

A função ReloadEvents() ocupa uma posição central na forma como extraímos e filtramos os dados. Ela consulta o Calendário Econômico do MetaTrader em busca de eventos programados da meia-noite de hoje até 24 horas depois. Ignoramos qualquer evento cujo timestamp já tenha ficado para trás. Cada evento válido é empacotado em um objeto CEvent e depois colocado no array high/medium/low de acordo com sua importância. No final, ordenamos cada faixa para que o evento mais próximo apareça primeiro na rolagem dessa faixa.

//+------------------------------------------------------------------+
//| 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);
}

Em mais detalhes, quando a função ReloadEvents() é executada, ela extrai a lista completa dos registros de hoje do Calendário Econômico por meio de CalendarValueHistory(), mas cada registro bruto informa apenas event_id e country_id. Ao combiná-los com a tabela MqlCalendarEvent, na qual cada tipo de evento contém seu nome, frequência, setor e, acima de tudo, sua importância, podemos apresentar apenas os eventos realmente relevantes para o mercado. A estrutura MqlCalendarCountry garante que rotulemos cada manchete com a moeda correta, por exemplo, [USD] para os Estados Unidos, com base em seu código ISO e símbolo. Essa busca em duas etapas (valor → tipo de evento → país) permite que nosso EA se atualize rapidamente, extraindo apenas o necessário, e seja preciso, já que nunca deixamos informações sobre país ou evento fixas no código, mas confiamos no próprio banco de dados do MetaTrader, mantida constantemente sincronizada.

As constantes de importância (CALENDAR_IMPORTANCE_HIGH, ..._MODERATE, ..._LOW) formam a base da nossa lógica de montagem das faixas. Ao escolher os níveis de importância que serão incluídos (ShowHigh/ShowMed/ShowLow) e colorir cada caixa de importância integrada em vermelho, laranja ou branco, damos ao trader um sinal visual imediato: em vermelho, marcamos as divulgações de maior impacto, por exemplo, decisões do Fed sobre taxas de juros e dados de emprego fora do setor agrícola; em laranja, as divulgações de impacto médio, como Índice de Preços ao Consumidor e vendas no varejo; e, em branco, as menos importantes, como pronunciamentos de menor relevância e dados de menor relevância.

Na prática, isso ajuda o trader a identificar imediatamente se precisa aumentar a distância dos stops ou até pausar estratégias automáticas conforme um evento importante se aproxima. Sem esse filtro e essa marcação por cor, baseada no campo de importância em MqlCalendarEvent, uma lista em rolagem com dezenas de registros rapidamente se transformaria em ruído, e não em sinal.

Renderização da faixa de rolagem

DrawLane() encapsula a lógica de uma única faixa horizontal. Escolhemos uma fonte monoespaçada ("Courier New") para que todos os caracteres, incluindo colchetes e números, tenham a mesma largura, garantindo um alinhamento limpo. Em seguida, desenhamos:

  1. Rótulo do tempo restante (horas ou minutos).
  2. Símbolo da moeda.
  3. Caixa de importância integrada (colorida em vermelho/laranja/branco).
  4. Nome do evento, seguido de um separador caso haja outros eventos depois dele.

Por fim, reduzimos o deslocamento da faixa pelo valor da velocidade da faixa e, se a linha inteira já tiver passado pela borda esquerda, nós a reposicionamos à direita.

//+------------------------------------------------------------------+
//| 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;
}

Montagem de todas as faixas e da linha de notícias

Em DrawAll(), posicionamos verticalmente as três faixas de eventos e depois colocamos o texto de preenchimento de notícias abaixo delas (ou acima, dependendo da posição). Depois de exibir os eventos em eventsCanvas, chamamos a função Update(false) para atualizar o conteúdo no objeto gráfico. O feed de notícias usa seu próprio newsCanvas, com uma exibição mais simples apenas de texto, seguida de Update(true) para atualização síncrona.

//+------------------------------------------------------------------+
//| 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);
}

Inicialização, timer e limpeza

Por fim, em OnInit(), criamos e configuramos nossos objetos Canvas, chamamos ReloadEvents() pela primeira vez, definimos todos os deslocamentos como canvW e posicionamos os dois canvases com base em InpPositionTop e InpTopOffset. Em seguida, desenhamos o primeiro quadro e iniciamos o timer em milissegundos. 

OnTimer() apenas reposiciona os canvases (para que os usuários possam alternar InpPositionTop em tempo real), recarrega os eventos uma vez por dia, ajusta o tamanho do gráfico e chama DrawAll() novamente. OnDeinit() limpa os canvases e remove todos os objetos CEvent alocados.

//+------------------------------------------------------------------+
//| 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];
}

Com esta etapa concluída, podemos começar a testar nosso código no gráfico. Durante o desenvolvimento, corrigi muitos erros de compilação, resultando em uma versão final limpa e bem estruturada. Depois de compilar os componentes listados acima, obtivemos um EA "Manchetes de Notícias" totalmente funcional, pronto para ser anexado ao gráfico. Veja minha experiência de teste na próxima seção.


Testes

No terminal MetaTrader 5, acesse a seção "EAs" e arraste o EA "Manchetes de Notícias" para o gráfico. Após ser adicionado com sucesso, o EA é exibido por padrão na parte superior do gráfico, com um deslocamento vertical de 50 pixels. Esse deslocamento evita a sobreposição dos botões Depth of Market (Book de Ofertas) e Trade Panel (painel de negociação), bem como do nome do EA no canto superior direito.

Você pode ajustar esse deslocamento para posicionar a área Canvas das manchetes em qualquer posição vertical desejada no gráfico. O EA conta com quatro faixas, cada uma com uma velocidade otimizada para a visualização das manchetes e operando a 20 quadros por segundo. As próximas notícias são exibidas como retângulos coloridos, indicando seu grau de importância.

Testing the News Headline EA.mq5

Teste do News Headline EA.mq5

A imagem acima mostra a anexação bem-sucedida do EA "Manchetes de Notícias". Ele aparece exatamente como planejado, exibindo todas as próximas notícias com uma animação suave e fluida.


Conclusão

Com isso, encerramos mais uma etapa empolgante de desenvolvimento, que culminou em uma ferramenta prática e útil tanto para traders quanto para desenvolvedores. Conseguimos usar os recursos da classe Canvas para obter renderização eficiente e clareza visual, uma abordagem que também simplifica o desenvolvimento de interfaces.

Ao longo deste projeto, aprendemos a extrair dados do Calendário Econômico e exibi-los em um formato compreensível para o trader. O resultado é uma exibição clara e minimalista das próximas notícias diretamente no gráfico, ajudando a resolver um problema antigo das ferramentas de negociação orientadas por notícias.

Olhando adiante, a segunda versão deste EA implementará o acesso a uma API para obter notícias em tempo real, permitindo atualizações ainda mais dinâmicas. Além disso, o Canvas pode ser reaproveitado para exibir outros dados relevantes para a negociação, o que torna essa abordagem bastante versátil.

Com as notícias importantes claramente visíveis no gráfico, os traders podem tomar decisões mais bem fundamentadas, escolhendo se desejam participar do mercado ou permanecer de fora. Como boa prática, geralmente recomenda-se evitar negociar algumas horas antes e depois da divulgação de notícias importantes, para reduzir o risco e evitar picos bruscos de volatilidade.

Compartilhe suas ideias ou faça perguntas na seção de comentários abaixo. Você também pode encontrar os arquivos anexados logo abaixo deste artigo.

Nome do arquivo Descrição
NewsTicker.mq5 Código-fonte principal do EA, que implementa o Calendário Econômico com rolagem em três faixas e um ticker de notícias de preenchimento diretamente no gráfico usando a classe CCanvas, com velocidade individual por faixa, caixas de importância integradas e contagem regressiva em tempo real.

Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/18299

Arquivos anexados |
Caminhe em novos trilhos: Personalize indicadores no MQL5 Caminhe em novos trilhos: Personalize indicadores no MQL5
Vou agora listar todas as possibilidades novas e recursos do novo terminal e linguagem. Elas são várias, e algumas novidades valem a discussão em um artigo separado. Além disso, não há códigos aqui escritos com programação orientada ao objeto, é um tópico muito importante para ser simplesmente mencionado em um contexto como vantagens adicionais para os desenvolvedores. Neste artigo vamos considerar os indicadores, sua estrutura, desenho, tipos e seus detalhes de programação em comparação com o MQL4. Espero que este artigo seja útil tanto para desenvolvedores iniciantes quanto para experientes, talvez alguns deles encontrem algo novo.
Desenvolvimento de um sistema personalizado de detecção do regime de mercado em MQL5 (Parte 1): Indicador Desenvolvimento de um sistema personalizado de detecção do regime de mercado em MQL5 (Parte 1): Indicador
Este artigo descreve em detalhes a criação de um sistema de detecção do regime de mercado em MQL5 usando métodos estatísticos, como autocorrelação e volatilidade. O artigo apresenta o código de classes capazes de classificar condições de tendência, de range e de mercado volátil, bem como um indicador personalizado.
Está chegando o novo MetaTrader 5 e MQL5 Está chegando o novo MetaTrader 5 e MQL5
Esta é apenas uma breve resenha do MetaTrader 5. Eu não posso descrever todos os novos recursos do sistema por um período tão curto de tempo - os testes começaram em 09.09.2009. Esta é uma data simbólica, e tenho certeza que será um número de sorte. Alguns dias passaram-se desde que eu obtive a versão beta do terminal MetaTrader 5 e MQL5. Eu ainda não consegui testar todos os seus recursos, mas já estou impressionado.
Transferência de dados de ticks do MetaTrader para Python via sockets usando serviços MQL5 Transferência de dados de ticks do MetaTrader para Python via sockets usando serviços MQL5
Às vezes, nem tudo pode ser implementado em MQL5. Mesmo que seja possível converter bibliotecas modernas já disponíveis para MQL5, isso levará muito tempo. Neste artigo, tentaremos contornar a dependência do Windows com o uso de serviços MQL5, transmitindo dados de ticks (bid, ask e time) para uma aplicação Python por meio de sockets.