English Русский 中文 Español Deutsch 日本語
preview
Do iniciante ao especialista: Criando um EA animado de notícias em MQL5 (IX) - Gerenciamento de múltiplos símbolos em um único gráfico para negociação baseada em notícias

Do iniciante ao especialista: Criando um EA animado de notícias em MQL5 (IX) - Gerenciamento de múltiplos símbolos em um único gráfico para negociação baseada em notícias

MetaTrader 5 — Exemplos |
24 2
Clemence Benjamin
Clemence Benjamin

Seções


Introdução

Durante períodos de alta volatilidade, como na divulgação de notícias econômicas, os traders costumam buscar oportunidades de rompimento, já que a reação imediata do mercado é imprevisível. Quando uma notícia importante é divulgada, o preço geralmente dispara, seguido de uma correção e, possivelmente, da continuação da tendência. Nessas condições, pode ser interessante operar vários símbolos simultaneamente, mas a configuração padrão do MetaTrader 5 dificulta essa tarefa. A plataforma permite executar apenas um EA por gráfico, o que obriga os traders a abrir vários gráficos e associar um EA diferente a cada símbolo.

Neste artigo, apresentamos uma solução para essa limitação: a negociação de múltiplos símbolos integrada ao EA "Manchetes de notícias". Com essa melhoria, os traders poderão gerenciar vários pares de moedas a partir de um único gráfico, utilizando botões de negociação intuitivos. Veremos como os recursos do MQL5, incluindo sua biblioteca padrão e classes de negociação personalizadas, permitem desenvolver um EA mais avançado, capaz de operar vários símbolos com facilidade em um único gráfico.

Suporte a um Expert Advisor por par.

Fig. 1: Cada gráfico no terminal MetaTrader 5 pode ter apenas um EA

A imagem acima ilustra a limitação do MetaTrader 5, que permite executar apenas um EA por gráfico. Para negociar vários símbolos com eficiência, precisamos de um EA mais avançado, capaz de operar tanto o par de moedas exibido no gráfico atual quanto outros pares simultaneamente, mesmo utilizando apenas um gráfico.

Ao final deste artigo, pretendemos alcançar os seguintes objetivos:

  • Desenvolver um EA mais avançado.
  • Ampliar a classe existente de manchetes de notícias em MQL5 com novas funcionalidades.
  • Utilizar a biblioteca padrão do MQL5 para criar novas classes.
  • Integrar as novas funcionalidades ao EA existente.
  • Aplicar princípios de modularidade e organizar os parâmetros de entrada em grupos estruturados.


Entendendo o conceito

Começaremos com uma breve retrospectiva do que desenvolvemos nas etapas anteriores. Inicialmente, criamos um EA simples que exibia manchetes de notícias animadas, obtendo informações do calendário econômico e de APIs externas de notícias, como a Alpha Vantage. Ao longo do projeto, incorporamos modelos locais de inteligência artificial, estratégias automatizadas de negociação baseada em notícias e botões para operações manuais, tornando o EA mais confiável.

Embora essas melhorias tenham aprimorado o sistema, ainda não representavam uma solução completa. A negociação algorítmica continua evoluindo, e cada avanço tecnológico traz novos desafios que exigem a atualização dos nossos sistemas. Neste artigo, vamos enfrentar um desses desafios: permitir a negociação de vários pares de moedas por meio de um único EA.

Por que isso é necessário?

Uma pergunta pertinente é: por que precisamos dessa funcionalidade?

Durante eventos de alta volatilidade, como a divulgação de notícias econômicas, os traders precisam reagir rapidamente, muitas vezes gerenciando várias posições e símbolos em questão de segundos. Essa funcionalidade oferece uma vantagem importante ao reunir a negociação algorítmica e a manual em uma única interface, aumentando a eficiência e o controle das operações. Com um único clique, o trader pode executar operações em diferentes símbolos e gerenciar várias posições simultaneamente, ganhando velocidade e eficiência operacional.

Integração das funcionalidades

Com isso em mente, vamos apresentar brevemente como a nova funcionalidade será integrada. Para ampliar os recursos do nosso EA, incluiremos arquivos de cabeçalho e utilizaremos classes personalizadas de botões de negociação, mantendo o código principal limpo e modular.

Para negociar vários símbolos, precisamos permitir que o usuário selecione os pares de moedas que serão operados junto com o par exibido no gráfico atual ao acionar os botões de negociação manual. Para isso, utilizaremos as classes CCheckBox e CLabel da biblioteca padrão do MQL5. Esses componentes permitirão exibir os pares disponíveis para seleção, processar as escolhas do usuário e vincular as opções selecionadas diretamente aos tratadores de eventos dos botões.

Por fim, ampliaremos a classe CTradingButtons para incorporar essas novas funcionalidades de forma integrada.


Implementação

Dividiremos a implementação em duas etapas principais. Primeiro, modificaremos a classe CTradingButtons no arquivo de cabeçalho TradingButtons para implementar os recursos de negociação de múltiplos símbolos previstos no projeto. Na segunda etapa, adaptaremos o EA "Manchetes de notícias" para oferecer suporte a esses novos recursos.

Acompanhe a análise do código, na qual explicaremos como cada trecho contribui para colocar essa ideia em prática. Para facilitar o acompanhamento, os blocos de código e suas respectivas explicações serão numerados em sequência, de cima para baixo, com destaque para as novas funcionalidades.

Se quiser revisar a estrutura básica do código, recomendo consultar os artigos anteriores desta série, nos quais examinamos detalhadamente as primeiras versões.


Adaptação da classe CtradingButtons para negociação de múltiplos símbolos

Apresentamos esse arquivo de cabeçalho pela primeira vez no artigo anterior, que vale consultar para entender melhor sua estrutura. Nesta seção, vamos ampliá-lo com a nova funcionalidade.

Visão geral da arquitetura

A classe CTradingButtons reúne três funcionalidades em um único módulo compacto de negociação de múltiplos pares, que pode ser incorporado ao EA: (1) uma interface gráfica (canvas, botões e caixas de seleção de símbolos criadas dinamicamente), (2) uma pequena camada de negociação que encapsula uma instância de CTrade responsável pelo envio de ordens e (3) um mecanismo de resolução de símbolos e negociação de múltiplos pares (que associa nomes-base, como EURUSD, aos símbolos da corretora e executa as ações em todos os símbolos selecionados). A arquitetura mantém os índices alinhados entre os arrays: a lista de símbolos solicitados (fornecida pelo EA), os símbolos correspondentes identificados na corretora (efetivamente negociados pelo terminal) e as caixas de seleção (marcadas ou desmarcadas pelo usuário). Assim, o índice i corresponde ao mesmo par de moedas em todos os arrays. Isso simplifica a integração entre a interface gráfica e os arrays de seleção do EA, tornando seu funcionamento previsível.

// top-of-file: class skeleton + key members (from TradingButtons.mqh)

class CTradingButtons

{

private:

