English Русский 中文 Español Deutsch 日本語
preview
MQL5 Trading Toolkit (Parte 2): Expansão e Aplicação da Biblioteca EX5 para Gerenciamento de Posições

MQL5 Trading Toolkit (Parte 2): Expansão e Aplicação da Biblioteca EX5 para Gerenciamento de Posições

MetaTrader 5Exemplos | 7 março 2025, 14:07
187 0
Wanateki Solutions LTD
Kelvin Muturi Muigua

Introdução

No primeiro artigo, analisamos detalhadamente as bibliotecas de código MQL5. Exploramos os diferentes tipos de bibliotecas, suas vantagens, a criação de bibliotecas EX5 e os componentes do arquivo de código-fonte da biblioteca (.mq5). Isso nos forneceu uma base sólida para compreender as bibliotecas EX5 e seu processo de criação. Em seguida, desenvolvemos um exemplo prático de uma biblioteca EX5 para gerenciamento de posições, demonstrando como implementar funções exportáveis no código MQL5.

Neste artigo, expandiremos a biblioteca EX5 para gerenciamento de posições e criaremos dois EAs básicos. Um desses EAs utilizará um painel gráfico de negociação e informações, demonstrando como importar e implementar a biblioteca EX5 para gerenciamento de posições na prática. Isso servirá como um exemplo real de como criar e integrar uma biblioteca EX5 ao seu código MQL5. Para começar, analisaremos o processo de importação e uso da biblioteca binária .ex5 já desenvolvida e compilada.


Como importar e utilizar uma biblioteca EX5

Para importar e utilizar uma biblioteca EX5 em seu código MQL5 (EAs, indicadores personalizados, scripts ou serviços), é necessário adicionar as diretivas #import abaixo das diretivas #property no cabeçalho ou na parte superior do arquivo de código-fonte. Para incluir a biblioteca binária compilada, comece especificando a diretiva #import, seguida do caminho do arquivo onde a biblioteca está armazenada. Por padrão, o MQL5 busca bibliotecas em dois locais para facilitar o acesso direto no código. O primeiro local é a pasta MQL5/Libraries, que é o diretório padrão para armazenamento de bibliotecas. Se a biblioteca não for encontrada lá, o MQL5 realiza uma busca na pasta onde o próprio programa MQL está localizado. Se a biblioteca EX5 estiver armazenada diretamente na pasta MQL5/Libraries/ ou na mesma pasta do código-fonte, basta indicar o nome da biblioteca entre aspas duplas após a diretiva #import, sem especificar o caminho da pasta.

Após especificar o caminho para a pasta da biblioteca, indique o nome da biblioteca seguido da extensão .ex5. Na linha seguinte, adicione as definições ou descrições de todos os protótipos de funções exportadas que precisam ser importadas para o seu código. Por fim, finalize o segmento de código de importação com outra diretiva #import para encerramento.

#import "FilePath/LibraryName.ex5" //-- Opening .EX5 Library import directive

   //-- Function definitions/descriptions prototypes
   int  FunctionPrototype1();
   void FunctionPrototype2(bool y);
   bool FunctionPrototype3(double x);

#import //--- Closing .EX5 Library import directive

Ao declarar a diretiva #import, é necessário incluir a extensão .ex5 após o nome da biblioteca. Se a extensão não for especificada, o MQL5 assumirá, por padrão, que você está importando uma biblioteca .DLL.

Também é possível importar e implementar várias bibliotecas .ex5 em um único arquivo MQL5. A estrutura do código para importar múltiplas bibliotecas .ex5 é semelhante à da importação de uma única biblioteca. A única diferença está na posição das diretivas de fechamento #import. Para importar várias bibliotecas, após a diretiva #import que fecha a primeira biblioteca, deve-se indicar o nome da próxima biblioteca .ex5 importada. Isso encerrará a primeira diretiva de importação e iniciará automaticamente a próxima, e assim por diante. Ao finalizar a última diretiva #import da última biblioteca, certifique-se de que ela termina sem um nome de biblioteca.

#import "FilePath/LibraryName.ex5"  //-- Opening .EX5 Library import directive

   //-- Function definitions/descriptions prototypes for the first library here
   int  FunctionPrototype1();
   void FunctionPrototype2(bool y);
   
#import "FilePath/SecondLibraryName.ex5"
   //-- Function definitions/descriptions prototypes for the second library here
   bool  FunctionPrototype();
   string FunctionPrototype2(bool z);

#import //--- Closing .EX5 Library import directive

Ao trabalhar com múltiplas bibliotecas em MQL5, é necessário que cada uma tenha um nome único. Não importa se essas bibliotecas estão armazenadas em pastas diferentes, ter nomes distintos é um requisito essencial para evitar erros.

Cada biblioteca cria seu próprio ambiente isolado, chamado de namespace (espaço de nomes). Isso significa que as funções dentro da biblioteca estão associadas ao seu próprio nome. Você pode nomear livremente as funções dentro da biblioteca, mesmo que coincidam com os nomes de funções internas do MQL5, sem se preocupar com conflitos. No entanto, geralmente é recomendado evitar essa prática para maior clareza.

Se funções com os mesmos nomes estiverem presentes em diferentes bibliotecas, o sistema aplicará regras específicas de prioridade para evitar conflitos ao chamá-las. Isso garante que não haja ambiguidade na execução de funções com nomes idênticos. Depois de importar com sucesso os protótipos de funções da biblioteca, você poderá integrá-los facilmente ao seu código e utilizá-los da mesma forma que qualquer outra função local definida por você.

A seguir, neste artigo, explicarei detalhadamente como implementar e utilizar bibliotecas EX5 na prática. Você encontrará duas demonstrações completas: uma na qual escreveremos o código de um EA baseado na estratégia de negociação VIDyA e outra que utiliza uma interface gráfica do usuário (GUI). Esses EAs integrarão e utilizarão nossa biblioteca EX5 especialmente desenvolvida para gerenciamento de posições. Esses exemplos práticos fornecerão informações valiosas sobre como incorporar bibliotecas EX5 em EAs reais.


Erros Comuns na Execução de Bibliotecas EX5

Depurar bibliotecas EX5 pode ser uma tarefa desafiadora, pois os erros mais comuns relacionados às funções importadas ocorrem durante a execução, quando o aplicativo MQL5 compilado é carregado no terminal de negociação. Esses erros geralmente surgem devido a problemas nas diretivas import, especificamente em caminhos ou nomes de arquivos da biblioteca, descrições de protótipos de funções, tipos, nomes, listas completas de parâmetros e valores de retorno durante as declarações de importação. O compilador não tem a responsabilidade de detectar esses erros durante a compilação, pois ele não tem acesso ao código-fonte da biblioteca importada, que já está encapsulada e compilada no formato binário executável (.ex5).

Qualquer arquivo de código-fonte contendo esses erros será compilado com sucesso, mas ao tentar carregar o aplicativo MQL5 compilado no terminal de negociação, ocorrerão erros de execução. Esses erros aparecem nas abas "Especialistas" ou "Jornal" do terminal MetaTrader 5. A seguir, estão listados os erros mais comuns:

Unresolved Import Function Call(cannot find 'Function_Name' in 'Library_Name.ex5')

    • Descrição: Esse erro de execução ocorre ao tentar carregar um aplicativo MQL5 no gráfico do MetaTrader 5 e aparece na aba "Especialistas". O erro é causado por definições incorretas ou descrições de protótipos de funções, como tipo, nome ou parâmetros fornecidos na diretiva import da biblioteca.
    • Solução: Certifique-se de que o segmento de código import da biblioteca contém as definições corretas dos protótipos de funções e recompile o seu código.

Unresolved import function call EX5 error


Cannot Open File 'Library_Name.ex5'(loading of ExpertAdvisor_Name (GBPJPY,M15) failed [0])

    • Descrição: Esse erro de execução ocorre ao tentar carregar um aplicativo MQL5 no gráfico do MetaTrader 5 e aparece na aba "Jornal". O erro ocorre quando o arquivo da biblioteca EX5 importado não pode ser encontrado e carregado.
    • Solução: Certifique-se de que o segmento de código import contém o caminho correto para a biblioteca e recompile o código.
can not open EX5 library file error

Embora possam surgir outros erros ao trabalhar com bibliotecas importadas no MQL5, os erros de execução mencionados acima são os mais comuns entre desenvolvedores iniciantes. Esses erros são fáceis de passar despercebidos e não são detectáveis pelo compilador durante o processo de compilação.


Como atualizar e redistribuir bibliotecas EX5

É essencial seguir a sequência correta ao redistribuir bibliotecas EX5 após cada atualização para garantir que as novas alterações sejam corretamente integradas aos projetos MQL5 que utilizam a biblioteca. A sequência de compilação é o passo mais importante no processo de atualização e redistribuição das bibliotecas em MQL5. Siga estas etapas para garantir que todas as novas modificações e atualizações sejam aplicadas corretamente a todos os projetos que importam a biblioteca:

  1. Compile o novo arquivo EX5: Comece compilando o arquivo de código-fonte atualizado da biblioteca .mq5 para gerar o novo arquivo binário executável .ex5.
  2. Atualize os protótipos de funções importadas: Em todos os projetos MQL5 que utilizam a biblioteca EX5, atualize todas as definições de importação dos protótipos de funções caso tenham sido modificadas na nova versão da biblioteca EX5.
  3. Compile os projetos: Recompile todos os projetos MQL5 que utilizam a biblioteca EX5.
Seguindo essa sequência, você garantirá que todas as atualizações da biblioteca EX5 sejam corretamente integradas a todos os projetos que a importam.


Função de trailing stop para stop-loss

Antes de implementarmos nossa biblioteca para gerenciamento de posições, precisamos expandi-la com a adição de algumas funções essenciais. Iniciaremos incluindo um módulo ou função para o gerenciamento de trailing stop-loss, pois nossa biblioteca não estará completa sem esse recurso essencial. O trailing stop é uma parte fundamental de qualquer estratégia de negociação, pois, quando bem implementado, pode aumentar a lucratividade do sistema e melhorar sua taxa de sucesso geral.

Chamaremos essa função de SetTrailingStopLoss(). Ela será responsável por definir o nível móvel de stop-loss para uma posição aberta, utilizando o ticket da posição como mecanismo de filtragem. A função receberá como argumentos o número do ticket da posição e o valor desejado do trailing stop em pips (pontos) e tentará atualizar o stop-loss da posição no servidor de negociação quando certas condições forem atendidas. Essa função deve ser chamada continuamente a cada tick, para que o trailing stop-loss seja ajustado em tempo real, uma vez que o status das posições-alvo está sempre mudando.

Primeiro, a função verifica se a negociação está permitida e se o valor especificado para o trailing stop-loss em pips (pontos) é válido. Em seguida, ela seleciona a posição, extrai e armazena todas as informações necessárias sobre o símbolo e calcula o preço do trailing stop-loss. Se o preço calculado for válido, a função enviará uma ordem ao servidor de negociação para definir o stop-loss. Se a ordem for executada com sucesso, a função retornará true; caso contrário, retornará false.

Vamos começar definindo a função. A função de trailing stop-loss terá o tipo bool e conterá dois parâmetros:

  1. ulong positionTicket - identificador único da posição que será modificada.
  2. int trailingStopLoss - nível desejado de stop-loss em pips (pontos) a partir do preço atual da posição.

A palavra-chave export indica que essa função da biblioteca pode ser chamada a partir de qualquer arquivo de código-fonte MQL5 ou projeto que a importe.

bool SetTrailingStopLoss(ulong positionTicket, int trailingStopLoss) export
  {
    //-- place the function body here
  }

Precisamos verificar se a negociação está permitida e se o parâmetro trailingStopLoss é maior que zero. Se qualquer uma dessas condições não for atendida, saímos da função e retornamos false para interromper a operação.

if(!TradingIsAllowed() || trailingStopLoss == 0)
     {
      return(false); //--- algo trading is disabled or trailing stop loss is invalid, exit function
     }

Em seguida, confirmamos e selecionamos a posição usando o positionTicket fornecido. Se a seleção da posição falhar, exibimos uma mensagem de erro e saímos da função.

//--- Confirm and select the position using the provided positionTicket
   ResetLastError(); //--- Reset error cache incase of ticket selection errors
   if(!PositionSelectByTicket(positionTicket))
     {
      //---Position selection failed
      Print("\r\n_______________________________________________________________________________________");
      Print(__FUNCTION__, ": Selecting position with ticket:", positionTicket, " failed. ERROR: ", GetLastError());
      return(false); //-- Exit the function
     }

Depois, criamos algumas variáveis que nos ajudarão a armazenar e verificar o trailing stop-loss. Começamos com a criação da variável slPrice para armazenar o preço calculado do trailing stop-loss e, em seguida, armazenamos as propriedades da posição, como símbolo, preço de entrada, volume, preços atuais de stop-loss e take-profit, além do tipo de posição.

//-- create variable to store the calculated trailing sl prices to send to the trade server
   double slPrice = 0.0;

//--- Position ticket selected, save the position properties
   string positionSymbol = PositionGetString(POSITION_SYMBOL);
   double entryPrice = PositionGetDouble(POSITION_PRICE_OPEN);
   double volume = PositionGetDouble(POSITION_VOLUME);
   double currentPositionSlPrice = PositionGetDouble(POSITION_SL);
   double currentPositionTpPrice = PositionGetDouble(POSITION_TP);
   ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);

Da mesma forma, continuamos armazenando diversas propriedades do símbolo associadas à posição selecionada. Essas propriedades também serão usadas posteriormente para verificar e calcular o trailing stop-loss.

//-- Get some information about the positions symbol
   int symbolDigits = (int)SymbolInfoInteger(positionSymbol, SYMBOL_DIGITS); //-- Number of symbol decimal places
   int symbolStopLevel = (int)SymbolInfoInteger(positionSymbol, SYMBOL_TRADE_STOPS_LEVEL);
   double symbolPoint = SymbolInfoDouble(positionSymbol, SYMBOL_POINT);
   double positionPriceCurrent = PositionGetDouble(POSITION_PRICE_CURRENT);
   int spread = (int)SymbolInfoInteger(positionSymbol, SYMBOL_SPREAD);

Verificamos se o valor especificado do stop-loss é inferior ao nível de stop do símbolo. Se for, ajustamos o trailing stop-loss para que ele seja pelo menos igual ao nível mínimo permitido pelo símbolo.

//-- Check if the trailing stop loss is less than the symbol trade stop levels
   if(trailingStopLoss < symbolStopLevel)
     {
      //-- Trailing stop loss is less than the allowed level for the current symbol
      trailingStopLoss = symbolStopLevel; //-- Set it to the symbol stop level by default
     }

O próximo passo envolve calcular o preço do trailing stop-loss com base no fato de a posição ser uma compra ou uma venda. Para posições de compra, o stop-loss é definido abaixo do preço atual, enquanto para posições de venda, o stop-loss é definido acima do preço atual. Também verificamos se o preço calculado do stop-loss está dentro dos limites aceitáveis.

//-- Calculate and store the trailing stop loss price
   if(positionType == POSITION_TYPE_BUY)
     {
      slPrice = positionPriceCurrent - (trailingStopLoss * symbolPoint);

      //-- Check if the proposed slPrice for the trailing stop loss is valid
      if(slPrice < entryPrice || slPrice < currentPositionSlPrice)
        {
         return(false); //-- Exit the function, proposed trailing stop loss price is invalid
        }
     }
   else  //-- SELL POSITION
     {
      slPrice = positionPriceCurrent + (trailingStopLoss * symbolPoint);

      //-- Check if the proposed slPrice for the trailing stop loss is valid
      if(slPrice > entryPrice || slPrice > currentPositionSlPrice)
        {
         return(false); //-- Exit the function, proposed trailing stop loss price is invalid
        }
     }

Antes de definir o trailing stop-loss, registramos os dados da posição no log do MetaTrader 5. Isso inclui o símbolo, tipo de posição, volume, preço de entrada, preços atuais de stop-loss e take-profit, além de outras informações importantes.

//-- Print position properties before setting the trailing stop loss
   string positionProperties = "--> "  + positionSymbol + " " + EnumToString(positionType) + " Trailing Stop Loss Modification Details" +
                               " <--\r\n";
   positionProperties += "------------------------------------------------------------\r\n";
   positionProperties += "Ticket: " + (string)positionTicket + "\r\n";
   positionProperties += "Volume: " + StringFormat("%G", volume) + "\r\n";
   positionProperties += "Price Open: " + StringFormat("%G", entryPrice) + "\r\n";
   positionProperties += "Current SL: " + StringFormat("%G", currentPositionSlPrice) + "   -> New Trailing SL: " + (string)slPrice + "\r\n";
   positionProperties += "Current TP: " + StringFormat("%G", currentPositionTpPrice) + "\r\n";
   positionProperties += "Comment: " + PositionGetString(POSITION_COMMENT) + "\r\n";
   positionProperties += "Magic Number: " + (string)PositionGetInteger(POSITION_MAGIC) + "\r\n";
   positionProperties += "---";
   Print(positionProperties);