   // UI & buttons
   CButton btnMultiToggle;
   CButton btnBuy, btnSell, btnCloseAll, btnDeleteOrders, btnCloseProfit, btnCloseLoss, btnBuyStop, btnSellStop;
   CCanvas buttonPanel;

   // trading

   CTrade  trade;

   // multipair UI & resolution

   CCheckBox *pairChecks[];      // dynamic checkbox pointers, index-aligned with requested list
   string     availablePairs[];  // resolved broker symbols (index-aligned)
   string     resolvedBases[];   // original requested bases (for logging)
   bool       multiEnabled;
public:

   double LotSize;
   int    StopLoss;
   int    TakeProfit;
   int    StopOrderDistancePips;
   double RiskRewardRatio;
   CTradingButtons() { /* default init inlined in full file */ }
   void Init();
   void Deinit();
   // ... other methods follow

};

Campos e construtor: o que a classe armazena

A classe armazena os parâmetros de layout (largura, altura e espaçamento entre os botões), o tamanho das caixas de seleção e suas coordenadas iniciais, um array dinâmico de caixas de seleção, os arrays de símbolos identificados na corretora e os parâmetros de negociação (tamanho do lote, níveis de stop e relação risco/retorno). O construtor define valores padrão adequados (por exemplo, LotSize=0.01, StopLoss=50, TakeProfit=100, multiEnabled=true), permitindo que o EA comece com uma configuração funcional e ajuste posteriormente os parâmetros necessários. A separação entre campos públicos, destinados aos parâmetros de negociação, e campos privados, reservados aos componentes internos da interface gráfica, mantém a interface da classe simples e segura.

// constructor + key field defaults (actual defaults in your file)

CTradingButtons() :
   buttonWidth(100), buttonHeight(30), buttonSpacing(10),
   checkWidth(120), checkHeight(20), checkSpacing(6), checkStartX(10),
   LotSize(0.01), StopLoss(50), TakeProfit(100),
   StopOrderDistancePips(8), RiskRewardRatio(2.0),
   multiEnabled(true)

{

   // constructor body intentionally minimal — Init() performs heavier setup

}

Inicialização e limpeza

O método Init() configura a instância de CTrade (número mágico e desvio permitido) e cria a interface gráfica (painel, botões e controle de ativação da negociação de múltiplos pares). Já Deinit() destrói corretamente todos os objetos dinâmicos (caixas de seleção, botões e canvas) e libera os arrays, evitando que objetos permaneçam indevidamente no gráfico ou ocorram vazamentos de memória. A rotina de limpeza percorre o array pairChecks[] em um laço, chama Destroy() e utiliza delete para liberar os objetos referenciados pelos ponteiros dinâmicos. Em seguida, libera o próprio array. Esse cuidado é especialmente importante quando o EA é reiniciado ou descarregado repetidamente durante o desenvolvimento.

// Init & Deinit excerpt

void Init()

{
   trade.SetExpertMagicNumber(123456);
   trade.SetDeviationInPoints(10);
   CreateButtonPanel();
   CreateButtons();
   CreateMultiToggle();
   UpdateMultiToggleVisual();

}

void Deinit()

{
   // destroy checkboxes
   for(int i = 0; i < ArraySize(pairChecks); i++)

   {
      if(CheckPointer(pairChecks[i]) == POINTER_DYNAMIC)
         pairChecks[i].Destroy();
         delete pairChecks[i];
      }
   }
   ArrayFree(pairChecks);

   // destroy buttons and panel
   btnMultiToggle.Destroy();
   btnBuy.Destroy();
   btnSell.Destroy();
   btnCloseAll.Destroy();
   btnDeleteOrders.Destroy();
   btnCloseProfit.Destroy();
   btnCloseLoss.Destroy();
   btnBuyStop.Destroy();
   btnSellStop.Destroy();
   buttonPanel.Destroy();
   ObjectDelete(0, "ButtonPanel");

}

Resolução de símbolos (essencial para a negociação de múltiplos pares)

Para negociar utilizando um nome-base como EURUSD, o EA precisa identificar corretamente o símbolo correspondente na corretora, que pode aparecer como EURUSD, EURUSD.ecn, FX.EURUSD etc. A função ResolveSymbol(base) primeiro tenta encontrar uma correspondência exata, que é a opção mais rápida. Se não encontrar, percorre todos os símbolos disponíveis no terminal em busca de correspondências, dando preferência àqueles cujos nomes começam com o nome-base solicitado e descartando os símbolos desativados. Nessa etapa, são preenchidas as entradas availablePairs[i], utilizadas tanto pelas rotinas de negociação quanto pelas caixas de seleção da interface gráfica. Esse array estabelece a ligação entre os nomes solicitados pelo EA e os símbolos efetivamente disponíveis para negociação na corretora.

// ResolveSymbol implementation (exact + starts-with + contains search)

string ResolveSymbol(const string base)

{
   if(StringLen(base) == 0) return("");
   // 1) Try exact symbol name first
   string baseName = base;
   if(SymbolInfoInteger(baseName, SYMBOL_SELECT) != 0 || SymbolSelect(baseName, false))
   {
      if(SymbolInfoInteger(baseName, SYMBOL_TRADE_MODE) != SYMBOL_TRADE_MODE_DISABLED)

      {
         PrintFormat("ResolveSymbol: exact match found %s", baseName);

         return(baseName);
      }
   }

   // 2) search all terminal symbols

   int total = SymbolsTotal(false);
   string base_u = base; StringToUpper(base_u);
   string firstStarts = ""; string firstContains = "";

   for(int i = 0; i < total; i++)

   {
      string sym = SymbolName(i, false);
      string sym_u = sym; StringToUpper(sym_u);
      if(sym_u == base_u) continue;
      if(SymbolInfoInteger(sym, SYMBOL_TRADE_MODE) == SYMBOL_TRADE_MODE_DISABLED) continue;
      if(StringFind(sym_u, base_u) == 0)
      {
         if(firstStarts == "") firstStarts = sym;
      }
      else if(StringFind(sym_u, base_u) >= 0)

      {
         if(firstContains == "") firstContains = sym;
      }
   }

   if(firstStarts != "") { PrintFormat("ResolveSymbol: resolved %s -> %s (starts-with)", base, firstStarts); return(firstStarts); }
   if(firstContains != "") { PrintFormat("ResolveSymbol: resolved %s -> %s (contains)", base, firstContains); return(firstContains); }
   PrintFormat("ResolveSymbol: no match for %s", base);
   return("");
}

Criando a interface para múltiplos pares: CreatePairCheckboxes(...)

CreatePairCheckboxes(inMajorPairs[], inPairSelected[], yPos) é o procedimento responsável por: (a) associar cada nome-base solicitado ao símbolo correspondente na corretora; (b) garantir que o símbolo esteja incluído na Observação do Mercado por meio de SymbolSelect e disponível para negociação; e (c) criar dinamicamente uma caixa de seleção CCheckBox para cada símbolo identificado, preservando o alinhamento dos índices com os arrays do EA. As entradas não resolvidas ou desativadas são mantidas como posições reservadas, garantindo que availablePairs[i] continue correspondendo ao respectivo inMajorPairs[i]. O estado inicial de cada caixa de seleção é definido pelo valor de inPairSelected[i], mantendo os arrays de seleção da interface gráfica e do EA sincronizados desde a inicialização.

// CreatePairCheckboxes: resolve requested bases -> create checkboxes aligned by index

void CreatePairCheckboxes(string &inMajorPairs[], bool &inPairSelected[], int yPos)

{
   // cleanup previous

   for(int i = 0; i < ArraySize(pairChecks); i++)

   {
      if(CheckPointer(pairChecks[i]) == POINTER_DYNAMIC)
      {
         pairChecks[i].Destroy();
         delete pairChecks[i];
      }
   }

   ArrayFree(pairChecks);
   ArrayResize(availablePairs, ArraySize(inMajorPairs));
   ArrayResize(resolvedBases, ArraySize(inMajorPairs));
   for(int k = 0; k < ArraySize(availablePairs); k++) { availablePairs[k] = ""; resolvedBases[k] = ""; }
   int count = ArraySize(inMajorPairs);
   if(count == 0) return;

   // Resolve each requested base

   for(int i = 0; i < count; i++)
   {
      string requested = inMajorPairs[i];
      string resolved = ResolveSymbol(requested);
      if(resolved == "")
      {
         PrintFormat("CreatePairCheckboxes: could not resolve %s -> skipping checkbox", requested);
         availablePairs[i] = "";
         resolvedBases[i] = requested;
         continue;
      }
      if(!SymbolSelect(resolved, true))
         PrintFormat("CreatePairCheckboxes: SymbolSelect failed for %s (from %s) Err=%d", resolved, requested, GetLastError());
      if(SymbolInfoInteger(resolved, SYMBOL_TRADE_MODE) == SYMBOL_TRADE_MODE_DISABLED)
      {
         PrintFormat("CreatePairCheckboxes: resolved symbol %s is disabled (from %s) - skipping", resolved, requested);
         availablePairs[i] = "";
         resolvedBases[i] = requested;
         continue;
      }
      availablePairs[i] = resolved;
      resolvedBases[i] = requested;
   }

   // Create checkbox controls (preserve index alignment)

   ArrayResize(pairChecks, count);
   int xPos = checkStartX;
   int chartW = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS);
   int wrapX = chartW - (buttonWidth * 3) - 30;
   for(int i = 0; i < count; i++)
   {
      if(StringLen(availablePairs[i]) == 0) { pairChecks[i] = NULL; continue; }
      pairChecks[i] = new CCheckBox();
      string objName = "Chk_" + availablePairs[i];
      if(!pairChecks[i].Create(ChartID(), objName, 0, xPos, yPos, xPos + checkWidth, yPos + checkHeight))
      {

         PrintFormat("CreatePairCheckboxes: failed to create checkbox %s Err=%d", objName, GetLastError());
         delete pairChecks[i];
         pairChecks[i] = NULL;
         availablePairs[i] = "";
         continue;
      }
      pairChecks[i].Text(" " + availablePairs[i]);
      pairChecks[i].Color(clrBlack);
      bool checked = false;
      if(i < ArraySize(inPairSelected)) checked = inPairSelected[i];
      pairChecks[i].Checked(checked);
      xPos += checkWidth + checkSpacing;
      if(xPos + checkWidth > wrapX) { xPos = checkStartX; yPos += checkHeight + checkSpacing; }
   }

   ChartRedraw();
   PrintFormat("CreatePairCheckboxes: created checkboxes (resolved count=%d)", CountResolvedPairs());
}

Contagem de pares identificados: CountResolvedPairs()

Pequenas funções auxiliares ajudam a manter o código legível. A função CountResolvedPairs() simplesmente conta as entradas não vazias do array availablePairs[] e é utilizada para registrar informações no log ou atualizar os textos da interface gráfica. É uma solução simples, mas útil durante a inicialização e a depuração.

// Count resolved availablePairs entries

int CountResolvedPairs()
{
   int c = 0;
   for(int i = 0; i < ArraySize(availablePairs); i++)
      if(StringLen(availablePairs[i]) > 0) c++;
   return c;
}

Tratamento de eventos: HandleChartEvent(...)

Todos os cliques nos objetos do gráfico são encaminhados para HandleChartEvent, que distingue três categorias: (A) cliques nas caixas de seleção (identificadas pelo prefixo Chk_ nos nomes dos objetos), permitindo identificar a qual símbolo corresponde a caixa de seleção acionada e atualizar o elemento inPairSelected[i]; (B) cliques no botão de alternância do modo multipar, que modifica multiEnabled e atualiza os elementos visuais; e (C) cliques nos botões de negociação (Buy/Sell/Close all/Delete pending/Place stops), que acionam as operações correspondentes, passando ao EA os pares solicitados e os indicadores de seleção. Essa função atua como um roteador de eventos entre a interface gráfica e o mecanismo de negociação (UI → engine router), mantendo sincronizados os arrays da interface e do EA.

// HandleChartEvent: routes object clicks to checkboxes / toggle / actions

void HandleChartEvent(const int id, const string &sparam, string &inMajorPairs[], bool &inPairSelected[])

{
   if(id == CHARTEVENT_OBJECT_CLICK)
   {
      // Checkbox click handling
      if(StringFind(sparam, "Chk_") == 0)
      {
         for(int i = 0; i < ArraySize(availablePairs); i++)
         {
            if(StringLen(availablePairs[i]) == 0) continue;
            string expected = "Chk_" + availablePairs[i];
            if(expected == sparam)

            {
               if(CheckPointer(pairChecks[i]) == POINTER_DYNAMIC)
               {
                 bool current = pairChecks[i].Checked();
                  if(i < ArraySize(inPairSelected)) inPairSelected[i] = current;
                  else { ArrayResize(inPairSelected, i+1); inPairSelected[i] = current; }
                  PrintFormat("HandleChartEvent: checkbox for %s toggled -> %s", availablePairs[i], current ? "true":"false");
               }
               break;
            }
         }
         return;
      }
      // Multi toggle

      if(sparam == btnMultiToggle.Name())

      {
         multiEnabled = !multiEnabled;
         UpdateMultiToggleVisual();
         PrintFormat("HandleChartEvent: Multi toggle clicked. New multiEnabled=%s", (multiEnabled ? "true":"false"));
         return;
      }

      // Buttons - delegate to command handlers

      if(sparam == btnBuy.Name())        OpenBuyOrder(inMajorPairs, inPairSelected);
      else if(sparam == btnSell.Name()) OpenSellOrder(inMajorPairs, inPairSelected);
      else if(sparam == btnCloseAll.Name()) CloseAllPositions(inMajorPairs, inPairSelected);
      else if(sparam == btnDeleteOrders.Name()) DeleteAllPendingOrders(inMajorPairs, inPairSelected);
      else if(sparam == btnCloseProfit.Name()) CloseProfitablePositions(inMajorPairs, inPairSelected);
      else if(sparam == btnCloseLoss.Name())   CloseLosingPositions(inMajorPairs, inPairSelected);
      else if(sparam == btnBuyStop.Name())     PlaceBuyStop(inMajorPairs, inPairSelected);
      else if(sparam == btnSellStop.Name())    PlaceSellStop(inMajorPairs, inPairSelected);
   }
}