Por fim, redefinimos as estruturas tradeRequest e tradeResult para zero. Em seguida, inicializamos os parâmetros necessários para a configuração do stop-loss e do take-profit.

//-- reset the the tradeRequest and tradeResult values by zeroing them
   ZeroMemory(tradeRequest);
   ZeroMemory(tradeResult);

//-- initialize the parameters to set the sltp
   tradeRequest.action = TRADE_ACTION_SLTP; //-- Trade operation type for setting sl and tp
   tradeRequest.position = positionTicket;
   tradeRequest.symbol = positionSymbol;
   tradeRequest.sl = slPrice;
   tradeRequest.tp = currentPositionTpPrice;

Por fim, redefinimos o cache de erros e enviamos a ordem ao servidor de negociação até que ela seja executada com sucesso ou até que sejam feitas 101 tentativas. Se a ordem for executada com sucesso, exibimos uma mensagem de confirmação, retornamos o valor true e saímos da função. Se a solicitação da ordem falhar, processamos o erro, retornamos false e encerramos a função.

ResetLastError(); //--- reset error cache so that we get an accurate runtime error code in the ErrorAdvisor function

   for(int loop = 0; loop <= 100; loop++) //-- try modifying the sl and tp 101 times untill the request is successful
     {
      //--- send order to the trade server
      if(OrderSend(tradeRequest, tradeResult))
        {
         //-- Confirm order execution
         if(tradeResult.retcode == 10008 || tradeResult.retcode == 10009)
           {
            PrintFormat("Successfully set the Trailing SL for #%I64d %s %s", positionTicket, positionSymbol, EnumToString(positionType));
            PrintFormat("retcode=%u  runtime_code=%u", tradeResult.retcode, GetLastError());
            Print("_______________________________________________________________________________________\r\n\r\n");
            return(true); //-- exit function
            break; //--- success - order placed ok. exit for loop
           }
        }
      else  //-- Order request failed
        {
         //-- order not sent or critical error found
         if(!ErrorAdvisor(__FUNCTION__, positionSymbol, tradeResult.retcode) || IsStopped())
           {
            PrintFormat("ERROR setting the Trailing SL for #%I64d %s %s", positionTicket, positionSymbol, EnumToString(positionType));
            Print("_______________________________________________________________________________________\r\n\r\n");
            return(false); //-- exit function
            break; //-- exit for loop
           }
        }
     }
   return(false);
  }

Certifique-se de que os segmentos de código da função SetTrailingStopLoss() sejam executados na seguinte sequência:

bool SetTrailingStopLoss(ulong positionTicket, int trailingStopLoss) export
  {
//-- first check if the EA is allowed to trade and the trailing stop loss parameter is more than zero
   if(!TradingIsAllowed() || trailingStopLoss == 0)
     {
      return(false); //--- algo trading is disabled or trailing stop loss is invalid, exit function
     }

//--- Confirm and select the position using the provided positionTicket
   ResetLastError(); //--- Reset error cache incase of ticket selection errors
   if(!PositionSelectByTicket(positionTicket))
     {
      //---Position selection failed
      Print("\r\n_______________________________________________________________________________________");
      Print(__FUNCTION__, ": Selecting position with ticket:", positionTicket, " failed. ERROR: ", GetLastError());
      return(false); //-- Exit the function
     }

//-- create variable to store the calculated trailing sl prices to send to the trade server
   double slPrice = 0.0;

//--- Position ticket selected, save the position properties
   string positionSymbol = PositionGetString(POSITION_SYMBOL);
   double entryPrice = PositionGetDouble(POSITION_PRICE_OPEN);
   double volume = PositionGetDouble(POSITION_VOLUME);
   double currentPositionSlPrice = PositionGetDouble(POSITION_SL);
   double currentPositionTpPrice = PositionGetDouble(POSITION_TP);
   ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);

//-- Get some information about the positions symbol
   int symbolDigits = (int)SymbolInfoInteger(positionSymbol, SYMBOL_DIGITS); //-- Number of symbol decimal places
   int symbolStopLevel = (int)SymbolInfoInteger(positionSymbol, SYMBOL_TRADE_STOPS_LEVEL);
   double symbolPoint = SymbolInfoDouble(positionSymbol, SYMBOL_POINT);
   double positionPriceCurrent = PositionGetDouble(POSITION_PRICE_CURRENT);
   int spread = (int)SymbolInfoInteger(positionSymbol, SYMBOL_SPREAD);

//-- Check if the trailing stop loss is less than the symbol trade stop levels
   if(trailingStopLoss < symbolStopLevel)
     {
      //-- Trailing stop loss is less than the allowed level for the current symbol
      trailingStopLoss = symbolStopLevel; //-- Set it to the symbol stop level by default
     }

//-- Calculate and store the trailing stop loss price
   if(positionType == POSITION_TYPE_BUY)
     {
      slPrice = positionPriceCurrent - (trailingStopLoss * symbolPoint);

      //-- Check if the proposed slPrice for the trailing stop loss is valid
      if(slPrice < entryPrice || slPrice < currentPositionSlPrice)
        {
         return(false); //-- Exit the function, proposed trailing stop loss price is invalid
        }
     }
   else  //-- SELL POSITION
     {
      slPrice = positionPriceCurrent + (trailingStopLoss * symbolPoint);

      //-- Check if the proposed slPrice for the trailing stop loss is valid
      if(slPrice > entryPrice || slPrice > currentPositionSlPrice)
        {
         return(false); //-- Exit the function, proposed trailing stop loss price is invalid
        }
     }

//-- Print position properties before setting the trailing stop loss
   string positionProperties = "--> "  + positionSymbol + " " + EnumToString(positionType) + " Trailing Stop Loss Modification Details" +
                               " <--\r\n";
   positionProperties += "------------------------------------------------------------\r\n";
   positionProperties += "Ticket: " + (string)positionTicket + "\r\n";
   positionProperties += "Volume: " + StringFormat("%G", volume) + "\r\n";
   positionProperties += "Price Open: " + StringFormat("%G", entryPrice) + "\r\n";
   positionProperties += "Current SL: " + StringFormat("%G", currentPositionSlPrice) + "   -> New Trailing SL: " + (string)slPrice + "\r\n";
   positionProperties += "Current TP: " + StringFormat("%G", currentPositionTpPrice) + "\r\n";
   positionProperties += "Comment: " + PositionGetString(POSITION_COMMENT) + "\r\n";
   positionProperties += "Magic Number: " + (string)PositionGetInteger(POSITION_MAGIC) + "\r\n";
   positionProperties += "---";
   Print(positionProperties);

//-- reset the the tradeRequest and tradeResult values by zeroing them
   ZeroMemory(tradeRequest);
   ZeroMemory(tradeResult);

//-- initialize the parameters to set the sltp
   tradeRequest.action = TRADE_ACTION_SLTP; //-- Trade operation type for setting sl and tp
   tradeRequest.position = positionTicket;
   tradeRequest.symbol = positionSymbol;
   tradeRequest.sl = slPrice;
   tradeRequest.tp = currentPositionTpPrice;

   ResetLastError(); //--- reset error cache so that we get an accurate runtime error code in the ErrorAdvisor function

   for(int loop = 0; loop <= 100; loop++) //-- try modifying the sl and tp 101 times untill the request is successful
     {
      //--- send order to the trade server
      if(OrderSend(tradeRequest, tradeResult))
        {
         //-- Confirm order execution
         if(tradeResult.retcode == 10008 || tradeResult.retcode == 10009)
           {
            PrintFormat("Successfully set the Trailing SL for #%I64d %s %s", positionTicket, positionSymbol, EnumToString(positionType));
            PrintFormat("retcode=%u  runtime_code=%u", tradeResult.retcode, GetLastError());
            Print("_______________________________________________________________________________________\r\n\r\n");
            return(true); //-- exit function
            break; //--- success - order placed ok. exit for loop
           }
        }
      else  //-- Order request failed
        {
         //-- order not sent or critical error found
         if(!ErrorAdvisor(__FUNCTION__, positionSymbol, tradeResult.retcode) || IsStopped())
           {
            PrintFormat("ERROR setting the Trailing SL for #%I64d %s %s", positionTicket, positionSymbol, EnumToString(positionType));
            Print("_______________________________________________________________________________________\r\n\r\n");
            return(false); //-- exit function
            break; //-- exit for loop
           }
        }
     }
   return(false);
  }



Função para fechar todas as posições

Essa função foi projetada para ser altamente flexível e será responsável por fechar todas as posições abertas com base nos parâmetros especificados. Vamos chamá-la de CloseAllPositions(). Ela varre as posições abertas correspondentes aos argumentos fornecidos, como símbolo e número mágico, e tenta fechá-las. Se a negociação não estiver permitida, a função interromperá sua execução imediatamente. A função percorrerá todas as posições abertas, filtrará aquelas que atendem aos critérios especificados e fechará todas as posições correspondentes.

Depois de tentar fechar todas as posições, a função entrará em um laço para verificar se todas as posições-alvo foram realmente fechadas, processar quaisquer erros e garantir que não fiquemos presos em um laço infinito. Após o fechamento bem-sucedido de todas as posições, a função sairá retornando true. Caso contrário, retornará false.

Vamos começar definindo a função CloseAllPositions(). Ela retornará um valor booleano e aceitará dois parâmetros com valores padrão:

  1. string symbol: O valor padrão será ALL_SYMBOLS.
  2. ulong magicNumber: O valor padrão será 0.

bool CloseAllPositions(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export
  {
//-- Functions body goes here
  }

Precisamos verificar se a negociação está permitida. Se a negociação não for permitida, saímos da função e retornamos false.

if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

Criamos uma nova variável booleana returnThis para armazenar o valor de retorno da função e atribuímos a ela um valor padrão.

bool returnThis = false;

Extraímos e armazenamos o número total de posições abertas e usamos esse valor em um laço for, que nos permitirá acessar todas as posições abertas e processá-las. Em cada iteração, armazenamos as propriedades da posição selecionada e utilizamos esses dados para filtrar as posições com base no símbolo e no número mágico fornecidos. Se a posição não atender aos critérios, passamos para a próxima posição. Se a posição corresponder aos critérios, fechamos a posição usando a função ClosePositionByTicket().

int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);

      //-- Filter positions by symbol and magic number
      if(
         (symbol != ALL_SYMBOLS && symbol != selectedSymbol) ||
         (magicNumber != 0 && positionMagicNo != magicNumber)
      )
        {
         continue;
        }

      //-- Close the position
      ClosePositionByTicket(positionTicket);
     }

Agora, percorremos todas as posições abertas especificadas e enviamos solicitações de fechamento ao servidor de negociação. Antes de finalizar a função, precisamos confirmar que todas as posições-alvo foram de fato fechadas. Para isso, utilizaremos um laço que chamará recursivamente a função CloseAllPositions() até que todas as posições que atendam aos nossos critérios tenham sido fechadas. Em cada iteração, tentaremos fechar todas as posições restantes, pausaremos a execução por um curto período para evitar sobrecarregar o servidor de negociação e aumentaremos um contador de interrupções para evitar ciclos infinitos. Também verificaremos a ocorrência de erros críticos e outras condições de saída, como a interrupção do script ou a superação do número máximo de iterações. Se qualquer uma dessas condições for atendida, sairemos do laço.

int breakerBreaker = 0; //-- Variable that safeguards and makes sure we are not locked in an infinite loop
   while(SymbolPositionsTotal(symbol, magicNumber) > 0)
     {
      breakerBreaker++;
      CloseAllPositions(symbol, magicNumber); //-- We still have some open positions, do a function callback
      Sleep(100); //-- Micro sleep to pace the execution and give some time to the trade server

      //-- Check for critical errors so that we exit the loop if we run into trouble
      if(!ErrorAdvisor(__FUNCTION__, symbol, GetLastError()) || IsStopped() || breakerBreaker > 101)
        {
         break;
        }
     }

Reconfirmamos que todas as posições-alvo foram fechadas e armazenamos esse status na variável de retorno antes da finalização da função.

if(SymbolPositionsTotal(symbol, magicNumber) == 0)
     {
      returnThis = true; //-- Save this status for the function return value
     }

   return(returnThis);

Confirme que todos os segmentos de código da função CloseAllPositions() estão completos na sequência abaixo:

bool CloseAllPositions(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export
  {
//-- first check if the EA is allowed to trade
   if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

   bool returnThis = false;

//-- Scan for symbol and magic number specific positions and close them
   int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);

      //-- Filter positions by symbol and magic number
      if(
         (symbol != ALL_SYMBOLS && symbol != selectedSymbol) ||
         (magicNumber != 0 && positionMagicNo != magicNumber)
      )
        {
         continue;
        }

      //-- Close the position
      ClosePositionByTicket(positionTicket);
     }

//-- Confirm that we have closed all the positions being targeted
   int breakerBreaker = 0; //-- Variable that safeguards and makes sure we are not locked in an infinite loop
   while(SymbolPositionsTotal(symbol, magicNumber) > 0)
     {
      breakerBreaker++;
      CloseAllPositions(symbol, magicNumber); //-- We still have some open positions, do a function callback
      Sleep(100); //-- Micro sleep to pace the execution and give some time to the trade server

      //-- Check for critical errors so that we exit the loop if we run into trouble
      if(!ErrorAdvisor(__FUNCTION__, symbol, GetLastError()) || IsStopped() || breakerBreaker > 101)
        {
         break;
        }
     }

//-- Final confirmations that all targeted positions have been closed
   if(SymbolPositionsTotal(symbol, magicNumber) == 0)
     {
      returnThis = true; //-- Save this status for the function return value
     }

   return(returnThis);
  }


Sobrecarga da função para fechamento de todas as posições

Para maior conveniência, criaremos uma sobrecarga da função CloseAllPositions() que não aceitará parâmetros e fechará todas as posições abertas na conta ao ser chamada. Essa função também poderá ser exportada e utilizada na biblioteca EX5 para gerenciamento de posições.

//+------------------------------------------------------------------+
//| CloseAllPositions(): Closes all positions in the account         |
//+------------------------------------------------------------------+
bool CloseAllPositions() export
  {
   return(CloseAllPositions(ALL_SYMBOLS, 0));
  }


Organização das funções de fechamento de posições

Ao navegar nos fóruns de desenvolvedores MQL5, você frequentemente encontrará perguntas de iniciantes pedindo ajuda para criar algoritmos que organizem e gerenciem diferentes operações de posição, como fechar ou modificar posições específicas com base em critérios como número mágico, lucro ou prejuízo, e assim por diante. A biblioteca de funções a seguir foi projetada para atender a essa necessidade, facilitando e acelerando a implementação eficiente dessas operações.

As funções de filtragem e ordenação para fechamento de posições apresentadas abaixo seguem um método semelhante ao da função CloseAllPositions(), mas possuem algumas diferenças. Elas utilizam uma abordagem de programação recursiva para garantir que todas as posições especificadas sejam fechadas e incluem logs de rastreamento para registrar quaisquer erros detectados no log do EA, possibilitando sua análise e diagnóstico pelo usuário final. Um benefício adicional dessas funções é a alta taxa de sucesso na execução de suas tarefas, pois elas escaneiam recursivamente erros corrigíveis e enviam múltiplas tentativas de execução das solicitações de negociação para garantir a conclusão bem-sucedida das ordens.


Fechamento de todas as posições de compra

A função CloseAllBuyPositions() é responsável por fechar todas as posições de compra abertas que atendam aos parâmetros ou argumentos fornecidos, como nome do símbolo e número mágico. A função retorna um valor booleano true se todas as posições especificadas forem fechadas com sucesso e false caso contrário.

bool CloseAllBuyPositions(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export
  {
//-- first check if the EA is allowed to trade
   if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

   bool returnThis = false;

//-- Scan for symbol and magic number specific buy positions and close them
   int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);
      ulong positionType = PositionGetInteger(POSITION_TYPE);

      //-- Filter positions by symbol, type and magic number
      if(
         (symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (positionType != POSITION_TYPE_BUY) ||
         (magicNumber != 0 && positionMagicNo != magicNumber)
      )
        {
         continue;
        }

      //-- Close the position
      ClosePositionByTicket(positionTicket);
     }

//-- Confirm that we have closed all the buy positions being targeted
   int breakerBreaker = 0; //-- Variable that safeguards and makes sure we are not locked in an infinite loop
   while(SymbolBuyPositionsTotal(symbol, magicNumber) > 0)
     {
      breakerBreaker++;
      CloseAllBuyPositions(symbol, magicNumber); //-- We still have some open buy positions, do a function callback
      Sleep(100); //-- Micro sleep to pace the execution and give some time to the trade server

      //-- Check for critical errors so that we exit the loop if we run into trouble
      if(!ErrorAdvisor(__FUNCTION__, symbol, GetLastError()) || IsStopped() || breakerBreaker > 101)
        {
         break;
        }
     }

   if(SymbolBuyPositionsTotal(symbol, magicNumber) == 0)
     {
      returnThis = true;
     }
   return(returnThis);
  }

Fechamento de todas as posições de venda

A função CloseAllSellPositions() é responsável por fechar todas as posições de venda abertas que atendam aos parâmetros ou argumentos fornecidos, como nome do símbolo e número mágico. A função retorna um valor booleano true se todas as posições especificadas forem fechadas com sucesso e false caso contrário.

bool CloseAllSellPositions(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export
  {
//-- first check if the EA is allowed to trade
   if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

   bool returnThis = false;

//-- Scan for symbol and magic number specific sell positions and close them
   int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);
      ulong positionType = PositionGetInteger(POSITION_TYPE);

      //-- Filter positions by symbol, type and magic number
      if(
         (symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (positionType != POSITION_TYPE_SELL) ||
         (magicNumber != 0 && positionMagicNo != magicNumber)
      )
        {
         continue;
        }

      //-- Close the position
      ClosePositionByTicket(positionTicket);
     }

//-- Confirm that we have closed all the sell positions being targeted
   int breakerBreaker = 0; //-- Variable that safeguards and makes sure we are not locked in an infinite loop
   while(SymbolSellPositionsTotal(symbol, magicNumber) > 0)
     {
      breakerBreaker++;
      CloseAllSellPositions(symbol, magicNumber); //-- We still have some open sell positions, do a function callback
      Sleep(100); //-- Micro sleep to pace the execution and give some time to the trade server

      //-- Check for critical errors so that we exit the loop if we run into trouble
      if(!ErrorAdvisor(__FUNCTION__, symbol, GetLastError()) || IsStopped() || breakerBreaker > 101)
        {
         break;
        }
     }

   if(SymbolSellPositionsTotal(symbol, magicNumber) == 0)
     {
      returnThis = true;
     }
   return(returnThis);
  }



Fechamento de todas as posições por número mágico

A função CloseAllMagicPositions() fecha todas as posições abertas que correspondam ao número mágico especificado como parâmetro ou argumento da função. A função retorna um valor booleano true se todas as posições especificadas forem fechadas com sucesso e false caso contrário.

bool CloseAllMagicPositions(ulong magicNumber) export
  {
//-- first check if the EA is allowed to trade
   if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

   bool returnThis = false;

//-- Variables to store the selected positions data
   ulong positionTicket, positionMagicNo;
   string positionSymbol;

//-- Scan for magic number specific positions and close them
   int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      positionMagicNo = PositionGetInteger(POSITION_MAGIC);
      positionSymbol = PositionGetString(POSITION_SYMBOL);

      //-- Filter positions by magic number
      if(magicNumber == positionMagicNo)
        {
         //-- Close the position
         ClosePositionByTicket(positionTicket);
        }
     }

//-- Confirm that we have closed all the positions being targeted
   int breakerBreaker = 0; //-- Variable that safeguards and makes sure we are not locked in an infinite loop
   while(MagicPositionsTotal(magicNumber) > 0)
     {
      breakerBreaker++;
      CloseAllMagicPositions(magicNumber); //-- We still have some open positions, do a function callback
      Sleep(100); //-- Micro sleep to pace the execution and give some time to the trade server

      //-- Check for critical errors so that we exit the loop if we run into trouble
      if(!ErrorAdvisor(__FUNCTION__, positionSymbol, GetLastError()) || IsStopped() || breakerBreaker > 101)
        {
         break;
        }
     }

   if(MagicPositionsTotal(magicNumber) == 0)
     {
      returnThis = true;
     }
   return(returnThis);
  }



Fechamento de todas as posições lucrativas

A função CloseAllProfitablePositions() fecha todas as posições abertas que estejam em lucro e que correspondam aos parâmetros fornecidos, como nome do símbolo e número mágico. A função retorna um valor booleano true se todas as posições especificadas forem fechadas com sucesso e false caso contrário.

bool CloseAllProfitablePositions(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export
  {
//-- first check if the EA is allowed to trade
   if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

//-- Scan for profitable positions that match the specified symbol and magic number to close them
   int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);
      double positionProfit = PositionGetDouble(POSITION_PROFIT);

      //-- Filter positions by symbol, magic number and profit
      if(
         ((symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (magicNumber != 0 && positionMagicNo != magicNumber)) ||
         positionProfit <= 0
      )
        {
         continue;
        }

      //-- Close the position
      ClosePositionByTicket(positionTicket);
     }
   return(true);
  }

___


Fechamento de todas as posições lucrativas de compra

A função CloseAllProfitableBuyPositions() fecha todas as posições de compra abertas que estejam em lucro e que correspondam aos parâmetros fornecidos, como nome do símbolo e número mágico. A função retorna o valor lógico true se todas as posições especificadas forem fechadas com sucesso e false caso contrário.

bool CloseAllProfitableBuyPositions(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export
  {
//-- first check if the EA is allowed to trade
   if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

//-- Scan for profitable positions that match the specified symbol and magic number to close them
   int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);
      double positionProfit = PositionGetDouble(POSITION_PROFIT);

      //-- Filter positions by symbol, magic number, profit and type
      if(
         ((symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (magicNumber != 0 && positionMagicNo != magicNumber)) ||
         positionProfit <= 0 || PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_BUY
      )
        {
         continue;
        }

      //-- Close the position
      ClosePositionByTicket(positionTicket);
     }
   return(true);
  }


Fechamento de todas as posições lucrativas de venda

A função CloseAllProfitableSellPositions() fecha todas as posições de venda abertas que estejam em lucro e que correspondam aos parâmetros fornecidos, como nome do símbolo e número mágico. A função retorna o valor lógico true se todas as posições especificadas forem fechadas com sucesso e false caso contrário.

bool CloseAllProfitableSellPositions(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export
  {
//-- first check if the EA is allowed to trade
   if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

//-- Scan for profitable positions that match the specified symbol and magic number to close them
   int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);
      double positionProfit = PositionGetDouble(POSITION_PROFIT);

      //-- Filter positions by symbol, magic number, profit and type
      if(
         ((symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (magicNumber != 0 && positionMagicNo != magicNumber)) ||
         positionProfit <= 0 || PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_SELL
      )
        {
         continue;
        }

      //-- Close the position
      ClosePositionByTicket(positionTicket);
     }
   return(true);
  }


Fechamento de todas as posições em prejuízo

A função CloseAllLossPositions() fecha todas as posições abertas que estejam em prejuízo e que correspondam aos parâmetros fornecidos, como nome do símbolo e número mágico. A função retorna o valor true se todas as posições especificadas forem fechadas com sucesso e false caso contrário.

bool CloseAllLossPositions(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export
  {
//-- first check if the EA is allowed to trade
   if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

//-- Scan for loss positions that match the specified symbol and magic number and close them
   int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);
      double positionProfit = PositionGetDouble(POSITION_PROFIT);

      //-- Filter positions by symbol, magic number and profit
      if(
         ((symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (magicNumber != 0 && positionMagicNo != magicNumber)) ||
         positionProfit > 0
      )
        {
         continue;
        }

      //-- Close the position
      ClosePositionByTicket(positionTicket);
     }

   return(true);
  }


Fechamento de todas as posições em prejuízo de compra

A função CloseAllLossBuyPositions() fecha todas as posições de compra abertas que estejam em prejuízo e que correspondam aos parâmetros fornecidos, como nome do símbolo e número mágico. A função retorna o valor lógico true se todas as posições especificadas forem fechadas com sucesso e false caso contrário.

bool CloseAllLossBuyPositions(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export
  {
//-- first check if the EA is allowed to trade
   if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

//-- Scan for loss positions that match the specified symbol and magic number and close them
   int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);
      double positionProfit = PositionGetDouble(POSITION_PROFIT);

      //-- Filter positions by symbol, magic number, profit and type
      if(
         ((symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (magicNumber != 0 && positionMagicNo != magicNumber)) ||
         positionProfit > 0 || PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_BUY
      )
        {
         continue;
        }

      //-- Close the position
      ClosePositionByTicket(positionTicket);
     }

   return(true);
  }


Fechamento de todas as posições em prejuízo de venda

A função CloseAllLossSellPositions() fecha todas as posições de venda abertas que estejam em prejuízo e que correspondam aos parâmetros fornecidos, como nome do símbolo e número mágico. A função retorna o valor lógico true se todas as posições especificadas forem fechadas com sucesso e false caso contrário.

bool CloseAllLossSellPositions(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export
  {
//-- first check if the EA is allowed to trade
   if(!TradingIsAllowed())
     {
      return(false); //--- algo trading is disabled, exit function
     }

//-- Scan for loss positions that match the specified symbol and magic number and close them
   int totalOpenPositions = PositionsTotal();
   for(int x = 0; x < totalOpenPositions; x++)
     {
      //--- Get position properties
      ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);
      double positionProfit = PositionGetDouble(POSITION_PROFIT);

      //-- Filter positions by symbol, magic number, profit and type
      if(
         ((symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (magicNumber != 0 && positionMagicNo != magicNumber)) ||
         positionProfit > 0 || PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_SELL
      )
        {
         continue;
        }

      //-- Close the position
      ClosePositionByTicket(positionTicket);
     }

   return(true);
  }  



Funções de status de posição

Ao desenvolver um sistema de negociação, é fundamental monitorar o estado da conta em tempo real, utilizando dados sobre diversas posições. Independentemente de você estar criando uma estratégia baseada em grid ou uma abordagem mais conservadora baseada em price action, ter uma visão clara e detalhada de todas as posições abertas é essencial para o sucesso do seu sistema. No entanto, não existem funções padrão no MQL5 que forneçam essas informações diretamente. Nossa biblioteca EX5 foi projetada para simplificar a coleta de informações sobre posições, permitindo que você faça chamadas de função em uma única linha de código. As funções exportáveis apresentadas abaixo fornecerão a vantagem necessária para monitorar suas posições e decidir sobre fechá-las ou aumentá-las, facilitando a gestão do seu sistema de negociação.


Obtenção de dados das posições

A função GetPositionsData() desempenha um papel crucial na coleta e armazenamento de todas as informações necessárias sobre o status das posições. Ela armazena esses dados em variáveis globais, que podem ser acessadas facilmente dentro de toda a biblioteca. Essas variáveis devem ser atualizadas continuamente a cada tick para garantir sua precisão e confiabilidade.

Vamos definir as seguintes declarações de variáveis globais no início da biblioteca, logo abaixo das declarações das estruturas de dados das operações de negociação.

string accountCurrency = AccountInfoString(ACCOUNT_CURRENCY);

//-- Position status global variables
//-------------------------------------------------------------------------------------------------------------------
int accountBuyPositionsTotal = 0, accountSellPositionsTotal = 0,
    symbolPositionsTotal = 0, symbolBuyPositionsTotal = 0, symbolSellPositionsTotal = 0,
    magicPositionsTotal = 0, magicBuyPositionsTotal = 0, magicSellPositionsTotal = 0;
double accountPositionsVolumeTotal = 0.0, accountBuyPositionsVolumeTotal = 0.0, accountSellPositionsVolumeTotal = 0.0,
       accountBuyPositionsProfit = 0.0, accountSellPositionsProfit = 0.0,
       symbolPositionsVolumeTotal = 0.0, symbolBuyPositionsVolumeTotal = 0.0,
       symbolSellPositionsVolumeTotal = 0.0, symbolPositionsProfit = 0.0,
       symbolBuyPositionsProfit = 0.0, symbolSellPositionsProfit = 0.0,
       magicPositionsVolumeTotal = 0.0, magicBuyPositionsVolumeTotal = 0.0,
       magicSellPositionsVolumeTotal = 0.0, magicPositionsProfit = 0.0,
       magicBuyPositionsProfit = 0.0, magicSellPositionsProfit = 0.0;

Atualizaremos e armazenaremos os dados do status da posição dentro da função GetPositionsData() descrita abaixo.

void GetPositionsData(string symbol, ulong magicNumber)
  {
//-- Reset the acount open positions status
   accountBuyPositionsTotal = 0;
   accountSellPositionsTotal = 0;
   accountPositionsVolumeTotal = 0.0;
   accountBuyPositionsVolumeTotal = 0.0;
   accountSellPositionsVolumeTotal = 0.0;
   accountBuyPositionsProfit = 0.0;
   accountSellPositionsProfit = 0.0;

//-- Reset the EA's magic open positions status
   magicPositionsTotal = 0;
   magicBuyPositionsTotal = 0;
   magicSellPositionsTotal = 0;
   magicPositionsVolumeTotal = 0.0;
   magicBuyPositionsVolumeTotal = 0.0;
   magicSellPositionsVolumeTotal = 0.0;
   magicPositionsProfit = 0.0;
   magicBuyPositionsProfit = 0.0;
   magicSellPositionsProfit = 0.0;

//-- Reset the symbol open positions status
   symbolPositionsTotal = 0;
   symbolBuyPositionsTotal = 0;
   symbolSellPositionsTotal = 0;
   symbolPositionsVolumeTotal = 0.0;
   symbolBuyPositionsVolumeTotal = 0.0;
   symbolSellPositionsVolumeTotal = 0.0;
   symbolPositionsProfit = 0.0;
   symbolBuyPositionsProfit = 0.0;
   symbolSellPositionsProfit = 0.0;

//-- Update and save the open positions status with realtime data
   int totalOpenPositions = PositionsTotal();
   if(totalOpenPositions > 0)
     {
      //-- Scan for symbol and magic number specific positions and save their status
      for(int x = 0; x < totalOpenPositions; x++)
        {
         //--- Get position properties
         ulong  positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
         string selectedSymbol = PositionGetString(POSITION_SYMBOL);
         ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);

         //-- Filter positions by magic number
         if(magicNumber != 0 && positionMagicNo != magicNumber)
           {
            continue;
           }

         //-- Save the account positions status first
         accountPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME);

         if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
           {
            //-- Account properties
            ++accountBuyPositionsTotal;
            accountBuyPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME);
            accountBuyPositionsProfit += PositionGetDouble(POSITION_PROFIT);
           }
         else //-- POSITION_TYPE_SELL
           {
            //-- Account properties
            ++accountSellPositionsTotal;
            accountSellPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME);
            accountSellPositionsProfit += PositionGetDouble(POSITION_PROFIT);
           }

         //-- Filter positions openend by EA and save their status
         if(
            PositionGetInteger(POSITION_REASON) == POSITION_REASON_EXPERT &&
            positionMagicNo == magicNumber
         )
           {
            ++magicPositionsTotal;
            magicPositionsProfit += PositionGetDouble(POSITION_PROFIT);
            magicPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME);
            if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
              {
               //-- Magic properties
               ++magicBuyPositionsTotal;
               magicBuyPositionsProfit += PositionGetDouble(POSITION_PROFIT);
               magicBuyPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME);
              }
            else //-- POSITION_TYPE_SELL
              {
               //-- Magic properties
               ++magicSellPositionsTotal;
               magicSellPositionsProfit += PositionGetDouble(POSITION_PROFIT);
               magicSellPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME);
              }
           }

         //-- Filter positions by symbol
         if(symbol == ALL_SYMBOLS || selectedSymbol == symbol)
           {
            ++symbolPositionsTotal;
            symbolPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME);
            symbolPositionsProfit += PositionGetDouble(POSITION_PROFIT);
            if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
              {
               ++symbolBuyPositionsTotal;
               symbolBuyPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME);
               symbolBuyPositionsProfit += PositionGetDouble(POSITION_PROFIT);
              }
            else //-- POSITION_TYPE_SELL
              {
               ++symbolSellPositionsTotal;
               symbolSellPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME);
               symbolSellPositionsProfit += PositionGetDouble(POSITION_PROFIT);
              }
           }
        }
     }
  }

Para acessar as diversas propriedades do status da posição que armazenamos em variáveis globais, precisamos criar funções simples exportáveis, que possam ser chamadas externamente. Vamos adicionar as seguintes funções:


Buy Positions Total

Retorna um valor inteiro representando o número total de posições de compra abertas na conta.

int BuyPositionsTotal() export
  {
   GetPositionsData(ALL_SYMBOLS, 0);
   return(accountBuyPositionsTotal);
  }

Sell Positions Total

Retorna um valor inteiro representando o número total de posições de venda abertas na conta.

int SellPositionsTotal() export
  {
   GetPositionsData(ALL_SYMBOLS, 0);
   return(accountSellPositionsTotal);
  }