Funções auxiliares de criação da interface gráfica

A criação da interface gráfica é dividida em funções auxiliares menores. CreateButtonPanel() cria uma imagem bitmap no canvas, incluindo o fundo do painel e um retângulo decorativo. CreateButtons() instancia e configura o estilo de cada botão de negociação, mantendo a consistência das fontes, dimensões e posições. Já CreateMultiToggle() cria o botão de alternância do modo multipar, posicionado acima dos principais botões de negociação. A função UpdateMultiToggleVisual() atualiza o texto e a cor desse botão para indicar se o modo multipar está ativado. Essa divisão separa o código da interface gráfica da lógica de negociação e facilita os ajustes visuais.

// Create panel + buttons + multi-toggle visual helpers

void CreateButtonPanel()

{
   int panelWidthLocal = buttonWidth + 20;
   int panelHeightLocal = (buttonHeight + buttonSpacing) * 9 + buttonSpacing + 40;
   int x = 0, y = 40;

   if(!buttonPanel.CreateBitmap(0, 0, "ButtonPanel", x, y, panelWidthLocal, panelHeightLocal, COLOR_FORMAT_ARGB_NORMALIZE))
   {
      Print("Failed to create button panel: Error=", GetLastError());
      return;
   }
   ObjectSetInteger(0, "ButtonPanel", OBJPROP_ZORDER, 10);
   buttonPanel.FillRectangle(0, 0, panelWidthLocal, panelHeightLocal, ColorToARGB(clrDarkGray, 200));
   buttonPanel.Rectangle(0, 0, panelWidthLocal - 1, panelHeightLocal - 1, ColorToARGB(clrRed, 255));
   buttonPanel.Update(true);
   ChartRedraw(0);
}
void CreateMultiToggle()
{
   int x = 10, y = 120;
   string font = "Calibri"; int fontSize = 8;
   color buttonBgColor = clrBlack;

   if(btnMultiToggle.Create(0, "btnMultiToggle", 0, x, y, x + buttonWidth, y + buttonHeight))
   {

      ObjectSetString(0, "btnMultiToggle", OBJPROP_FONT, font);
      ObjectSetInteger(0, "btnMultiToggle", OBJPROP_FONTSIZE, fontSize);
      ObjectSetInteger(0, "btnMultiToggle", OBJPROP_BGCOLOR, buttonBgColor);
      ObjectSetInteger(0, "btnMultiToggle", OBJPROP_ZORDER, 11);
   }
}

void UpdateMultiToggleVisual()
{
   if(multiEnabled)
   {
      btnMultiToggle.Text("MULTI:ON");
      btnMultiToggle.ColorBackground(clrGreen);
      btnMultiToggle.Color(clrWhite);
   }
   else
   {
      btnMultiToggle.Text("MULTI:OFF");
      btnMultiToggle.ColorBackground(clrRed);
      btnMultiToggle.Color(clrWhite);
   }
}

Funções auxiliares de negociação

Essas funções encapsulam os detalhes da execução das operações. PipSize(symbol) retorna o tamanho de um pip para o símbolo (no código, calculado como SYMBOL_POINT * 10.0), enquanto IsSymbolValid(symbol) verifica a disponibilidade das cotações Bid e Ask. As funções TradeBuySingle() e TradeSellSingle() verificam se o símbolo pode ser negociado e se o volume respeita os limites permitidos, calculam o preço de execução e os níveis de Stop Loss (SL) e Take Profit (TP) com base no tamanho do pip, definem o tipo de preenchimento da ordem e enviam as ordens por meio de trade.Buy() e trade.Sell(). Essas funções auxiliares centralizam a lógica de envio de ordens, permitindo que os laços de negociação de múltiplos pares simplesmente as chamem para cada símbolo.

// Pip size, validation, and single-symbol trade helpers

double PipSize(string symbol)

{
   double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
   if(point <= 0) { Print("Invalid point size for ", symbol, ": Error=", GetLastError()); return 0; }
   return point * 10.0;
}
bool IsSymbolValid(string symbol)
{
   bool inMarketWatch = SymbolInfoDouble(symbol, SYMBOL_BID) > 0 && SymbolInfoDouble(symbol, SYMBOL_ASK) > 0;
   if(!inMarketWatch) Print("Symbol ", symbol, " invalid: Not in Market Watch or no valid bid/ask price.");
   return inMarketWatch;
}
bool TradeBuySingle(const string symbol)
{
   if(!IsSymbolValid(symbol)) return false;
   long tradeMode = SymbolInfoInteger(symbol, SYMBOL_TRADE_MODE);
   if(tradeMode != SYMBOL_TRADE_MODE_FULL) { Print("TradeBuySingle: Skipping ", symbol, ": Trading disabled"); return false; }
   double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
   double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
   if(LotSize < minLot || LotSize > maxLot) { Print("TradeBuySingle: invalid lot"); return false; }

   double price = SymbolInfoDouble(symbol, SYMBOL_ASK);
   double sl = StopLoss > 0 ? price - StopLoss * PipSize(symbol) : 0;
   double tp = TakeProfit > 0 ? price + TakeProfit * PipSize(symbol) : 0;
   trade.SetTypeFillingBySymbol(symbol);
   int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
   price = NormalizeDouble(price, digits);
   sl    = NormalizeDouble(sl, digits);
   tp    = NormalizeDouble(tp, digits);

   if(trade.Buy(LotSize, symbol, price, sl, tp))
   { Print("Buy order placed on ", symbol, ": Ticket #", trade.ResultOrder()); return true; }
   else { Print("Buy order failed on ", symbol, ": Retcode=", trade.ResultRetcode()); return false; }
}
bool TradeSellSingle(const string symbol)
{
   if(!IsSymbolValid(symbol)) return false;
   long tradeMode = SymbolInfoInteger(symbol, SYMBOL_TRADE_MODE);
   if(tradeMode != SYMBOL_TRADE_MODE_FULL) { Print("TradeSellSingle: Skipping ", symbol, ": Trading disabled"); return false; }

   double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
   double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
   if(LotSize < minLot || LotSize > maxLot) { Print("TradeSellSingle: invalid lot"); return false; }

   double price = SymbolInfoDouble(symbol, SYMBOL_BID);
   double sl = StopLoss > 0 ? price + StopLoss * PipSize(symbol) : 0;
   double tp = TakeProfit > 0 ? price - TakeProfit * PipSize(symbol) : 0;
   trade.SetTypeFillingBySymbol(symbol);

   int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);

   price = NormalizeDouble(price, digits);
   sl    = NormalizeDouble(sl, digits);
   tp    = NormalizeDouble(tp, digits);

   if(trade.Sell(LotSize, symbol, price, sl, tp))
   { Print("Sell order placed on ", symbol, ": Ticket #", trade.ResultOrder()); return true; }
   else { Print("Sell order failed on ", symbol, ": Retcode=", trade.ResultRetcode()); return false; }
}