Positions Total Volume

Retorna um valor do tipo double, representando o volume/lote/quantidade total de todas as posições abertas na conta.

double PositionsTotalVolume() export
  {
   GetPositionsData(ALL_SYMBOLS, 0);
   return(accountPositionsVolumeTotal);
  }


Buy Positions Total Volume

Retorna um valor do tipo double, representando o volume/lote/quantidade total de todas as posições de compra abertas na conta.

double BuyPositionsTotalVolume() export
  {
   GetPositionsData(ALL_SYMBOLS, 0);
   return(accountBuyPositionsVolumeTotal);
  }


Sell Positions Total Volume

Retorna um valor do tipo double, representando o volume/lote/quantidade total de todas as posições de venda abertas na conta.

double SellPositionsTotalVolume() export
  {
   GetPositionsData(ALL_SYMBOLS, 0);
   return(accountSellPositionsVolumeTotal);
  }


Buy Positions Profit

Retorna um valor do tipo double, representando o lucro total de todas as posições de compra abertas na conta.

double BuyPositionsProfit() export
  {
   GetPositionsData(ALL_SYMBOLS, 0);
   return(accountBuyPositionsProfit);
  }


Sell Positions Profit

Retorna um valor do tipo double, representando o lucro total de todas as posições de venda abertas na conta.

double SellPositionsProfit() export
  {
   GetPositionsData(ALL_SYMBOLS, 0);
   return(accountSellPositionsProfit);
  }


Magic Positions Total

Retorna um valor inteiro representando o número total de posições abertas na conta para o número mágico especificado.

int MagicPositionsTotal(ulong magicNumber) export
  {
   GetPositionsData(ALL_SYMBOLS, magicNumber);
   return(magicPositionsTotal);
  }


Magic Buy Positions Total

Retorna um valor inteiro representando o número total de posições de compra abertas na conta para o número mágico especificado.

int MagicBuyPositionsTotal(ulong magicNumber) export
  {
   GetPositionsData(ALL_SYMBOLS, magicNumber);
   return(magicBuyPositionsTotal);
  }


Magic Sell Positions Total

Retorna um valor inteiro representando o número total de posições de venda abertas na conta para o número mágico especificado.

int MagicSellPositionsTotal(ulong magicNumber) export
  {
   GetPositionsData(ALL_SYMBOLS, magicNumber);
   return(magicSellPositionsTotal);
  }


Magic Positions Total Volume

Retorna um valor do tipo double, representando o volume/lote/quantidade total de todas as posições abertas na conta para o número mágico especificado.

double MagicPositionsTotalVolume(ulong magicNumber) export
  {
   GetPositionsData(ALL_SYMBOLS, magicNumber);
   return(magicPositionsVolumeTotal);
  }


Magic Buy Positions Total Volume

Retorna um valor do tipo double, representando o volume/lote/quantidade total de todas as posições de compra abertas na conta para o número mágico especificado.

double MagicBuyPositionsTotalVolume(ulong magicNumber) export
  {
   GetPositionsData(ALL_SYMBOLS, magicNumber);
   return(magicBuyPositionsVolumeTotal);
  }


Magic Sell Positions Total Volume

Retorna um valor do tipo double, representando o volume/lote/quantidade total de todas as posições de venda abertas na conta para o número mágico especificado.

double MagicSellPositionsTotalVolume(ulong magicNumber) export
  {
   GetPositionsData(ALL_SYMBOLS, magicNumber);
   return(magicSellPositionsVolumeTotal);
  }


Magic Positions Profit

Retorna um valor do tipo double, representando o lucro total de todas as posições abertas na conta para o número mágico especificado.

double MagicPositionsProfit(ulong magicNumber) export
  {
   GetPositionsData(ALL_SYMBOLS, magicNumber);
   return(magicPositionsProfit);
  }


Magic Buy Positions Profit

Retorna um valor do tipo double, representando o lucro total de todas as posições de compra abertas na conta para o número mágico especificado.

double MagicBuyPositionsProfit(ulong magicNumber) export
  {
   GetPositionsData(ALL_SYMBOLS, magicNumber);
   return(magicBuyPositionsProfit);
  }


Magic Sell Positions Profit

Retorna um valor do tipo double, representando o lucro total de todas as posições de venda abertas na conta para o número mágico especificado.

double MagicSellPositionsProfit(ulong magicNumber) export
  {
   GetPositionsData(ALL_SYMBOLS, magicNumber);
   return(magicSellPositionsProfit);
  }


Symbol Positions Total

Retorna um valor inteiro representando o número total de posições abertas na conta para o símbolo especificado.

int SymbolPositionsTotal(string symbol, ulong magicNumber) export
  {
   GetPositionsData(symbol, magicNumber);
   return(symbolPositionsTotal);
  }


Symbol Buy Positions Total

Retorna um valor inteiro representando o número total de posições de compra abertas na conta para o símbolo especificado.

int SymbolBuyPositionsTotal(string symbol, ulong magicNumber) export
  {
   GetPositionsData(symbol, magicNumber);
   return(symbolBuyPositionsTotal);
  }


Symbol Sell Positions Total

Retorna um valor inteiro representando o número total de posições de venda abertas na conta para o símbolo especificado.

int SymbolSellPositionsTotal(string symbol, ulong magicNumber) export
  {
   GetPositionsData(symbol, magicNumber);
   return(symbolSellPositionsTotal);
  }


Symbol Positions Total Volume

Retorna um valor do tipo double, representando o volume/lote/quantidade total de todas as posições abertas na conta para o símbolo especificado.

double SymbolPositionsTotalVolume(string symbol, ulong magicNumber) export
  {
   GetPositionsData(symbol, magicNumber);
   return(symbolPositionsVolumeTotal);
  }


Symbol Buy Positions Total Volume

Retorna um valor do tipo double, representando o volume/lote/quantidade total de todas as posições de compra abertas na conta para o símbolo especificado.

double SymbolBuyPositionsTotalVolume(string symbol, ulong magicNumber) export
  {
   GetPositionsData(symbol, magicNumber);
   return(symbolBuyPositionsVolumeTotal);
  }


Symbol Sell Positions Total Volume

Retorna um valor do tipo double, representando o volume/lote/quantidade total de todas as posições de venda abertas na conta para o símbolo especificado.

double SymbolSellPositionsTotalVolume(string symbol, ulong magicNumber) export
  {
   GetPositionsData(symbol, magicNumber);
   return(symbolSellPositionsVolumeTotal);
  }


Symbol Positions Profit

Retorna um valor do tipo double, representando o lucro total de todas as posições abertas na conta para o símbolo especificado.

double SymbolPositionsProfit(string symbol, ulong magicNumber) export
  {
   GetPositionsData(symbol, magicNumber);
   return(NormalizeDouble(symbolPositionsProfit, 2));
  }


Symbol Buy Positions Profit

Retorna um valor do tipo double, representando o lucro total de todas as posições de compra abertas na conta para o símbolo especificado.

double SymbolBuyPositionsProfit(string symbol, ulong magicNumber) export
  {
   GetPositionsData(symbol, magicNumber);
   return(NormalizeDouble(symbolBuyPositionsProfit, 2));
  }


Symbol Sell Positions Profit

Retorna um valor do tipo double, representando o lucro total de todas as posições de venda abertas na conta para o símbolo especificado.

double SymbolSellPositionsProfit(string symbol, ulong magicNumber) export
  {
   GetPositionsData(symbol, magicNumber);
   return(NormalizeDouble(symbolSellPositionsProfit, 2));
  }


Account Positions Status

Retorna uma string previamente formatada contendo o status das posições da conta, que pode ser registrada no log ou exibida nos comentários do gráfico. A função aceita um parâmetro booleano formatForComment. Se formatForComment for true, os dados serão formatados para exibição na janela do gráfico. Se false, os dados serão formatados para exibição na aba de logs do EA.

string AccountPositionsStatus(bool formatForComment) export
  {
   GetPositionsData(ALL_SYMBOLS, 0); //-- Update the position status variables before we display their data
   string spacer = "";
   if(formatForComment) //-- Add some formating space for the chart comment string
     {
      spacer = "                                        ";
     }
   string accountPositionsStatus = "\r\n" + spacer + "|---------------------------------------------------------------------------\r\n";
   accountPositionsStatus += spacer + "| " + (string)AccountInfoInteger(ACCOUNT_LOGIN) + " - ACCOUNT POSTIONS STATUS \r\n";
   accountPositionsStatus += spacer + "|---------------------------------------------------------------------------\r\n";
   accountPositionsStatus += spacer + "|     Total Open:   " + (string)PositionsTotal() + "\r\n";
   accountPositionsStatus += spacer + "|     Total Volume: " + (string)accountPositionsVolumeTotal + "\r\n";
   accountPositionsStatus += spacer + "|     Total Profit: " +
   (string)(NormalizeDouble(AccountInfoDouble(ACCOUNT_PROFIT), 2)) + accountCurrency + "\r\n";
   accountPositionsStatus += spacer + "|------------------------------------------------------------------\r\n";
   accountPositionsStatus += spacer + "| BUY POSITIONS: \r\n";
   accountPositionsStatus += spacer + "|     Total Open:   " + (string)accountBuyPositionsTotal + "\r\n";
   accountPositionsStatus += spacer + "|     Total Volume: " + (string)accountBuyPositionsVolumeTotal + "\r\n";
   accountPositionsStatus += spacer + "|     Total Profit: " + (string)(NormalizeDouble(accountBuyPositionsProfit, 2)) +
   accountCurrency + "\r\n";
   accountPositionsStatus += spacer + "|------------------------------------------------------------------\r\n";
   accountPositionsStatus += spacer + "| SELL POSITIONS: \r\n";
   accountPositionsStatus += spacer + "|     Total Open:   " + (string)accountSellPositionsTotal + "\r\n";
   accountPositionsStatus += spacer + "|     Total Volume: " + (string)accountSellPositionsVolumeTotal + "\r\n";
   accountPositionsStatus += spacer + "|     Total Profit: " + (string)(NormalizeDouble(accountSellPositionsProfit, 2)) +
   accountCurrency + "\r\n";
   accountPositionsStatus += spacer + "|---------------------------------------------------------------------------\r\n";
   accountPositionsStatus += spacer + "\r\n";
   return(accountPositionsStatus);
  }


Magic Positions Status

Retorna uma string previamente formatada contendo o status das posições da conta associadas a um número mágico, que pode ser registrada no log ou exibida nos comentários do gráfico. A função aceita dois parâmetros: um número do tipo ulong (magicNumber) e um booleano (formatForComment). Se formatForComment for true, os dados serão formatados para exibição na janela do gráfico. Se for false, os dados serão formatados para exibição nos logs do EA.

string MagicPositionsStatus(ulong magicNumber, bool formatForComment) export
  {
   GetPositionsData(ALL_SYMBOLS, magicNumber); //-- Update the position status variables before we display their data
   string spacer = "";
   if(formatForComment) //-- Add some formating space for the chart comment string
     {
      spacer = "                                        ";
     }
   string magicPositionsStatus = "\r\n" + spacer + "|---------------------------------------------------------------------------\r\n";
   magicPositionsStatus += spacer + "| " + (string)magicNumber + " - MAGIC POSTIONS STATUS \r\n";
   magicPositionsStatus += spacer + "|---------------------------------------------------------------------------\r\n";
   magicPositionsStatus += spacer + "|     Total Open:   " + (string)magicPositionsTotal + "\r\n";
   magicPositionsStatus += spacer + "|     Total Volume: " + (string)magicPositionsVolumeTotal + "\r\n";
   magicPositionsStatus += spacer + "|     Total Profit: " +
   (string)(NormalizeDouble(magicPositionsProfit, 2)) + accountCurrency + "\r\n";
   magicPositionsStatus += spacer + "|------------------------------------------------------------------\r\n";
   magicPositionsStatus += spacer + "| BUY POSITIONS: \r\n";
   magicPositionsStatus += spacer + "|     Total Open:   " + (string)magicBuyPositionsTotal + "\r\n";
   magicPositionsStatus += spacer + "|     Total Volume: " + (string)magicBuyPositionsVolumeTotal + "\r\n";
   magicPositionsStatus += spacer + "|     Total Profit: " + (string)(NormalizeDouble(magicBuyPositionsProfit, 2)) +
   accountCurrency + "\r\n";
   magicPositionsStatus += spacer + "|------------------------------------------------------------------\r\n";
   magicPositionsStatus += spacer + "| SELL POSITIONS: \r\n";
   magicPositionsStatus += spacer + "|     Total Open:   " + (string)magicSellPositionsTotal + "\r\n";
   magicPositionsStatus += spacer + "|     Total Volume: " + (string)magicSellPositionsVolumeTotal + "\r\n";
   magicPositionsStatus += spacer + "|     Total Profit: " + (string)(NormalizeDouble(magicSellPositionsProfit, 2)) +
   accountCurrency + "\r\n";
   magicPositionsStatus += spacer + "|---------------------------------------------------------------------------\r\n";
   magicPositionsStatus += spacer + "\r\n";
   return(magicPositionsStatus);
  }


Symbol Positions Status

Retorna uma string previamente formatada contendo o status das posições associadas a um símbolo, que pode ser registrada no log ou exibida nos comentários do gráfico. A função aceita três parâmetros: uma string symbol, um número do tipo ulong (magicNumber) e um booleano (formatForComment). Se formatForComment for true, os dados serão formatados para exibição na janela do gráfico. Se for false, os dados serão formatados para exibição nos logs do EA.

string SymbolPositionsStatus(string symbol, ulong magicNumber, bool formatForComment) export
  {
   GetPositionsData(symbol, magicNumber); //-- Update the position status variables before we display their data
   string spacer = "";
   if(formatForComment) //-- Add some formating space for the chart comment string
     {
      spacer = "                                        ";
     }
   string symbolPositionsStatus = "\r\n" + spacer + "|---------------------------------------------------------------------------\r\n";
   symbolPositionsStatus += spacer + "| " + symbol + " - SYMBOL POSTIONS STATUS \r\n";
   symbolPositionsStatus += spacer + "|---------------------------------------------------------------------------\r\n";
   symbolPositionsStatus += spacer + "|     Total Open:   " + (string)symbolPositionsTotal + "\r\n";
   symbolPositionsStatus += spacer + "|     Total Volume: " + (string)symbolPositionsVolumeTotal + "\r\n";
   symbolPositionsStatus += spacer + "|     Total Profit: " +
   (string)(NormalizeDouble(symbolPositionsProfit, 2)) + accountCurrency + "\r\n";
   symbolPositionsStatus += spacer + "|------------------------------------------------------------------\r\n";
   symbolPositionsStatus += spacer + "| BUY POSITIONS: \r\n";
   symbolPositionsStatus += spacer + "|     Total Open:   " + (string)symbolBuyPositionsTotal + "\r\n";
   symbolPositionsStatus += spacer + "|     Total Volume: " + (string)symbolBuyPositionsVolumeTotal + "\r\n";
   symbolPositionsStatus += spacer + "|     Total Profit: " + (string)(NormalizeDouble(symbolBuyPositionsProfit, 2)) +
   accountCurrency + "\r\n";
   symbolPositionsStatus += spacer + "|------------------------------------------------------------------\r\n";
   symbolPositionsStatus += spacer + "| SELL POSITIONS: \r\n";
   symbolPositionsStatus += spacer + "|     Total Open:   " + (string)symbolSellPositionsTotal + "\r\n";
   symbolPositionsStatus += spacer + "|     Total Volume: " + (string)symbolSellPositionsVolumeTotal + "\r\n";
   symbolPositionsStatus += spacer + "|     Total Profit: " + (string)(NormalizeDouble(symbolSellPositionsProfit, 2)) +
   accountCurrency + "\r\n";
   symbolPositionsStatus += spacer + "|---------------------------------------------------------------------------\r\n";
   symbolPositionsStatus += spacer + "\r\n";
   return(symbolPositionsStatus);
  }



Como importar e integrar a biblioteca EX5 para gerenciamento de posições

Desenvolvemos uma biblioteca EX5 abrangente para gerenciamento de posições, contendo todas as funções essenciais para operações com posições, extração de status e módulos de exibição. Agora, chegou o momento de documentar e explicar como importar e utilizar essa biblioteca de maneira eficiente em qualquer projeto MQL5.

Para simplificar o processo de implementação, começaremos descrevendo todas as funções ou módulos disponíveis na biblioteca de gerenciamento de posições e apresentaremos alguns exemplos de uso com código real. Isso proporcionará uma visão clara dos componentes incluídos no arquivo binário PositionsManager.ex5.

Documentação da biblioteca EX5 para gerenciamento de posições

Descrição do protótipo da função Descrição Exemplo de uso
bool ErrorAdvisor(
   string callingFunc, 
   string symbol, 
   int tradeServerErrorCode
);
Trata erros do servidor de negociação e erros de tempo de execução ao processar posições e ordens. Retorna true se o erro puder ser corrigido e a solicitação de negociação puder ser reenviada, ou false se for um erro crítico que exija a interrupção do envio da solicitação.
ResetLastError(); //-- Reset and clear the last error
//--------------------------------------------------------------
//-- Insert code to send the order request to the trade server
//--------------------------------------------------------------
string symbol = _Symbol; //Symbol being traded
int retcode = tradeResult.retcode;//Trade Request Structure (MqlTradeRequest)
if(!ErrorAdvisor(__FUNCTION__, symbol, retcode)
  {
//Critical error found
//Order can not be executed. Exit function or log this error
  }
bool TradingIsAllowed();
Verifica se o EA tem permissão do usuário, do servidor de negociação e da corretora para realizar operações. 
if(!TradingIsAllowed())
  {
   //--- algo trading is disabled, exit function
   return(false);
  }

bool OpenBuyPosition(
   ulong magicNumber,
   string symbol,
   double lotSize,
   int sl, int tp,
   string positionComment
);
Abre uma nova posição de compra com base nos parâmetros especificados.
ulong magicNo = 123;
string symbol = _Symbol;
double lotSize = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
int sl = 500; //-- pips
int tp = 1000; //-- pips
string comment = "Buy position";
OpenBuyPosition(magicNo, symbol, lotSize, sl, tp, comment);
bool OpenSellPosition(
   ulong magicNumber,
   string symbol,
   double lotSize,
   int sl,
   int tp,
   string positionComment
);
Abre uma nova posição de venda com base nos parâmetros especificados.
ulong magicNo = 123;
string symbol = _Symbol;
double lotSize = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
int sl = 500; //-- pips
int tp = 1000; //-- pips
string comment = "Sell position";
OpenSellPosition(magicNo, symbol, lotSize, sl, tp, comment);
bool SetSlTpByTicket(
   ulong positionTicket,
   int sl,
   int tp
);
Define o stop-loss para a posição correspondente ao ticket especificado.
int sl = 500, int tp = 1000; //-- pips
int totalOpenPostions = PositionsTotal();
for(int x = 0; x < totalOpenPostions; x++)
{
   ulong positionTicket = PositionGetTicket(x);
   if(positionTicket > 0)
   {
      SetSlTpByTicket(positionTicket, sl, tp);
   }   
}
bool ClosePositionByTicket(
   ulong positionTicket
);
Fecha a posição correspondente ao ticket especificado.
//-- Example to close all open positions
for(int x = 0; x < totalOpenPostions; x++)
{
   ulong positionTicket = PositionGetTicket(x);
   if(positionTicket > 0)
   {
      ClosePositionByTicket(positionTicket);
   }   
}
bool SetTrailingStopLoss(
   ulong positionTicket,
   int trailingStopLoss
);
Define o trailing stop-loss para a posição correspondente ao ticket especificado. Essa função deve ser chamada a cada tick dentro de OnTick() para atualizar o trailing stop-loss em tempo real.
//-- Execute this on every tick
//-- Example to set 500 pips trailing stop loss for all positions
int trailingStopLoss = 500; //-- 500 pips trailing stop loss
for(int x = 0; x < totalOpenPostions; x++)
{
   ulong positionTicket = PositionGetTicket(x);
   if(positionTicket > 0)
   {
      SetTrailingStopLoss(positionTicket, trailingStopLoss);
   }   
}
bool CloseAllPositions(
   string symbol, 
   ulong magicNumber
);
Fecha todas as posições abertas que correspondem aos parâmetros fornecidos.
//Close all positions
CloseAllPositions("", 0);

//Only close all positions matching a magic number value of 1
CloseAllPositions("", 1);

//Only close all current symbol positions
CloseAllPositions(_Symbol, 0);
bool CloseAllPositions();

Fecha todas as posições abertas.
//Close all open positions in the account
CloseAllPositions();
 
bool CloseAllBuyPositions(
   string symbol, 
   ulong magicNumber
);
Fecha todas as posições de compra que correspondem aos parâmetros especificados.
//Close all buy positions for the current symbol
CloseAllBuyPositions(_Symbol, 0);

//Close all buy positions matching magic number 1 for all symbols
CloseAllBuyPositions("", 1);

//Close all buy positions in the account
CloseAllBuyPositions("", 0);
 
bool CloseAllSellPositions(
   string symbol,
   ulong magicNumber
);

Fecha todas as posições de venda que correspondem aos parâmetros especificados.  
//Close all sell positions for the current symbol
CloseAllSellPositions(_Symbol, 0);

//Close all sell positions matching magic number 1 for all symbols
CloseAllSellPositions("", 1);

//Close all sell positions in the account
CloseAllSellPositions("", 0);
 
bool CloseAllMagicPositions(
   ulong magicNumber
);
Fecha todas as posições correspondentes ao número mágico especificado.  
//Close all positions matching magic number 1
CloseAllMagicPositions(1);

//Close all positions in the account
CloseAllMagicPositions(0);
 
bool CloseAllProfitablePositions(
   string symbol,
   ulong magicNumber
);

Fecha todas as posições lucrativas que correspondem aos parâmetros especificados.
//Close all profitable positions for the current symbol
CloseAllProfitablePositions(_Symbol, 0);

//Close all profitable positions matching magic number 1 for all symbols
CloseAllProfitablePositions("", 1);

//Close all profitable positions in the account
CloseAllProfitablePositions("", 0);
 
bool CloseAllProfitableBuyPositions(
   string symbol,
   ulong magicNumber
);
Fecha todas as posições de compra lucrativas que correspondem aos parâmetros especificados.
//Close all profitable buy positions for the current symbol
CloseAllProfitableBuyPositions(_Symbol, 0);

//Close all profitable buy positions matching magic number 1 for all symbols
CloseAllProfitableBuyPositions("", 1);

//Close all profitable buy positions in the account
CloseAllProfitableBuyPositions("", 0);
 
bool CloseAllProfitableSellPositions(
   string symbol,
   ulong magicNumber
);
Fecha todas as posições de venda lucrativas que correspondem aos parâmetros especificados.
//Close all profitable sell positions for the current symbol
CloseAllProfitableSellPositions(_Symbol, 0);

//Close all profitable sell positions matching magic number 1 for all symbols
CloseAllProfitableSellPositions("", 1);

//Close all profitable sell positions in the account
CloseAllProfitableSellPositions("", 0);
 
bool CloseAllLossPositions(
   string symbol,
   ulong magicNumber
);

Fecha todas as posições não lucrativas que correspondem aos parâmetros especificados.
//Close all loss positions for the current symbol
CloseAllLossPositions(_Symbol, 0);

//Close all loss positions matching magic number 1 for all symbols
CloseAllLossPositions("", 1);

//Close all loss positions in the account
CloseAllLossPositions("", 0);
 
bool CloseAllLossBuyPositions(
   string symbol,
   ulong magicNumber
);
Fecha todas as posições de compra não lucrativas que correspondem aos parâmetros especificados.
//Close all loss buy positions for the current symbol
CloseAllLossBuyPositions(_Symbol, 0);

//Close all loss buy positions matching magic number 1 for all symbols
CloseAllLossBuyPositions("", 1);

//Close all loss buy positions in the account
CloseAllLossBuyPositions("", 0);

 
bool CloseAllLossSellPositions(
   string symbol,
   ulong magicNumber
);

Fecha todas as posições de venda não lucrativas que correspondem aos parâmetros especificados.
//Close all loss sell positions for the current symbol
CloseAllLossSellPositions(_Symbol, 0);

//Close all loss sell positions matching magic number 1 for all symbols
CloseAllLossSellPositions("", 1);

//Close all loss sell positions in the account
CloseAllLossSellPositions("", 0);
 
int BuyPositionsTotal();

Retorna o número de posições de compra abertas.  
//Get the total number of open buy positions in the account
BuyPositionsTotal();

 
int SellPositionsTotal();

Retorna o número de posições de venda abertas.
//Get the total number of open sell positions in the account
SellPositionsTotal();

 
double PositionsTotalVolume();

Retorna o volume total de todas as posições abertas.
//Get the total volume of all open positions in the account
PositionsTotalVolume();

 
double BuyPositionsTotalVolume();
Retorna o volume total de todas as posições de compra abertas.
//Get the total volume of all open buy positions in the account
BuyPositionsTotalVolume();

 
double SellPositionsTotalVolume();

Retorna o volume total de todas as posições de venda abertas.
//Get the total volume of all open sell positions in the account
SellPositionsTotalVolume();

 
double BuyPositionsProfit();
Retorna o lucro total de todas as posições de compra abertas.
//Get the total profit of all open buy positions in the account
BuyPositionsProfit();

 
double SellPositionsProfit();

Retorna o lucro total de todas as posições de venda abertas.
//Get the total profit of all open sell positions in the account
SellPositionsProfit();

 
int MagicPositionsTotal(
   ulong magicNumber
);

Retorna o número de posições abertas correspondentes ao número mágico especificado.
//Get the total number of open positions matching magic number 1
MagicPositionsTotal(1);
 
int MagicBuyPositionsTotal(
   ulong magicNumber
);

Retorna o número de posições de compra abertas correspondentes ao número mágico especificado.
//Get the total number of open buy positions matching magic number 1
MagicBuyPositionsTotal(1);
 
int MagicSellPositionsTotal(
   ulong magicNumber
);

Retorna o número de posições de venda abertas correspondentes ao número mágico especificado.
//Get the total number of open sell positions matching magic number 1
MagicSellPositionsTotal(1);
 
double MagicPositionsTotalVolume(
   ulong magicNumber
);

Retorna o volume total de todas as posições abertas correspondentes ao número mágico especificado.
//Get the total volume of open positions matching magic number 1
MagicPositionsTotalVolume(1);
 
double MagicBuyPositionsTotalVolume(
   ulong magicNumber
);

Retorna o volume total de todas as posições de compra abertas correspondentes ao número mágico especificado.
//Get the total volume of open buy positions matching magic number 1
MagicBuyPositionsTotalVolume(1);
 
double MagicSellPositionsTotalVolume(
   ulong magicNumber
);

Retorna o volume total de todas as posições de venda abertas correspondentes ao número mágico especificado.
 
//Get the total volume of open sell positions matching magic number 1
MagicSellPositionsTotalVolume(1);
 
double MagicPositionsProfit(
   ulong magicNumber
);

Retorna o lucro total de todas as posições abertas correspondentes ao número mágico especificado.
//Get the total profit of open positions matching magic number 1
MagicPositionsProfit(1);
 
double MagicBuyPositionsProfit(
   ulong magicNumber
);
Retorna o lucro total de todas as posições de compra abertas correspondentes ao número mágico especificado.
//Get the total profit of open buy positions matching magic number 1
MagicBuyPositionsProfit(1);
 
double MagicSellPositionsProfit(
   ulong magicNumber
);
Retorna o lucro total de todas as posições de venda abertas correspondentes ao número mágico especificado.
//Get total profit of sell positions matching magic number 1
MagicSellPositionsProfit(1);

 
int SymbolPositionsTotal(
   string symbol,
   ulong magicNumber
);

Retorna o número total de todas as posições abertas que correspondem ao símbolo e ao número mágico especificados.
//Get total number of positions matching symbol and magic number 1
MagicPositionsTotal(_Symbol, 1);
 
int SymbolBuyPositionsTotal(
   string symbol,
   ulong magicNumber
);
Retorna o número total de todas as posições de compra abertas que correspondem ao símbolo e ao número mágico especificados.
//Get total number of buy positions matching symbol and magic number 1
SymbolBuyPositionsTotal(_Symbol, 1);

 
int SymbolSellPositionsTotal(
   string symbol,
   ulong magicNumber
);
Retorna o número total de todas as posições de venda abertas que correspondem ao símbolo e ao número mágico especificados.
//Get total number of sell positions matching symbol and magic number 1
SymbolSellPositionsTotal(_Symbol, 1);

 
double SymbolPositionsTotalVolume(
   string symbol,
   ulong magicNumber
);

Retorna o volume total de todas as posições abertas correspondentes ao símbolo e ao número mágico especificados.
//Get the volume of positions matching symbol and magic number 1
SymbolPositionsTotalVolume(_Symbol, 1);

 
double SymbolBuyPositionsTotalVolume(
   string symbol,
   ulong magicNumber
);

Retorna o volume total de todas as posições de compra abertas correspondentes ao símbolo e ao número mágico especificados.
//Get the volume of buy positions matching symbol and magic number 1
SymbolBuyPositionsTotalVolume(_Symbol, 1);
 
double SymbolSellPositionsTotalVolume(
   string symbol,
   ulong magicNumber
);

Retorna o volume total de todas as posições de venda abertas que correspondem ao símbolo e ao número mágico especificados.
//Get the volume of sell positions matching symbol and magic number 1
SymbolSellPositionsTotalVolume(_Symbol, 1);
 
double SymbolPositionsProfit(
   string symbol,
   ulong magicNumber
);

Retorna o lucro total de todas as posições abertas correspondentes ao símbolo e ao número mágico especificados.
//Get the profit of all positions matching symbol and magic number 1
SymbolPositionsProfit(_Symbol, 1);
 
double SymbolBuyPositionsProfit(
   string symbol,
   ulong magicNumber
);
Retorna o lucro total de todas as posições de compra abertas correspondentes ao símbolo e ao número mágico especificados.
//Get the profit of all buy positions matching symbol and magic number 1
SymbolBuyPositionsProfit(_Symbol, 1);

 
double SymbolSellPositionsProfit(
   string symbol,
   ulong magicNumber
);
Retorna o lucro total de todas as posições de venda abertas correspondentes ao símbolo e ao número mágico especificados.
//Get the profit of all sell positions matching symbol and magic number 1
SymbolSellPositionsProfit(_Symbol, 1);
 
string AccountPositionsStatus(
   bool formatForComment
);
Mostra o status de todas as posições abertas no gráfico do símbolo ou na aba "Especialistas" do MetaTrader 5.  
//Print the status of all open positions formatted for the chart comments
AccountPositionsStatus(true);

//Print the status of all open positions formatted for the Experts tab
AccountPositionsStatus(false);
 
string MagicPositionsStatus(
   ulong magicNumber,
   bool formatForComment
);

Exibe o status de todas as posições abertas correspondentes ao número mágico especificado no gráfico do símbolo ou na aba "Especialistas" no MetaTrader 5.
//Print the status of all open positions matching
//the magic number 1 formatted for the chart comments
MagicPositionsStatus(1, true);

//Print the status of all open positions matching
//the magic number 1 formatted for the Experts tab
MagicPositionsStatus(1, false);
 
string SymbolPositionsStatus(
   string symbol,
   ulong magicNumber,
   bool formatForComment
);
Exibe o status de todas as posições abertas correspondentes ao símbolo especificado e ao número mágico no gráfico do símbolo na aba "Especialistas" no MetaTrader 5.
//Print the status of all open positions matching
//the symbol and magic number 1 formatted for the chart comments
SymbolPositionsStatus(_Symbol, 1, true);

//Print the status of all open positions matching
//the symbol and magic number 1 formatted for the Experts tab
SymbolPositionsStatus(_Symbol, 1, false);

A integração da biblioteca em projetos MQL5 é um processo simples. Siga os dois passos abaixo para importar PositionsManager.ex5 para o seu código MQL5:

  • Passo 1: Copie o arquivo executável da biblioteca (PositionsManager.ex5)

Instale o arquivo PositionsManager.ex5 na pasta MQL5/Libraries/Toolkit. Certifique-se de que o arquivo foi baixado e copiado para esse local, caso ainda não esteja lá. O arquivo PositionsManager.ex5 está anexado ao final do artigo.

  • Passo 2: Importe as definições dos protótipos de funções

Adicione as diretivas de importação da biblioteca de gerenciamento de posições e as descrições dos protótipos de suas funções na seção de cabeçalho do seu arquivo de código-fonte. Utilize o trecho de código abaixo para importar de forma eficiente todas as funções e módulos da biblioteca PositionsManager.ex5. Além disso, criei um modelo de EA vazio (PositionsManager_Imports_Template.mq5) que já contém esse segmento de código. Você pode comentar ou remover seletivamente quaisquer descrições de funções que não sejam necessárias para o seu projeto. O arquivo PositionsManager_Imports_Template.mq5 também está anexado ao final do artigo.

//+-------------------------------------------------------------------------------------+
//| PositionsManager.ex5 imports template                                               |
//+-------------------------------------------------------------------------------------+
#import "Toolkit/PositionsManager.ex5" //-- Opening import directive
//-- Function descriptions for the imported function prototypes

//-- Error Handling and Permission Status Functions
bool   ErrorAdvisor(string callingFunc, string symbol, int tradeServerErrorCode);
bool   TradingIsAllowed();

//-- Position Execution and Modification Functions
bool   OpenBuyPosition(ulong magicNumber, string symbol, double lotSize, int sl, int tp, string positionComment);
bool   OpenSellPosition(ulong magicNumber, string symbol, double lotSize, int sl, int tp, string positionComment);
bool   SetSlTpByTicket(ulong positionTicket, int sl, int tp);
bool   ClosePositionByTicket(ulong positionTicket);
bool   SetTrailingStopLoss(ulong positionTicket, int trailingStopLoss);
bool   CloseAllPositions(string symbol, ulong magicNumber);
bool   CloseAllPositions();
bool   CloseAllBuyPositions(string symbol, ulong magicNumber);
bool   CloseAllSellPositions(string symbol, ulong magicNumber);
bool   CloseAllMagicPositions(ulong magicNumber);
bool   CloseAllProfitablePositions(string symbol, ulong magicNumber);
bool   CloseAllProfitableBuyPositions(string symbol, ulong magicNumber);
bool   CloseAllProfitableSellPositions(string symbol, ulong magicNumber);
bool   CloseAllLossPositions(string symbol, ulong magicNumber);
bool   CloseAllLossBuyPositions(string symbol, ulong magicNumber);
bool   CloseAllLossSellPositions(string symbol, ulong magicNumber);

//-- Position Status Monitoring Functions
int    BuyPositionsTotal();
int    SellPositionsTotal();
double PositionsTotalVolume();
double BuyPositionsTotalVolume();
double SellPositionsTotalVolume();
double BuyPositionsProfit();
double SellPositionsProfit();

//-- Positions Filtered By Magic Number Status Monitoring Functions
int    MagicPositionsTotal(ulong magicNumber);
int    MagicBuyPositionsTotal(ulong magicNumber);
int    MagicSellPositionsTotal(ulong magicNumber);
double MagicPositionsTotalVolume(ulong magicNumber);
double MagicBuyPositionsTotalVolume(ulong magicNumber);
double MagicSellPositionsTotalVolume(ulong magicNumber);
double MagicPositionsProfit(ulong magicNumber);
double MagicBuyPositionsProfit(ulong magicNumber);
double MagicSellPositionsProfit(ulong magicNumber);

//-- Positions Filtered By Symbol and/or Magic Number Status Monitoring Functions
int    SymbolPositionsTotal(string symbol, ulong magicNumber);
int    SymbolBuyPositionsTotal(string symbol, ulong magicNumber);
int    SymbolSellPositionsTotal(string symbol, ulong magicNumber);
double SymbolPositionsTotalVolume(string symbol, ulong magicNumber);
double SymbolBuyPositionsTotalVolume(string symbol, ulong magicNumber);
double SymbolSellPositionsTotalVolume(string symbol, ulong magicNumber);
double SymbolPositionsProfit(string symbol, ulong magicNumber);
double SymbolBuyPositionsProfit(string symbol, ulong magicNumber);
double SymbolSellPositionsProfit(string symbol, ulong magicNumber);

//-- Log and Data Display Functions
string AccountPositionsStatus(bool formatForComment);
string MagicPositionsStatus(ulong magicNumber, bool formatForComment);
string SymbolPositionsStatus(string symbol, ulong magicNumber, bool formatForComment);

#import //--- Closing import directive

Após importar a biblioteca, você poderá facilmente abrir, fechar, modificar ou recuperar dados sobre o status de posições usando chamadas de função simples. Para ilustrar isso, criaremos três EAs simples nos próximos tópicos.


Desenvolvimento do EA Dual VIDyA Trailing Stop com base na biblioteca EX5 para gerenciamento de posições

Nesta seção, desenvolveremos um EA baseado na estratégia de trailing stop utilizando o indicador técnico Variable Index Dynamic Average (VIDyA), com o objetivo de demonstrar a aplicação da biblioteca EX5 para gerenciamento de posições em um ambiente de negociação real.

A estratégia de trailing stop VIDyA usará um par de indicadores técnicos de média móvel dinâmica com índice variável para gerar sinais de compra e venda. Como o indicador VIDyA é exibido no gráfico como uma linha, utilizaremos uma estratégia de cruzamento de linhas para gerar sinais de novas operações. Para implementar essa estratégia, os dois indicadores devem ter configurações diferentes. O primeiro indicador VIDyA, com valores de entrada menores, será chamado de fast VIDyA (VIDyA rápido), pois responderá mais rapidamente às mudanças no preço e gerará sinais com mais agilidade. O segundo, com valores de entrada maiores, será chamado de slow VIDyA (VIDyA lento), pois terá uma resposta mais suave às variações do mercado. Para um sinal de compra, a linha fast VIDyA deve cruzar acima da linha slow VIDyA. Para um sinal de venda, a linha fast VIDyA deve cruzar abaixo da linha slow VIDyA.

Estratégia Dual VIDyA


Criamos um novo EA no MetaEditor, utilizando o Assistente MQL (MQL Wizard) e nomeamos o arquivo como DualVidyaTrader.mq5. Como nosso EA utilizará a biblioteca PositionsManager.ex5, o primeiro passo é importar e inserir as descrições dos protótipos das funções da biblioteca, conforme descrito anteriormente. O segmento import da biblioteca deve ser colocado logo abaixo das diretivas #property. Como a biblioteca contém muitas funções, não importaremos todas, mas apenas os protótipos das funções listadas no código abaixo.

//--- Import the PositionsManager EX5 Library
#import "Toolkit/PositionsManager.ex5" //-- Open the ex5 import directive
//-- Prototype function descriptions of the EX5 PositionsManager library
bool   OpenBuyPosition(ulong magicNumber, string symbol, double lotSize, int sl, int tp, string positionComment);
bool   OpenSellPosition(ulong magicNumber, string symbol, double lotSize, int sl, int tp, string positionComment);
bool   SetTrailingStopLoss(ulong positionTicket, int trailingStopLoss);
int    MagicPositionsTotal(ulong magicNumber);
int    MagicBuyPositionsTotal(ulong magicNumber);
int    MagicSellPositionsTotal(ulong magicNumber);
bool   CloseAllProfitableBuyPositions(string symbol, ulong magicNumber);
bool   CloseAllProfitableSellPositions(string symbol, ulong magicNumber);
string MagicPositionsStatus(ulong magicNumber, bool formatForComment);
#import //-- Close the ex5 import directive

Após o segmento import da biblioteca PositionsManager.ex5, adicionamos as variáveis globais definidas pelo usuário, conforme mostrado a seguir.

input group ""
input ulong magicNo = 1234;
input ENUM_TIMEFRAMES timeframe = PERIOD_H1;
input ENUM_APPLIED_PRICE  appliedPrice = PRICE_CLOSE; // Applied VIDyA Price

//-- Fast Vidya user inputs
input group "-- FAST VIDyA INPUTS"
input int fast_cmoPeriod = 5; // Fast Chande Momentum Period
input int fast_maPeriod = 10; // Fast MA Smoothing Period
input int fast_emaShift = 0; // Fast Horizontal Shift

//-- Slow Vidya user inputs
input group "-- SLOW VIDyA INPUTS"
input int slow_cmoPeriod = 9; //  Slow Chande Momentum Period
input int slow_maPeriod = 12; // Slow MA Smoothing Period
input int slow_emaShift = 0; // Slow Horizontal Shift

input group "-- PROFIT MANAGEMENT"
input bool liquidateProfitOnCrossover = false; // Liquidate Profit On VIDyA Signal
input bool enableTrailingStops = true; // Use Trailing Stop Losses

Criamos mais variáveis globais para armazenar os valores de stop-loss, take-profit, trailing stop-loss e lote ou volume.

//-- Get and save the SL, trailingSL and TP values from the spread
int spreadMultiForSl = 1000;
int spreadMultiForTrailingSl = 300;
int spreadMultiForTp = 1000;
int sl = int(SymbolInfoInteger(_Symbol, SYMBOL_SPREAD)) * spreadMultiForSl;
int trailingSl = int(SymbolInfoInteger(_Symbol, SYMBOL_SPREAD)) * spreadMultiForTrailingSl;
int tp = int(SymbolInfoInteger(_Symbol, SYMBOL_SPREAD)) * spreadMultiForTp;

//-- Set the lot or volume to the symbol allowed min value
double lotSize = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);