Operações principais: como os comandos de negociação de múltiplos pares são executados

As operações principais (como OpenBuyOrder, OpenSellOrder, CloseAllPositions, PlaceBuyStop e PlaceSellStop) utilizam os arrays inMajorPairs[] e inPairSelected[] fornecidos pelo EA. Quando multiEnabled é true, as rotinas percorrem todos os índices e chamam as funções auxiliares de negociação, utilizando availablePairs[i] para cada par selecionado. Quando multiEnabled é false, as operações são executadas apenas no símbolo do gráfico atual. As funções OpenBuyOrder e OpenSellOrder também utilizam indicadores booleanos para controlar se já foi executada uma operação com o símbolo do gráfico. Caso contrário, executam uma operação nesse símbolo. Esse mecanismo garante o comportamento esperado pelo usuário ao alternar entre o modo de negociação do gráfico atual e o modo multipar.

// OpenBuyOrder / OpenSellOrder excerpt (multipair iteration + fallback to chart symbol)

void OpenBuyOrder(string &inMajorPairs[], bool &inPairSelected[])

{
   Print("Starting OpenBuyOrder");
   string chartSym = Symbol();
   if(!multiEnabled)

   {
      PrintFormat("OpenBuyOrder: multipair disabled => trading only chart symbol %s", chartSym);
      if(SymbolInfoInteger(chartSym, SYMBOL_TRADE_MODE) == SYMBOL_TRADE_MODE_DISABLED) { Print("chart symbol not tradeable"); return; }
      TradeBuySingle(chartSym);
      return;
   }
   bool chartTraded = false;
   for(int i = 0; i < ArraySize(inMajorPairs); i++)
   {
      if(i < ArraySize(inPairSelected) && inPairSelected[i] && StringLen(availablePairs[i]) > 0)
      {
         string symbol = availablePairs[i];
         Print("Attempting Buy order on ", symbol, " (requested ", resolvedBases[i], ")");
         if(TradeBuySingle(symbol) && symbol == chartSym) chartTraded = true;
      }
      else
      {
         if(i < ArraySize(inMajorPairs)) Print("Skipping ", inMajorPairs[i], ": Not selected or unresolved");
      }
   }
   if(!chartTraded && SymbolInfoInteger(chartSym, SYMBOL_TRADE_MODE) != SYMBOL_TRADE_MODE_DISABLED)
   {
      PrintFormat("OpenBuyOrder: attempting BUY on chart symbol %s", chartSym);
      TradeBuySingle(chartSym);
   }
}
void OpenSellOrder(string &inMajorPairs[], bool &inPairSelected[])

{
   // (same structure as OpenBuyOrder but calling TradeSellSingle)
   // Implementation mirrors the buy flow but uses SELL specifics.
}


Integração da negociação de múltiplos símbolos ao EA "Manchetes de notícias"

Onde o sistema multipar é integrado (includes e inputs)

No início do código, o EA inclui o arquivo de cabeçalho responsável pela interface gráfica e pelas operações com múltiplos pares, além de disponibilizar um parâmetro input que permite ativar ou desativar o modo multipar na inicialização. É nesse ponto que o EA define dois aspectos: (a) a utilização de um componente externo de interface gráfica e negociação multipar; e (b) a possibilidade de o usuário configurar o estado inicial desse modo. Assim, a funcionalidade fica acessível e pode ser configurada diretamente nos parâmetros do EA.

#include <TradingButtons.mqh>             // header that implements the multipair UI & trading logic.
// ... other includes ...
input bool   EnableMultipair = true;      // initial multipair enabled state

Precisamos incluir o arquivo de cabeçalho e disponibilizar um parâmetro input para que o usuário possa definir o comportamento desejado na inicialização.

Onde os dados dos múltiplos pares são armazenados (majorPairs e indicadores de seleção)

O EA define um array de strings majorPairs[], que contém os nomes dos pares de moedas solicitados, e um array booleano paralelo pairSelected[], que registra quais pares estão selecionados. Esses dois arrays estabelecem a interface de dados entre o EA e o arquivo de cabeçalho: o índice i corresponde ao mesmo par de moedas em ambos. O código do arquivo de cabeçalho configura as caixas de seleção e consulta o array booleano para identificar os pares selecionados.

// MULTIPAIR arrays (provided to the header)
// default major pairs (you can edit or later replace with resolved broker symbols)
string majorPairs[] = {"EURUSD","GBPUSD","USDJPY","USDCHF","AUDUSD","USDCAD","NZDUSD"};
bool   pairSelected[];

Essa estrutura mantém uma lista simples de pares de moedas e seus respectivos estados de seleção, com índices correspondentes. Além de facilitar a leitura do código, permite passar os arrays por referência e simplifica a sincronização.

Inicialização da seleção padrão e passagem dos parâmetros ao módulo (configuração de OnInit)

Durante a execução de OnInit(), o EA redimensiona o array pairSelected[] para que tenha o mesmo número de elementos que majorPairs[] e define inicialmente todos os seus valores como true. Em seguida, configura os parâmetros públicos de buttonsEA (tamanho do lote, níveis de stop e configurações de risco) e inicializa o módulo por meio das chamadas SetMultiEnabled(EnableMultipair) e Init(). Isso garante que o módulo comece no modo definido pelo EA e utilize os mesmos parâmetros de negociação.

// In OnInit()
ArrayResize(pairSelected, ArraySize(majorPairs));
for(int i = 0; i < ArraySize(pairSelected); i++) pairSelected[i] = true;

// Initialize TradingButtons
buttonsEA.LotSize = ButtonLotSize;
buttonsEA.StopLoss = ButtonStopLoss;
buttonsEA.TakeProfit = ButtonTakeProfit;
buttonsEA.StopOrderDistancePips = StopOrderDistancePips;
buttonsEA.RiskRewardRatio = RiskRewardRatio;
buttonsEA.Init();
buttonsEA.SetMultiEnabled(EnableMultipair); // pass initial multipair state

A configuração deve ser sincronizada antes da inicialização do objeto responsável pela interface gráfica e pelas operações de negociação. Primeiro, definimos os campos públicos e o modo de operação; depois, chamamos Init(), garantindo que o módulo utilize os parâmetros corretos durante a execução.

Criação das caixas de seleção (configuração da interface gráfica): chamada a CreatePairCheckboxes