Também declaramos variáveis globais para o indicador técnico VIDyA, garantindo que possam ser acessadas de qualquer parte do código do EA.

//-- Vidya indicator variables
double fastVidya[], slowVidya[];
int fastVidyaHandle, slowVidyaHandle;
bool buyOk, sellOk, vidyaBuy, vidyaSell;
string vidyaTrend;

Após a seção de variáveis globais, criamos uma função de inicialização do EA, que será chamada dentro da função padrão de tratamento de eventos OnInit(), executada quando o EA é iniciado ou carregado no gráfico pela primeira vez. Denominamos essa função como GetInit(). Nela, realizamos todas as inicializações necessárias, incluindo a inicialização do indicador VIDyA e a configuração do comportamento do EA no momento da ativação.

int GetInit()
  {
   int returnVal = 1;

//-- Helps to regulate and prevent openning multiple trades on a single signal trigger
   buyOk = true;
   sellOk = true;

//-- Create the fast iVIDyA indicator handle
   fastVidyaHandle = iVIDyA(_Symbol, timeframe, fast_cmoPeriod, fast_maPeriod, fast_emaShift, appliedPrice);
   if(fastVidyaHandle < 0)
     {
      Print("Error creating fastVidyaHandle = ", INVALID_HANDLE);
      Print("Handle creation: Runtime error = ", GetLastError());
      //-- Close the EA if the handle is not properly loaded
      return(-1);
     }
   ArraySetAsSeries(fastVidya, true); //-- set the vidya array to series access

//-- Create the slow iVIDyA indicator handle
   slowVidyaHandle = iVIDyA(_Symbol, timeframe, slow_cmoPeriod, slow_maPeriod, slow_emaShift, appliedPrice);
   if(slowVidyaHandle < 0)
     {
      Print("Error creating vidyaHandle = ", INVALID_HANDLE);
      Print("Handle creation: Runtime error = ", GetLastError());
      //-- Close the EA if the handle is not properly loaded
      return(-1);
     }
   ArraySetAsSeries(slowVidya, true); //-- set the vidya array to series access

   return(returnVal);
  }

Agora, criamos uma função de desinicialização chamada GetDeinit(). Essa função será executada na função padrão OnDeinit() para garantir que todos os recursos utilizados pelo EA sejam devidamente liberados. Isso inclui a liberação do indicador VIDyA, a remoção de todos os recursos alocados em arrays de handles de indicadores e a exclusão de quaisquer comentários ou objetos gráficos criados pelo EA no gráfico.

void GetDeinit()  //-- De-initialize the robot on shutdown and clean everything up
  {
//-- Delete the vidya handles and de-allocate the memory spaces occupied
   IndicatorRelease(fastVidyaHandle);
   ArrayFree(fastVidya);
   IndicatorRelease(slowVidyaHandle);
   ArrayFree(slowVidya);

//-- Delete and clear all chart displayed messages
   Comment("");
  }

Em seguida, precisamos criar uma função personalizada para detectar e capturar os sinais de negociação gerados pelo par de indicadores VIDyA. Denominamos essa função como GetVidya(). Ela será executada e atualizada a cada novo tick, garantindo que os sinais gerados sejam precisos e estejam sempre atualizados.

void GetVidya()
  {
//-- Get vidya line directions
   if(CopyBuffer(fastVidyaHandle, 0, 0, 100, fastVidya) <= 0 || CopyBuffer(slowVidyaHandle, 0, 0, 100, slowVidya) <= 0)
     {
      return;
     }

//-- Reset vidya status variables
   vidyaBuy = false;
   vidyaSell = false;
   vidyaTrend = "FLAT";

//-- Scan for vidya crossover buy signal
   if(fastVidya[1] > slowVidya[1])
     {
      //-- Save the vidya signal
      vidyaTrend = "BUY/LONG";
      vidyaBuy = true;
      vidyaSell = false;
     }

//-- Scan for vidya crossover sell signal
   if(fastVidya[1] < slowVidya[1])
     {
      //-- Save the vidya signal
      vidyaTrend = "SELL/SHORT";
      vidyaSell = true;
      vidyaBuy = false;
     }
  }

Agora que criamos a função para capturar e atualizar o sinal VIDyA, precisamos de outra função que será executada a cada novo tick para analisar o mercado e abrir novas posições com base nos sinais atuais do VIDyA. Nomeamos essa função como ScanForTradeOpportunities(). Dentro dessa função, chamaremos e utilizaremos os protótipos de funções de abertura de ordens e status de posições que foram importados da biblioteca PositionsManager.ex5.

void ScanForTradeOpportunities()
  {
//-- Get the VIDyA signal
   GetVidya();

   if(MagicPositionsTotal(magicNo) == 0)
     {
      buyOk = true;
      sellOk = true;
     }

//-- Check for a buy entry when a VIDyA buy signal is found
   if(buyOk && vidyaBuy) //-- Open a new buy position
     {
      if(OpenBuyPosition(magicNo, _Symbol, lotSize, sl, tp, "Vidya_BUY: " + IntegerToString(MagicBuyPositionsTotal(magicNo) + 1)))
        {
         buyOk = false;
         sellOk = true;
        }
      //-- Market has a strong buy trend, close all profitable sell positions
      if(liquidateProfitOnCrossover)
        {
         CloseAllProfitableSellPositions(_Symbol, magicNo);
        }
     }

//-- Check for a sell entry when a VIDyA sell signal is found
   if(sellOk && vidyaSell) //-- Open a new sell position
     {
      if(OpenSellPosition(magicNo, _Symbol, lotSize, sl, tp, "Vidya_SELL: " + IntegerToString(MagicSellPositionsTotal(magicNo) + 1)))
        {
         sellOk = false;
         buyOk = true;
        }
      //-- Market has a strong sell trend, close all profitable buy positions
      if(liquidateProfitOnCrossover)
        {
         CloseAllProfitableBuyPositions(_Symbol, magicNo);
        }
     }
  }

Também é preciso verificar e definir trailing stop-loss para todas as posições abertas. Essa tarefa será facilitada pelo protótipo da função de trailing stop-loss incluído na biblioteca PositionsManager.ex5. Criamos uma nova função chamada CheckAndSetTrailingSl(), que verificará todas as posições abertas e recuperará seus tickets para usá-los como parâmetros na função importada SetTrailingStopLoss().

void CheckAndSetTrailingSl()
  {
   int totalOpenPostions = PositionsTotal();
   for(int x = 0; x < totalOpenPostions; x++)
     {
      //--- Get position properties
      ulong  positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);
      int positionType = int(PositionGetInteger(POSITION_TYPE));

      //-- modify only the positions we have opened with this EA (magic number)
      if(selectedSymbol != _Symbol && positionMagicNo != magicNo)
        {
         continue;
        }
      //-- Only set the trailing stop loss when the market trend is in the opposing direction of the position type
      if((positionType == POSITION_TYPE_BUY && vidyaBuy) || (positionType == POSITION_TYPE_SELL && vidyaSell))
        {
         continue;
        }
      //--- set the trailing stop loss
      SetTrailingStopLoss(positionTicket, trailingSl); //-- call the imported function from our ex5 library
     }
  }

Agora que criamos todos os módulos essenciais para o nosso EA, vamos integrá-los dentro da função de tratamento de eventos OnTick(), que será executada a cada novo tick do mercado. Certifique-se de organizá-los na ordem especificada abaixo para garantir que eles operem a estratégia de negociação de forma sistemática e na sequência correta.

void OnTick()
  {
//-- Scan and open new positions based on the vidya signal
   ScanForTradeOpportunities();

//-- Check and set the trailing stop
   if(enableTrailingStops)
     {
      CheckAndSetTrailingSl();
     }

//-- Display the vidya trend and positions status for the EA's magicNo
   Comment(
      "\nvidyaTrend: ", vidyaTrend,
      MagicPositionsStatus(magicNo, true)
   );
  }

Por fim, não se esqueça de colocar as funções de inicialização e desinicialização dentro das respectivas funções padrão de tratamento de eventos do MQL5.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   if(GetInit() <= 0)
     {
      return(INIT_FAILED);
     }
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   GetDeinit();
  }

O arquivo de código-fonte DualVidyaTrader.mq5 está anexado ao final do artigo. O código completo foi incluído para garantir que você tenha todos os componentes necessários para implementar e personalizar a estratégia de negociação conforme necessário.

Ao compilar e carregar o novo EA DualVidyaTrader no MetaTrader 5, você notará que, na aba Dependencies (Dependências), serão listados todos os protótipos das funções importadas da biblioteca PositionsManager.ex5, juntamente com o caminho completo do arquivo onde a biblioteca EX5 está armazenada. Isso garante que todas as dependências necessárias estejam corretamente vinculadas antes do EA ser carregado no gráfico. Se houver erros de referência de biblioteca, como os discutidos anteriormente, eles aparecerão na aba "Especialistas" ou "Jornal" na janela "Ferramentas" do MetaTrader 5.

Dual Vidya Trader, aba Dependencies


Painel de Controle de Posições baseado na biblioteca EX5

No segundo exemplo, criaremos um painel de negociação simples com uma interface gráfica do usuário (GUI), utilizando a biblioteca PositionsManager.ex5.

Interface gráfica do painel de controle de posições


Criamos um novo EA no MetaEditor, utilizando o Assistente MQL, e nomeamos o arquivo como PositionsManagerPanel.mq5. Logo após as diretivas #property, importamos a biblioteca PositionsManager.ex5. Na seção de descrições de funções import, incluímos apenas os seguintes protótipos de funções necessários para essa implementação.

//+------------------------------------------------------------------+
//| EX5 PositionsManager imports                                     |
//+------------------------------------------------------------------+
#import "Toolkit/PositionsManager.ex5" //-- Open import directive
//-- Function descriptions for the imported function prototypes

//--Position Execution and Modification Functions
bool   OpenBuyPosition(ulong magicNumber, string symbol, double lotSize, int sl, int tp, string positionComment);
bool   OpenSellPosition(ulong magicNumber, string symbol, double lotSize, int sl, int tp, string positionComment);
bool   SetSlTpByTicket(ulong positionTicket, int sl, int tp);
bool   ClosePositionByTicket(ulong positionTicket);
bool   SetTrailingStopLoss(ulong positionTicket, int trailingStopLoss);
bool   CloseAllPositions(string symbol, ulong magicNumber);
bool   CloseAllBuyPositions(string symbol, ulong magicNumber);
bool   CloseAllSellPositions(string symbol, ulong magicNumber);
bool   CloseAllMagicPositions(ulong magicNumber);
bool   CloseAllProfitablePositions(string symbol, ulong magicNumber);
bool   CloseAllLossPositions(string symbol, ulong magicNumber);

//--Position Status Monitoring Functions
int    BuyPositionsTotal();
int    SellPositionsTotal();
double PositionsTotalVolume();
double BuyPositionsTotalVolume();
double SellPositionsTotalVolume();
double BuyPositionsProfit();
double SellPositionsProfit();
int    MagicPositionsTotal(ulong magicNumber);
int    MagicBuyPositionsTotal(ulong magicNumber);
int    MagicSellPositionsTotal(ulong magicNumber);
double MagicPositionsTotalVolume(ulong magicNumber);
double MagicBuyPositionsTotalVolume(ulong magicNumber);
double MagicSellPositionsTotalVolume(ulong magicNumber);
double MagicPositionsProfit(ulong magicNumber);
double MagicBuyPositionsProfit(ulong magicNumber);
double MagicSellPositionsProfit(ulong magicNumber);
int    SymbolPositionsTotal(string symbol, ulong magicNumber);
int    SymbolBuyPositionsTotal(string symbol, ulong magicNumber);
int    SymbolSellPositionsTotal(string symbol, ulong magicNumber);
double SymbolPositionsTotalVolume(string symbol, ulong magicNumber);
double SymbolBuyPositionsTotalVolume(string symbol, ulong magicNumber);
double SymbolSellPositionsTotalVolume(string symbol, ulong magicNumber);
double SymbolPositionsProfit(string symbol, ulong magicNumber);
double SymbolBuyPositionsProfit(string symbol, ulong magicNumber);
double SymbolSellPositionsProfit(string symbol, ulong magicNumber);
string AccountPositionsStatus(bool formatForComment);
string MagicPositionsStatus(ulong magicNumber, bool formatForComment);
string SymbolPositionsStatus(string symbol, ulong magicNumber, bool formatForComment);
#import //--- Close import directive

O arquivo PositionsManagerPanel.mq5 conterá apenas um parâmetro de entrada do usuário, que será o número mágico das operações.

//--User input variables
input ulong magicNo = 101010;

Em seguida, criamos variáveis globais para armazenar os valores de volume do lote (volumeLot), stop-loss (sl) e take-profit (tp).

//-- Global variables
//-----------------------
//-- Get the current symbol spread and multiply it by a significant number
//-- to simulate user-input SL and TP values
double volumeLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
int sl = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD) * 50;
int tp = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD) * 100;

Nosso primeiro objeto gráfico será criado para servir como fundo da interface gráfica do usuário. Para isso, utilizaremos um rótulo retangular. Criamos uma função personalizada chamada CreateRectangleLabel() para essa finalidade.

//+-----------------------------------------------------------------------+
//| CreateRectangleLabel(): Creates a rectangle label on the chart window |
//+-----------------------------------------------------------------------+
void CreateRectangleLabel()
  {
//--- Detect if we have an object named the same as our rectangle label
   if(ObjectFind(0, "mainRectangleLabel") >= 0)
     {
      //--- Delete the specified object if it is not a rectangle label
      if(ObjectGetInteger(0, "mainRectangleLabel", OBJPROP_TYPE) != OBJ_RECTANGLE_LABEL)
        {
         ObjectDelete(0, "mainRectangleLabel");
        }
     }
   else
     {
      //-- Create the mainRectangleLabel
      ObjectCreate(0, "mainRectangleLabel", OBJ_RECTANGLE_LABEL, 0, 0, 0);
     }
//--- Set up the new rectangle label properties
   ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_XDISTANCE, 240);
   ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_YDISTANCE, 2);
   ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_XSIZE, 460);
   ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_YSIZE, 520);
   ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_BGCOLOR, clrMintCream);
   ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_BACK, false);
   ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_HIDDEN, true);
  }

Também precisaremos de rótulos para exibir textos na interface do nosso painel de negociação. Para isso, criamos outra função personalizada chamada CreateLabel(), que será responsável por essa tarefa.

//+---------------------------------------------------------+
//| CreateLabel(): Creates a text label on the chart window |
//+---------------------------------------------------------+
void CreateLabel(
   string labelName, int xDistance, int yDistance, int xSize, int ySize,
   string labelText, color textColor, string fontType, int fontSize
)
  {
//--- Detect if we have an object with the same name as our label
   if(ObjectFind(0, labelName) >= 0)
     {
      //--- Delete the specified object if it is not a label
      if(ObjectGetInteger(0, labelName, OBJPROP_TYPE) != OBJ_LABEL)
        {
         ObjectDelete(0, labelName);
        }
     }
   else
     {
      //-- Create the label
      ObjectCreate(0, labelName, OBJ_LABEL, 0, 0, 0);
     }
//--- Set up the new rectangle label properties
   ObjectSetInteger(0, labelName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, labelName, OBJPROP_XDISTANCE, xDistance);
   ObjectSetInteger(0, labelName, OBJPROP_YDISTANCE, yDistance);
   ObjectSetInteger(0, labelName, OBJPROP_XSIZE, xSize);
   ObjectSetInteger(0, labelName, OBJPROP_YSIZE, ySize);
   ObjectSetString(0, labelName, OBJPROP_TEXT, labelText);
   ObjectSetInteger(0, labelName, OBJPROP_COLOR, textColor);
   ObjectSetString(0, labelName, OBJPROP_FONT, fontType);
   ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, fontSize);
   ObjectSetInteger(0, labelName, OBJPROP_BACK, false);
   ObjectSetInteger(0, labelName, OBJPROP_HIDDEN, true);
   ObjectSetInteger(0, labelName, OBJPROP_SELECTABLE, false);
   ObjectSetInteger(0, labelName, OBJPROP_SELECTED, false);
  }

Para realizar diversas operações de negociação no painel de negociação, precisamos de botões clicáveis ou interativos. Portanto, criamos uma função personalizada para gerenciar a criação desses botões. Nomeamos essa função como CreateButton().

//+------------------------------------------------------+
//| CreateButton(): Creates buttons on the chart window  |
//+------------------------------------------------------+
void CreateButton(
   string btnName, int xDistance, int yDistance, int xSize, int ySize, string btnText,
   string tooltip, color textColor, string fontType, int fontSize, color bgColor
)
  {
//--- Detect if we have an object named the same as our button
   if(ObjectFind(0, btnName) >= 0)
     {
      //--- Delete the specified object if it is not a button
      if(ObjectGetInteger(0, btnName, OBJPROP_TYPE) != OBJ_BUTTON)
        {
         ObjectDelete(0, btnName);
        }
     }
   else
     {
      //-- Create the button
      ObjectCreate(0, btnName, OBJ_BUTTON, 0, 0, 0);
     }
//--- Set up the new button properties
   ObjectSetInteger(0, btnName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, btnName, OBJPROP_XDISTANCE, xDistance);
   ObjectSetInteger(0, btnName, OBJPROP_YDISTANCE, yDistance);
   ObjectSetInteger(0, btnName, OBJPROP_XSIZE, xSize);
   ObjectSetInteger(0, btnName, OBJPROP_YSIZE, ySize);
   ObjectSetString(0, btnName, OBJPROP_TEXT, btnText);
   ObjectSetString(0, btnName, OBJPROP_TOOLTIP, tooltip);
   ObjectSetInteger(0, btnName, OBJPROP_COLOR, textColor);
   ObjectSetString(0, btnName, OBJPROP_FONT, fontType);
   ObjectSetInteger(0, btnName, OBJPROP_FONTSIZE, fontSize);
   ObjectSetInteger(0, btnName, OBJPROP_BGCOLOR, bgColor);
  }

Agora, precisamos de outra função personalizada para carregar todos os objetos gráficos e componentes gráficos de entrada do usuário criados pelas funções mencionadas anteriormente. Nomeamos essa função como LoadChartObjects().

//+--------------------------------------------------------------------+
//| LoadChartObjects(): Create and load the buttons and chart objects  |
//| for demonstrating how the imported library functions work          |
//+--------------------------------------------------------------------+
void LoadChartObjects()
  {
//-- Create the rectangle label first
   CreateRectangleLabel();

//-- Create the heading label
   CreateLabel(
      "headingLabel", 250, 10, 440, 60,
      "PositionsManager ex5 Library Demo Trade Panel",
      clrMidnightBlue, "Calibri", 10
   );

//-- Create the second heading label
   CreateLabel(
      "headingLabel2", 250, 30, 440, 60,
      ("Trading " + _Symbol + " with Magic Number: " + (string)magicNo),
      clrBlack, "Consolas", 11
   );

//-- "BUY": Button to call the imported ex5 OpenBuyPosition() function
   CreateButton(
      "OpenBuyPositionBtn", 250, 50, 215, 35, "BUY",
      "OpenBuyPosition() Function", clrMintCream, "Arial Black", 10, clrDodgerBlue
   );

//-- "SELL": Button to call the imported ex5 OpenSellPosition() function
   CreateButton(
      "OpenSellPositionBtn", 475, 50, 215, 35, "SELL",
      "OpenSellPosition() Function", clrMintCream, "Arial Black", 10, clrCrimson
   );

//-- "SetSlTpByTicket": Button to call the imported ex5 SetSlTpByTicket() function
   CreateButton(
      "SetSlTpBtn", 250, 90, 215, 35, "SetSlTpByTicket",
      "SetSlTpByTicket() Function", clrMintCream, "Arial Black", 10, clrDarkSlateGray
   );

//-- "SetTrailingStopLoss": Button to call the imported ex5 SetTrailingStopLoss() function when clicked
   CreateButton(
      "SetTrailingStopLossBtn", 475, 90, 215, 35, "SetTrailingStopLoss",
      "SetTrailingStopLoss Function", clrMintCream, "Arial Black", 10, clrDarkSlateGray
   );

//-- "ClosePositionsByTicket": Button to call the imported ex5 ClosePositionByTicket() function
   CreateButton(
      "ClosePositionsBtn", 250, 130, 215, 35, "ClosePositionsByTicket",
      "ClosePositionByTicket() Function", clrMintCream, "Arial Black", 10, clrMaroon
   );

//-- "CloseAllSymbolPositions": Button to call the imported ex5 CloseAllSymbolPositions() function
   CreateButton(
      "CloseAllPositionsBtn", 475, 130, 215, 35, "CloseAllPositions",
      "CloseAllPositions() Function", clrMintCream, "Arial Black", 10, clrMaroon
   );

//-- "CloseAllBuySymbolPositions": Button to call the imported ex5 CloseAllBuySymbolPositions() function
   CreateButton(
      "CloseAllBuyPositionsBtn", 250, 170, 215, 35, "CloseAllBuyPositions",
      "CloseAllBuyPositions() Function", clrMintCream, "Arial Black", 10, clrBrown
   );

//-- "CloseAllSellSymbolPositions": Button to call the imported ex5 CloseAllSellSymbolPositions() function
   CreateButton(
      "CloseAllSellPositionsBtn", 475, 170, 215, 35, "CloseAllSellPositions",
      "CloseAllSellPositions() Function", clrMintCream, "Arial Black", 10, clrBrown
   );

//-- "CloseAllMagicPositions": Button to call the imported ex5 CloseAllMagicPositions() function
   CreateButton(
      "CloseAllMagicPositionsBtn", 250, 210, 440, 35, "CloseAllMagicPositions",
      "CloseAllMagicPositions() Function", clrMintCream, "Arial Black", 10, C'203,18,55'
   );

//-- "CloseAllProfitablePositions": Button to call the imported ex5 CloseAllMagicPositions() function
   CreateButton(
      "CloseAllProfitablePositionsBtn", 250, 250, 215, 35, "CloseAllProfitablePositions",
      "CloseAllProfitablePositions() Function", clrMintCream, "Arial Black", 10, clrSeaGreen
   );

//-- "CloseAllLossPositions": Button to call the imported ex5 CloseAllLossPositions() function
   CreateButton(
      "CloseAllLossPositionsBtn", 475, 250, 215, 35, "CloseAllLossPositions",
      "CloseAllLossPositions() Function", clrMintCream, "Arial Black", 10, C'179,45,0'
   );

//-- Create the bottomHeadingLabel
   CreateLabel(
      "bottomHeadingLabel", 250, 310, 440, 60,
      (_Symbol + " - (Magic Number: " + (string)magicNo + ") Positions Status"),
      clrBlack, "Calibri", 12
   );

//-- Create totalOpenPositionsLabel
   CreateLabel(
      "totalOpenPositionsLabel", 250, 340, 440, 60,
      ("  Total Open:   " + (string)MagicPositionsTotal(magicNo)),
      clrNavy, "Consolas", 11
   );

//-- Create totalPositionsVolumeLabel
   CreateLabel(
      "totalPositionsVolumeLabel", 250, 360, 440, 60,
      ("  Total Volume: " + (string)NormalizeDouble(MagicPositionsTotalVolume(magicNo), 2)),
      clrNavy, "Consolas", 11
   );

//-- Create the totalPositionsProfitLabel
   CreateLabel(
      "totalPositionsProfitLabel", 250, 380, 100, 60,
      (
         "  Total Profit: " + (string)(NormalizeDouble(MagicPositionsProfit(magicNo), 2)) +
         " " + AccountInfoString(ACCOUNT_CURRENCY)
      ),
      clrNavy, "Consolas", 11
   );

//-- Create the buyPositionsHeadingLabel
   CreateLabel(
      "buyPositionsHeadingLabel", 250, 410, 440, 60,
      ("BUY POSITIONS:"),
      clrBlack, "Calibri", 12
   );

//-- Create the totalBuyPositionsLabel
   CreateLabel(
      "totalBuyPositionsLabel", 250, 430, 440, 60,
      ("  Total Open:   " + (string)MagicBuyPositionsTotal(magicNo)),
      clrNavy, "Consolas", 11
   );

//-- Create the totalBuyPositionsVolumeLabel
   CreateLabel(
      "totalBuyPositionsVolumeLabel", 250, 450, 440, 60,
      ("  Total Volume: " + (string)NormalizeDouble(MagicBuyPositionsTotalVolume(magicNo), 2)),
      clrNavy, "Consolas", 11
   );

//-- Create the totalBuyPositionsProfitLabel
   CreateLabel(
      "totalBuyPositionsProfitLabel", 250, 470, 440, 60,
      (
         "  Total Profit: " + (string)(NormalizeDouble(MagicBuyPositionsProfit(magicNo), 2)) +
         " " + AccountInfoString(ACCOUNT_CURRENCY)
      ),
      clrNavy, "Consolas", 11
   );

//-- Create the sellPositionsHeadingLabel
   CreateLabel(
      "sellPositionsHeadingLabel", 475, 410, 440, 60,
      ("SELL POSITIONS:"),
      clrBlack, "Calibri", 12
   );

//-- Create the totalSellPositionsLabel
   CreateLabel(
      "totalSellPositionsLabel", 475, 430, 440, 60,
      ("  Total Open:   " + (string)MagicSellPositionsTotal(magicNo)),
      clrNavy, "Consolas", 11
   );

//-- Create the totalSellPositionsVolumeLabel
   CreateLabel(
      "totalSellPositionsVolumeLabel", 475, 450, 440, 60,
      ("  Total Volume: " + (string)NormalizeDouble(MagicSellPositionsTotalVolume(magicNo), 2)),
      clrNavy, "Consolas", 11
   );

//-- Create the totalSellPositionsProfitLabel
   CreateLabel(
      "totalSellPositionsProfitLabel", 475, 470, 100, 60,
      (
         "  Total Profit: " + (string)(NormalizeDouble(MagicSellPositionsProfit(magicNo), 2)) +
         " " + AccountInfoString(ACCOUNT_CURRENCY)
      ),
      clrNavy, "Consolas", 11
   );

//--- Redraw the chart to refresh it so that it loads our new chart objects
   ChartRedraw();
//---
  }