Aqui, o EA calcula o deslocamento vertical das caixas de seleção (checkboxY) para posicioná-las abaixo das faixas de notícias e chama CreatePairCheckboxes(majorPairs, pairSelected, checkboxY). Essa chamada cria as caixas de seleção por meio do arquivo de cabeçalho, preservando a correspondência dos índices com majorPairs[]. O código do arquivo de cabeçalho também define o estado inicial de cada caixa a partir de pairSelected[], mantendo a interface gráfica e o EA sincronizados. Dessa forma, o componente de interface gráfica fica responsável por exibir os controles, enquanto os arrays do EA são passados por referência. O EA continua sendo a fonte principal dos dados sobre quais pares existem e quais estão selecionados, enquanto o código do arquivo de cabeçalho opera sobre esses mesmos arrays.

// create pair checkboxes aligned below the canvas lanes

int checkboxY = InpTopOffset + (InpSeparateLanes ? 8 : 28) * lineH + 6; // adjust +6 px margin if needed

buttonsEA.CreatePairCheckboxes(majorPairs, pairSelected, checkboxY);

Roteamento de eventos: encaminhamento dos eventos do gráfico ao módulo

O EA não implementa diretamente a lógica dos cliques nos botões. Em vez disso, encaminha os eventos de clique nos objetos do gráfico ao módulo por meio da chamada buttonsEA.HandleChartEvent(...) dentro de OnChartEvent. Essa integração por meio de uma única chamada simplifica o código do EA, pois o módulo fica responsável pela alternância do modo multipar, pelo tratamento dos cliques nas caixas de seleção e pelas ações dos botões de negociação manual.

// OnChartEvent: forward to the header with majorPairs and pairSelected arrays
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   // Header will handle multipair toggle and trade behaviour
   buttonsEA.HandleChartEvent(id, sparam, majorPairs, pairSelected);
}

Com esse roteamento separado, o EA apenas encaminha os eventos, enquanto o módulo processa as interações com a interface gráfica e determina as operações de negociação correspondentes. Assim, cada componente mantém responsabilidades bem definidas.

Como são executadas as operações manuais com múltiplos pares (papel do módulo)

O módulo encapsula a execução das operações manuais com múltiplos pares. O EA fornece os arrays necessários, enquanto o módulo percorre os elementos e identifica os símbolos correspondentes, mantendo o código principal mais simples. Quando o usuário clica em Buy/Sell ou alterna o modo multipar, HandleChartEvent utiliza os arrays majorPairs e pairSelected recebidos para determinar como executar a ação. Por exemplo, no modo multipar, percorre os índices e opera apenas os pares para os quais pairSelected[i] == true. O EA fornece somente os arrays e os parâmetros de configuração; o módulo resolve os símbolos e executa as operações em múltiplos pares. (Consulte no arquivo de cabeçalho as funções auxiliares de negociação por símbolo e a lógica de iteração sobre os pares.)
// (conceptual) header receives arrays and performs per-index iteration:
// Pseudocode excerpt of header behavior (actual code in TradingButtons.mqh)
for(i = 0; i < ArraySize(majorPairs); i++)
{
   if(i < ArraySize(pairSelected) && pairSelected[i])
   {
      // resolve broker symbol for majorPairs[i]
      // call TradeBuySingle(resolvedSymbol) or TradeSellSingle(...)
   }
}

A lógica das ordens automatizadas permanece vinculada ao gráfico (como a negociação de múltiplos símbolos coexiste com a automação)

As ordens stop automatizadas, enviadas antes e depois dos eventos de notícias, operam exclusivamente com o símbolo do gráfico atual (_Symbol), e não com os pares definidos em majorPairs[]. O sistema de negociação manual com múltiplos pares funciona de maneira independente: as operações manuais acionadas pelos botões e as operações automatizadas em resposta a eventos seguem fluxos distintos. Essa separação evita que ordens automatizadas sejam enviadas inadvertidamente para vários símbolos, a menos que a lógica de automação seja explicitamente ampliada para utilizar majorPairs[].

// Example: automated BuyStop/SellStop placement uses _Symbol (chart symbol)
if(trade.BuyStop(InpOrderVolume, buyPrice, _Symbol, buySL, buyTP))
   ticketBuyStop = trade.ResultOrder();
if(trade.SellStop(InpOrderVolume, sellPrice, _Symbol, sellSL, sellTP))
   ticketSellStop = trade.ResultOrder();

O código apresentado demonstra uma lição importante: convém manter o gerenciamento manual de múltiplos pares separado das estratégias automatizadas vinculadas ao símbolo do gráfico, a menos que exista a intenção de ampliar a automação para outros símbolos. Essa separação clara de responsabilidades ajuda a evitar operações inesperadas.

Modelo de sincronização: o EA é responsável pelos dados, enquanto o módulo é responsável pela interface gráfica e pela lógica

O EA define e armazena os arrays majorPairs[] e pairSelected[], que constituem a fonte principal dos dados de seleção. O módulo consulta esses arrays para criar os controles e executar ações sobre os pares selecionados. Também atualiza os valores de pairSelected[i] quando o usuário marca ou desmarca as caixas de seleção, já que os arrays são passados por referência. Esse modelo de sincronização bidirecional é simples e confiável: o EA pode consultar pairSelected[] a qualquer momento, por exemplo, em OnTimer, enquanto o módulo atualiza seus valores conforme as interações do usuário.

// EA owns arrays; header is given references and updates them when checkboxes are toggled
buttonsEA.CreatePairCheckboxes(majorPairs, pairSelected, checkboxY);
...
// header's HandleChartEvent updates pairSelected[] in-place when checkboxes are clicked

Utilizamos a passagem por referência para compartilhar o estado durante a execução. Essa abordagem tem baixo custo de processamento e mantém a interface gráfica e o EA sincronizados sem a necessidade de mecanismos adicionais de troca de mensagens.

Recomendações de posicionamento e apresentação visual (caixas de seleção abaixo das faixas de notícias)

O EA calcula o deslocamento vertical checkboxY com base nas faixas de notícias e nos parâmetros de configuração (InpTopOffset, InpSeparateLanes, lineH), posicionando as caixas de seleção do modo multipar abaixo das faixas de notícias e indicadores. A integração de elementos gráficos de diferentes módulos exige atenção tanto ao layout quanto à lógica de funcionamento. Ao calcular dinamicamente os deslocamentos, a interface se adapta às alterações de altura ou posição das faixas.

// compute vertical position for checkboxes so they sit below the lanes
int checkboxY = InpTopOffset + (InpSeparateLanes ? 8 : 28) * lineH + 6;
buttonsEA.CreatePairCheckboxes(majorPairs, pairSelected, checkboxY);

Ao combinar elementos canvas com painéis de interface gráfica de outros módulos, centralize os cálculos de posicionamento no EA para que ambos utilizem regras consistentes de espaçamento.


Testes

Os testes do EA no terminal MetaTrader 5 apresentaram excelentes resultados. Consegui selecionar os pares de moedas que desejava negociar, e os botões de negociação executaram imediatamente as ações correspondentes. As ordens eram executadas com a velocidade proporcionada pela negociação algorítmica e, com um único clique, eu conseguia fechar todas as posições de vários pares de moedas. Essa funcionalidade é extremamente valiosa para a negociação baseada em notícias e outras estratégias de scalping em períodos de alta volatilidade.

A imagem abaixo apresenta os resultados dos testes realizados em um gráfico em tempo real. É importante observar que as funcionalidades de negociação manual exigem interação direta com o gráfico em tempo real, enquanto os componentes automatizados do EA podem ser avaliados detalhadamente no testador de estratégias para verificar sua eficiência.

Negociação de múltiplos símbolos com o EA "Manchetes de notícias"

Negociação de múltiplos símbolos com o EA "Manchetes de notícias"



Conclusão

A parte IX representa mais um marco importante na evolução do EA "Manchetes de notícias": a integração da negociação de múltiplos símbolos. Essa melhoria supera uma limitação antiga, permitindo que os traders gerenciem vários pares de moedas a partir de um único gráfico. Embora essa funcionalidade não constitua um sistema de negociação totalmente automatizado, ela oferece uma interface de negociação manual com execução algorítmica, proporcionando velocidade e precisão sem retirar do trader o controle das decisões em condições de alta volatilidade.

O desenvolvimento foi cuidadosamente planejado, com a aplicação de princípios de modularidade e separação de responsabilidades para criar um sistema compacto, mas poderoso. O que começou como uma simples exibição do calendário econômico e de um feed de notícias evoluiu para uma plataforma versátil, que combina funcionalidades manuais e automatizadas para atender às necessidades práticas dos traders que operam com base em notícias. Embora o sistema tenha sido desenvolvido para os principais pares de moedas, também pode ser adaptado para símbolos personalizados com pequenos ajustes de compatibilidade.

Um dos principais desafios encontrados foi a diferença na nomenclatura dos símbolos entre as corretoras. Por exemplo, inicialmente as operações falharam porque a conta utilizava o símbolo EURUSD.0 em vez do padrão EURUSD. Para resolver esse problema, aprimoramos o EA para que se adaptasse dinamicamente à nomenclatura utilizada pela corretora para os principais pares de moedas.

Também utilizamos a classe CCheckBox da biblioteca padrão do MQL5 para permitir uma seleção simples e intuitiva dos pares, demonstrando a flexibilidade e a extensibilidade da linguagem MQL5.

Espero que este artigo tenha apresentado ideias úteis e ensinamentos práticos. O código-fonte completo está disponível abaixo e pode ser consultado como referência para a implementação descrita neste artigo. Para facilitar a consulta, também reuni as principais conclusões em uma tabela a seguir. Comentários e sugestões são sempre bem-vindos.


Principais lições

Principais lições Descrição
Arrays alinhados por índice Os dois módulos utilizam os arrays majorPairs[] e pairSelected[], mantendo os índices alinhados. Isso garante que cada caixa de seleção, nome-base solicitado e símbolo correspondente na corretora estejam associados ao mesmo par de moedas.
Sincronização por passagem por referência Os arrays são passados por referência do EA para TradingButtons.mqh, permitindo que o código do arquivo de cabeçalho atualize diretamente os estados de seleção quando o usuário marca ou desmarca as caixas. Assim, o estado do EA é sincronizado imediatamente.
Roteamento explícito de eventos O EA não processa diretamente os cliques nos botões. Em vez disso, OnChartEvent encaminha os eventos para buttonsEA.HandleChartEvent(), onde o módulo trata a alternância do modo multipar, os cliques nas caixas de seleção e as ações de negociação.
Abstração da resolução de símbolos A função ResolveSymbol(), definida no arquivo de cabeçalho, associa nomes-base simples, como EURUSD, aos símbolos específicos da corretora, como EURUSD.ecn. Dessa forma, o EA não precisa lidar diretamente com as particularidades da nomenclatura de cada corretora.
Separação entre operações manuais e automatizadas No EA, as ordens automatizadas executadas antes e depois dos eventos de notícias utilizam sempre o símbolo do gráfico atual, enquanto a negociação de múltiplos pares fica reservada às operações manuais acionadas pelos botões. Essa separação evita a execução inesperada de operações em vários símbolos.
Criação e limpeza dinâmica da interface gráfica O módulo cria e remove dinamicamente caixas de seleção e botões durante Init() e Deinit(). O EA calcula os deslocamentos necessários para posicionar esses componentes abaixo das faixas de notícias, integrando-os à interface gráfica existente.
Configuração dos parâmetros antes de Init() Em OnInit(), o EA configura LotSize, StopLoss, TakeProfit e EnableMultipair antes de chamar buttonsEA.Init(). Isso garante que o módulo seja inicializado com os parâmetros corretos.
Centralização das funções auxiliares de negociação A lógica de negociação é encapsulada em funções auxiliares reutilizáveis, como TradeBuySingle() e TradeSellSingle(). Isso evita a duplicação de código nos laços de negociação de múltiplos pares e nos tratadores de eventos dos botões.
Alternância do modo multipar O botão btnMultiToggle permite alternar entre a negociação de um único símbolo e a de múltiplos pares. No modo multipar, as operações são executadas em todos os pares selecionados. No modo de símbolo único, as ações são aplicadas apenas ao símbolo do gráfico atual.
Retorno ao símbolo do gráfico Se o modo multipar estiver ativado, mas o símbolo do gráfico não estiver selecionado, o módulo ainda garante a execução de uma operação nesse símbolo. Isso proporciona um comportamento previsível para os usuários que desejam manter o foco no gráfico atual.
Coordenação do layout O EA calcula o valor de checkboxY para posicionar corretamente as caixas de seleção do modo multipar abaixo do canvas com notícias em rolagem. Isso demonstra como integrar painéis de interface gráfica de outros módulos a elementos gráficos personalizados de indicadores, evitando sobreposições.
Registro de erros e clareza no diagnóstico Os dois módulos geram logs detalhados, incluindo erros de resolução de símbolos e códigos de retorno do envio de ordens. Esses registros permitem que desenvolvedores e usuários identifiquem rapidamente problemas de configuração.
Modelo de sincronização bidirecional Os estados iniciais das caixas de seleção são definidos a partir de pairSelected[], sincronizando os dados do EA com a interface gráfica. Quando o usuário marca ou desmarca uma caixa, o valor correspondente em pairSelected[] é atualizado, sincronizando a interface com o EA. Esse mecanismo bidirecional garante que os dois módulos compartilhem o mesmo estado de seleção.
Gerenciamento seguro da memória dinâmica O módulo utiliza new CCheckBox() para criar uma caixa de seleção para cada par e remove corretamente esses objetos em Deinit(). Essa implementação demonstra como gerenciar com segurança os objetos da interface gráfica em EAs que permanecem em execução por longos períodos.
Extensibilidade por meio da modularidade Ao encapsular a negociação de múltiplos pares em um arquivo de cabeçalho independente, a mesma classe pode ser reutilizada em diferentes EAs, como o EA "Manchetes de notícias", sem a necessidade de reescrever a lógica de negociação multipar. Essa abordagem oferece uma estrutura escalável para a reutilização de código.