A próxima função personalizada será responsável por limpar e remover todos os objetos gráficos e dados ao finalizar ou desinicializar o EA. Chamamos essa função de DeleteChartObjects(), e ela será executada dentro da função de evento OnDeinit().

//+------------------------------------------------------------------------------+
//| DeleteChartObjects(): Delete all the chart objects when the EA is terminated |
//| on De-initialization                                                         |
//+------------------------------------------------------------------------------+
void DeleteChartObjects()
  {
//---
//--- Clean up and delete all the buttons or graphical objects
   ObjectDelete(0, "OpenBuyPositionBtn");
   ObjectDelete(0, "OpenSellPositionBtn");
   ObjectDelete(0, "SetSlTpBtn");
   ObjectDelete(0, "SetTrailingStopLossBtn");
   ObjectDelete(0, "ClosePositionsBtn");
   ObjectDelete(0, "CloseAllPositionsBtn");
   ObjectDelete(0, "CloseAllBuyPositionsBtn");
   ObjectDelete(0, "CloseAllSellPositionsBtn");
   ObjectDelete(0, "CloseAllMagicPositionsBtn");
   ObjectDelete(0, "CloseAllProfitablePositionsBtn");
   ObjectDelete(0, "CloseAllLossPositionsBtn");
   ObjectDelete(0, "mainRectangleLabel");

   ObjectDelete(0, "headingLabel");
   ObjectDelete(0, "headingLabel2");

   ObjectDelete(0, "bottomHeadingLabel");
   ObjectDelete(0, "totalOpenPositionsLabel");
   ObjectDelete(0, "totalPositionsVolumeLabel");
   ObjectDelete(0, "totalPositionsProfitLabel");

   ObjectDelete(0, "buyPositionsHeadingLabel");
   ObjectDelete(0, "totalBuyPositionsLabel");
   ObjectDelete(0, "totalBuyPositionsVolumeLabel");
   ObjectDelete(0, "totalBuyPositionsProfitLabel");

   ObjectDelete(0, "sellPositionsHeadingLabel");
   ObjectDelete(0, "totalSellPositionsLabel");
   ObjectDelete(0, "totalSellPositionsVolumeLabel");
   ObjectDelete(0, "totalSellPositionsProfitLabel");
  }

Criamos funções personalizadas para implementar algumas das funções importadas da biblioteca PositionsManager.ex5. A primeira função dessa categoria, chamada ModifySlTp(), será responsável por modificar o stop-loss (SL) e o take-profit (TP) de todas as posições abertas pelo EA que correspondam ao número mágico especificado pelo usuário. Essa função será executada sempre que o botão setSLTP for pressionado no gráfico.

//+-------------------------------------------------------------------------+
// ModifySlTp(): This function demonstrates how to use the imported ex5     |
// bool SetSlTpByTicket(ulong positionTicket, int sl, int tp);              |
// It runs this function when the setSLTP button on the chart is clicked.   |
//+-------------------------------------------------------------------------+
void ModifySlTp()
  {
//-- Get positions that we have openend with the chart buy and sell buttons to test the imported function with
   int totalOpenPostions = PositionsTotal();
//--- Scan open positions
   for(int x = 0; x < totalOpenPostions; x++)
     {
      //--- Get position properties
      ulong  positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);

      //-- modify only the positions we have opened with this EA (magic number) using the BUY and SELL buttons on the chart
      if(selectedSymbol != _Symbol && positionMagicNo != magicNo)
        {
         continue;
        }
      //--- modify the sl and tp of the position
      SetSlTpByTicket(positionTicket, sl, tp);//-- call the imported function from our ex5 library
     }
  }

A próxima função, SetTrailingSl(), será responsável por atualizar o trailing stop-loss. Ela será executada tanto quando o botão SetTrailingStopLoss for pressionado no gráfico quanto em cada novo tick dentro da função OnTick().

//+-----------------------------------------------------------------------------------+
// SetTrailingSl(): This function demonstrates how to use the imported ex5            |
// bool SetTrailingStopLoss(ulong positionTicket, int trailingStopLoss);              |
// It runs this function when the SetTrailingStopLoss button on the chart is clicked. |
//+-----------------------------------------------------------------------------------+
void SetTrailingSl()
  {
   int trailingSl = sl;

//-- Get positions that we have openend with the chart buy and sell buttons to test the imported function with
   int totalOpenPostions = PositionsTotal();
//--- Scan open positions
   for(int x = 0; x < totalOpenPostions; x++)
     {
      //--- Get position properties
      ulong  positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);

      //-- modify only the positions we have opened with this EA (magic number) using the BUY and SELL buttons on the chart
      if(selectedSymbol != _Symbol && positionMagicNo != magicNo)
        {
         continue;
        }
      //--- set the trailing stop loss
      SetTrailingStopLoss(positionTicket, trailingSl); //-- call the imported function from our ex5 library
     }
  }

A função ClosePositionWithTicket() será encarregada de fechar todas as posições abertas e será acionada sempre que o botão ClosePositions for pressionado no gráfico.

//+-----------------------------------------------------------------------------------+
// ClosePositionWithTicket(): This function demonstrates how to use the imported ex5  |
// bool ClosePositionByTicket(ulong positionTicket)                                   |
// It runs this function when the ClosePositions button on the chart is clicked.      |
//+-----------------------------------------------------------------------------------+
void ClosePositionWithTicket()
  {
//-- Get positions that we have openend with the chart buy and sell buttons to test the imported function with
   int totalOpenPostions = PositionsTotal();
//--- Scan open positions
   for(int x = 0; x < totalOpenPostions; x++)
     {
      //--- Get position properties
      ulong  positionTicket = PositionGetTicket(x); //-- Get ticket to select the position
      string selectedSymbol = PositionGetString(POSITION_SYMBOL);
      ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC);

      //-- close only the positions we have opened with this EA (magic number) using the BUY and SELL buttons on the chart
      if(selectedSymbol != _Symbol && positionMagicNo != magicNo)
        {
         continue;
        }

      //--- Close the position
      ClosePositionByTicket(positionTicket);//-- call the imported function from our ex5 library
     }
  }

A última função é a função padrão do MQL5 OnChartEvent(), que detectará os cliques nos botões do painel e executará as ações correspondentes. Quase todas as funções importadas de gerenciamento de posições da biblioteca PositionsManager.ex5 serão chamadas e executadas dentro dessa função.

//+------------------------------------------------------------------+
//| ChartEvent function to detect when the buttons are clicked       |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
//--- Detected a CHARTEVENT_CLICK event
   if(id == CHARTEVENT_OBJECT_CLICK)
     {
      Print(__FUNCTION__, ": ", sparam);

      //--- Buy when OpenBuyPositionBtn button (BUY) is pressed or clicked
      if(sparam == "OpenBuyPositionBtn")
        {
         //-- Call our imported function from the Toolkit/PositionsManager ex5 library
         OpenBuyPosition(magicNo, _Symbol, volumeLot, sl, tp, "ex5 PositionsManager");

         //--- Release and unpress the button
         ObjectSetInteger(0, "OpenBuyPositionBtn", OBJPROP_STATE, false);
        }

      //--- Sell when OpenSellPositionBtn button (SELL) is pressed
      if(sparam == "OpenSellPositionBtn")
        {
         //-- Call our imported function from the Toolkit/PositionsManager ex5 library
         OpenSellPosition(magicNo, _Symbol, volumeLot, sl, tp, "ex5 PositionsManager");
         //OpenSellPosition(magicNo, "NON-EXISTENT-Symbol-Name"/*_Symbol*/, volumeLot, sl, tp, "ex5 PositionsManager");

         //--- Release and unpress the button
         ObjectSetInteger(0, "OpenSellPositionBtn", OBJPROP_STATE, false);
        }

      //--- Modify specified positions SL and TP when SetSlTpBtn button (setSLTP) is pressed
      if(sparam == "SetSlTpBtn")
        {
         ModifySlTp();//-- Modify the SL and TP of the positions generated by the BUY and SELL buttons
         //--- Release and unpress the button
         ObjectSetInteger(0, "SetSlTpBtn", OBJPROP_STATE, false);
        }

      //--- Set the Trailing Stop Loss when SetSlTpBtn button (SetTrailingStopLossBtn) is pressed
      if(sparam == "SetTrailingStopLossBtn")
        {
         SetTrailingSl();//-- Set the Trailing Stop Loss for the positions generated by the BUY and SELL buttons
         //--- Release and unpress the button
         ObjectSetInteger(0, "SetTrailingStopLossBtn", OBJPROP_STATE, false);
        }

      //--- Close specified positions when SetSlTpBtn button (setSLTP) is pressed
      if(sparam == "ClosePositionsBtn")
        {
         ClosePositionWithTicket();//-- Close all the positions generated by the BUY and SELL buttons
         //--- Release and unpress the button
         ObjectSetInteger(0, "ClosePositionsBtn", OBJPROP_STATE, false);
        }

      //--- Close all positions for the current symbol when the CloseAllPositionsBtn button is pressed
      if(sparam == "CloseAllPositionsBtn")
        {
         CloseAllPositions(_Symbol, 0);//-- Close all the open symbol positions
         //--- Release and unpress the button
         ObjectSetInteger(0, "CloseAllPositionsBtn", OBJPROP_STATE, false);
        }

      //--- Close all buy positions for the current symbol when the CloseAllBuyPositionsBtn button is pressed
      if(sparam == "CloseAllBuyPositionsBtn")
        {
         CloseAllBuyPositions(_Symbol, magicNo);//-- Close all the open symbol buy positions
         //--- Release and unpress the button
         ObjectSetInteger(0, "CloseAllBuyPositionsBtn", OBJPROP_STATE, false);
        }

      //--- Close all sell positions for the current symbol when the CloseAllSellPositionsBtn button is pressed
      if(sparam == "CloseAllSellPositionsBtn")
        {
         CloseAllSellPositions(_Symbol, magicNo);//-- Close all the open symbol sell positions
         //--- Release and unpress the button
         ObjectSetInteger(0, "CloseAllSellPositionsBtn", OBJPROP_STATE, false);
        }

      //--- Close all positions with the specified magic number when the CloseAllMagicPositionsBtn button is pressed
      if(sparam == "CloseAllMagicPositionsBtn")
        {
         CloseAllMagicPositions(magicNo);//-- Close all the open positions with the specified magic number
         //--- Release and unpress the button
         ObjectSetInteger(0, "CloseAllMagicPositionsBtn", OBJPROP_STATE, false);
        }

      //--- Close all profitable positions with the specified symbol and magic number when the CloseAllProfitablePositionsBtn button is pressed
      if(sparam == "CloseAllProfitablePositionsBtn")
        {
         CloseAllProfitablePositions(_Symbol, magicNo);//-- Close all the open profitable positions with the specified symbol and magic number
         //--- Release and unpress the button
         ObjectSetInteger(0, "CloseAllProfitablePositionsBtn", OBJPROP_STATE, false);
        }

      //--- Close all loss positions with the specified symbol and magic number when the CloseAllLossPositionsBtn button is pressed
      if(sparam == "CloseAllLossPositionsBtn")
        {
         CloseAllLossPositions(_Symbol, magicNo);//-- Close all the open loss positions with the specified symbol and magic number
         //--- Release and unpress the button
         ObjectSetInteger(0, "CloseAllLossPositionsBtn", OBJPROP_STATE, false);
        }

      //--- Redraw the chart to refresh it
      ChartRedraw();
     }
//---
  }

Antes de rodar o EA PositionsTradePanel.mq5, precisamos garantir que todos os componentes necessários estejam incluídos nas funções de manipulação de eventos OnInit(), OnDeinit() e OnTick(). Começamos carregando todos os objetos gráficos durante a inicialização do EA, chamando a função LoadChartObjects() dentro da função OnInit().

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
//create buttons to demonstrate how the different ex5 library functions work
   LoadChartObjects();
//---
   return(INIT_SUCCEEDED);
  }

Chamamos e executamos as seguintes funções dentro de OnTick().

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//-- Check for profitable positions and set the trailing stop loss on every new tick
   SetTrailingSl(); //-- Calls the ex5 library function responsible for setting Trailing stops
   LoadChartObjects(); //--- Update chart objects
  }

Adicionamos a função de desinicialização dentro do manipulador de eventos OnDeinit() para remover todos os objetos gráficos ao fechar ou encerrar o EA.

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
//-- Clean up the chart
   DeleteChartObjects();

//-- Clear any chart comments
   Comment("");
  }

O arquivo de código-fonte do EA PositionsManagerPanel.mq5 está anexado ao final do artigo.

Salvamos, compilamos e carregamos o EA PositionsManagerPanel.mq5 em qualquer gráfico no MetaTrader 5. Na aba Dependencies (Dependências), podemos ver todos os protótipos das funções importadas da biblioteca PositionsManager.ex5, juntamente com o caminho completo do arquivo onde a biblioteca EX5 está armazenada. Após carregar o EA no gráfico, realizamos testes abrindo algumas posições e verificando os registros na aba "Especialistas" dentro do painel "Ferramentas" do terminal de negociação. Devemos ver registros gerados pelos protótipos das funções da biblioteca PositionsManager.ex5.

Aba Dependencies do painel de controle de posições


Considerações finais

Analisamos detalhadamente as bibliotecas EX5 no MQL5. Exploramos seu processo de criação, integração e implementação em projetos MQL5 externos, além de abordarmos a depuração de erros, atualização e redistribuição de bibliotecas EX5. Além disso, desenvolvemos uma biblioteca EX5 robusta e multifuncional para gerenciamento de posições, acompanhada por documentação detalhada e exemplos práticos de uso. Também demonstrei como importar e aplicar essa biblioteca em dois EAs diferentes, fornecendo exemplos reais de implantação eficiente de uma biblioteca EX5. Na próxima parte, utilizaremos uma abordagem semelhante para desenvolver uma biblioteca EX5 especializada no gerenciamento de ordens pendentes, projetada para simplificar o processamento de ordens pendentes em seus projetos MQL5. Obrigado pela atenção! Desejo muito sucesso em sua negociação e programação!


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

Monitoramento de Trading com Notificações-Push — Exemplo de Serviço no MetaTrader 5 Monitoramento de Trading com Notificações-Push — Exemplo de Serviço no MetaTrader 5
Neste artigo, analisaremos a criação de um programa de serviço para enviar notificações para um smartphone sobre os resultados do trading. No decorrer do artigo, aprenderemos a trabalhar com listas de objetos da Biblioteca Padrão para facilitar a seleção de objetos com as propriedades necessárias.
Negociação de Notícias Facilitada (Parte 3): Realizando Negócios Negociação de Notícias Facilitada (Parte 3): Realizando Negócios
Neste artigo, nosso especialista em negociação de notícias começará a abrir negociações com base no calendário econômico armazenado em nosso banco de dados. Além disso, melhoraremos os gráficos do especialista para exibir informações mais relevantes sobre os próximos eventos do calendário econômico.
Reimaginando Estratégias Clássicas (Parte IV): SP500 e Notas do Tesouro dos EUA Reimaginando Estratégias Clássicas (Parte IV): SP500 e Notas do Tesouro dos EUA
Nesta série de artigos, analisamos estratégias clássicas de negociação usando algoritmos modernos para determinar se podemos melhorar a estratégia utilizando IA. No artigo de hoje, revisamos uma abordagem clássica para negociar o SP500 usando a relação que ele tem com as Notas do Tesouro dos EUA.
DoEasy. Funções de Serviço (Parte 3): Padrão "Barra Externa" DoEasy. Funções de Serviço (Parte 3): Padrão "Barra Externa"
Neste artigo, desenvolveremos o padrão Price Action "Barra Externa" na biblioteca DoEasy e otimizaremos os métodos de acesso ao gerenciamento de padrões de preço. Além disso, realizaremos correções de erros e melhorias identificadas durante os testes da biblioteca.