Conteúdo do anexo

Nome do arquivo Versão Descrição
News_Headline_EA.mq5 1.13 EA que integra os eventos do calendário econômico e as manchetes de notícias diretamente ao gráfico. Gerencia ordens stop antes dos eventos, operações após os eventos e a exibição de notícias em rolagem. A versão 1.13 amplia suas funcionalidades com o suporte à negociação de múltiplos pares por meio do módulo TradingButtons, permitindo a execução manual de ordens em vários pares de moedas, além das operações automatizadas baseadas em eventos do gráfico.
TradingButtons.mqh 1 Arquivo de cabeçalho modular que implementa uma interface de negociação de múltiplos pares. Cria botões para operações de compra, venda, fechamento de posições, exclusão de ordens pendentes e colocação de ordens stop, além de caixas de seleção para escolher vários pares de moedas. Inclui a lógica de resolução de símbolos, funções auxiliares para o envio de ordens e um mecanismo de alternância entre a negociação de um único símbolo e a de múltiplos pares. Foi desenvolvido para ser reutilizado em diferentes EAs, incluindo o EA "Manchetes de notícias".

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

Arquivos anexados |
TradingButtons.mqh (38.59 KB)
Últimos Comentários | Ir para discussão (2)
Stanislav Korotky
Stanislav Korotky | 17 set. 2025 em 18:34

Qual é o sentido real disso tudo? O raciocínio apresentado é irracional, pois os EAs são capazes, por padrão, de operar com diversos símbolos em qualquer gráfico (sem necessidade de configuração adicional), e é possível alternar facilmente entre os símbolos do gráfico sem afetar os EAs — eles não são recarregados quando o símbolo ou o período do gráfico é alterado.

PS. O comentário original foi publicado em inglês — por favor, leia-o para entender corretamente — a tradução automática pode gerar textos absurdos.

Clemence Benjamin
Clemence Benjamin | 6 out. 2025 em 06:02
Stanislav Korotky #:

Qual é o sentido real disso tudo? O raciocínio apresentado é irracional, pois os EAs são capazes, por padrão, de negociar diversos símbolos em qualquer gráfico (sem necessidade de configuração adicional), e é possível alternar facilmente entre os símbolos dos gráficos sem afetar os EAs — eles não são recarregados quando o símbolo ou o período do gráfico é alterado.

PS. O comentário original foi publicado em inglês — por favor, leia-o para entender corretamente — a tradução automática pode gerar textos absurdos.

Olá, Stanislav Korotky,

Obrigado por compartilhar sua perspectiva. Entendo perfeitamente seu ponto de vista — de fato, um EA pode negociar vários símbolos a partir de um único gráfico, e a troca manual de símbolos não recarrega nem interrompe o EA em execução.

No entanto, minha ideia visa especificamente situações em que é necessária a execução simultânea em vários pares — por exemplo, durante eventos noticiosos de alto impacto, quando você pode querer colocar ordens sincronizadas tanto no GBPUSD quanto no EURUSD exatamente no mesmo momento. Nesses casos, a troca manual de símbolos não é prática.

É por isso que enfatizo o gerenciamento programático de vários símbolos — garantindo que o EA possa lidar e executar negociações nos pares selecionados automaticamente, mesmo que esteja vinculado a um gráfico com um símbolo base diferente.

Arquitetura do sistema de aprendizado de máquina no MetaTrader 5 (Parte 2): Rotulagem de dados financeiros para aprendizado de máquina Arquitetura do sistema de aprendizado de máquina no MetaTrader 5 (Parte 2): Rotulagem de dados financeiros para aprendizado de máquina
Na segunda parte da série "MetaTrader 5 e aprendizado de máquina: guia prático", você entenderá por que rótulos simples podem confundir seus modelos e como aplicar técnicas avançadas, como o método da barreira tripla e a varredura de tendências, para definir variáveis-alvo confiáveis que levem o risco em consideração. Com exemplos práticos de implementações otimizadas em Python desses métodos de alto custo computacional, este guia mostra como transformar dados de mercado ruidosos em rótulos confiáveis, capazes de refletir as condições reais de negociação.
Recursos do Assistente MQL5 que você precisa conhecer (Parte 79): Uso dos osciladores Gator e A/D no aprendizado supervisionado Recursos do Assistente MQL5 que você precisa conhecer (Parte 79): Uso dos osciladores Gator e A/D no aprendizado supervisionado
No artigo anterior, concluímos a análise da combinação dos osciladores Gator e Acumulação/Distribuição (A/D) em sua aplicação convencional, baseada nos sinais brutos gerados por esses indicadores. Eles se complementam: o Gator atua como indicador de tendência, enquanto o oscilador Acumulação/Distribuição funciona como indicador de volume. Agora, daremos continuidade ao tema, investigando como o aprendizado supervisionado pode melhorar alguns dos padrões de sinal estudados anteriormente. Nossa abordagem utiliza uma rede neural convolucional (CNN), na qual a regressão por kernel e a similaridade baseada no produto escalar são empregadas para definir os tamanhos dos kernels e a quantidade de canais. Como de costume, implementaremos essa abordagem em um arquivo personalizado da classe de sinal, que interage com o Assistente MQL5 durante a criação do EA.
Arbitragem estatística com ações cointegradas (Parte 3): Configuração do banco de dados Arbitragem estatística com ações cointegradas (Parte 3): Configuração do banco de dados
Neste artigo, apresentamos um exemplo de implementação de um serviço em MQL5 para atualizar um banco de dados recém-criado, que será utilizado como fonte de dados para a análise e a negociação de uma cesta de ações cointegradas. Explicamos detalhadamente a lógica de modelagem do banco de dados e fornecemos uma descrição da estrutura dos dados (data dictionary) como material de referência. Também disponibilizamos scripts em MQL5 e Python para criar o banco de dados, inicializar seu esquema e carregar os dados de mercado.
Repensando as estratégias clássicas (Parte 15): Estratégia de rompimento da faixa de preços do dia anterior Repensando as estratégias clássicas (Parte 15): Estratégia de rompimento da faixa de preços do dia anterior
Muito antes do surgimento dos computadores, os traders já atuavam nos mercados financeiros e desenvolviam regras práticas para orientar suas decisões. Neste artigo, voltaremos a examinar uma conhecida estratégia de rompimento para avaliar se essa lógica de mercado, adquirida por meio da experiência, pode competir com abordagens sistemáticas. Nossos resultados mostram que, embora a estratégia original apresentasse uma elevada taxa de acerto, seus resultados eram instáveis e sua gestão de risco era deficiente. Ao aperfeiçoar essa abordagem, demonstraremos como o conhecimento acumulado pelos traders discricionários pode ser incorporado a estratégias de trading algorítmico mais robustas.