English Русский 中文 Español Deutsch 日本語
preview
Construindo um Modelo de Restrição de Tendência com Candlestick (Parte 8): Desenvolvimento de Expert Advisor (I)

Construindo um Modelo de Restrição de Tendência com Candlestick (Parte 8): Desenvolvimento de Expert Advisor (I)

MetaTrader 5Testador |
139 2
Clemence Benjamin
Clemence Benjamin

Conteúdo


Introdução

O software MetaEditor inclui um compilador que gerencia efetivamente os erros detectados durante as tentativas de perfilamento. Esta ferramenta me ajudou a descobrir por que a versão anterior não conseguiu exibir os retângulos de risco e recompensa como esperado. Embora o programa tenha compilado com sucesso, o problema não estava no código em si. O desafio estava no fato de que nada foi exibido dentro do intervalo dos candlesticks de retrospectiva, principalmente devido a especificidades técnicas.
  1. O valor de retrospectiva do candle foi definido muito alto, em 5.000 barras por padrão.
  2. Ter múltiplos buffers em um único programa aumenta a complexidade dos cálculos, o que pode retardar a exibição da janela de gráfico do indicador.

    Após discutirmos brevemente como resolvemos os problemas encontrados, vamos seguir para o principal objetivo deste artigo: desenvolver um Expert Advisor com base no Indicador de Restrição de Tendência refinado. Abaixo está uma imagem mostrando como um script separado resolveu com sucesso o problema que originalmente pretendíamos resolver com o indicador principal.

    Razão risco-recompensa desenhada para o cruzamento de Média Móvel

    Retângulos de risco e recompensa desenhados automaticamente usando o retângulo


    Solução para os desafios anteriores sobre o desenho de retângulos de risco e recompensado

    Para resolver os desafios no programa do indicador:

    1. Reduzimos o período de retrospectiva de 5000 barras para 1000 barras, diminuindo significativamente a quantidade de dados a serem calculados.
    2. Nosso objetivo foi reduzir a carga de trabalho do programa criando um script independente como parte do conjunto de ferramentas. Este script verifica especificamente as condições tratadas pelo Buffer 6 e Buffer 7 no indicador. Assim que essas condições são atendidas, o script desenha os retângulos necessários de risco e recompensa e coloca linhas com rótulos de preço para o preço de entrada, Stop Loss e Take Profit. No entanto, é importante observar que o script realiza uma tarefa única e não executa continuamente. O usuário deve adicionar manualmente o script ao gráfico para visualizar os níveis de negociação representados pelos objetos desenhados e as marcações de preço.

    Abaixo está uma imagem mostrando o lançamento do programa do script:

    Lançamento do script Trend Constraint R-R

    Script Trend Constraint R-R: Para desenhar o retângulo de risco e recompensa quando ocorre um cruzamento de Média Móvel

    Ao isolar essa funcionalidade, garantimos que nosso indicador funcione sem problemas, evitando qualquer congelamento do computador ou do terminal de negociação. Incorporar retângulos de risco e recompensa e marcar os níveis de saída permite que os traders avaliem visualmente a direção e os alvos da negociação com antecedência, possibilitando negociações manuais sem a necessidade de um Expert Advisor. O programa do script com a lógica necessária funcionou perfeitamente. Aqui está nosso programa completo de script.

    //+------------------------------------------------------------------+
    //|                                        Trend Constraint R-R.mq5  |
    //|                                                  Script program  |
    //+------------------------------------------------------------------+
    #property strict
    #property script_show_inputs
    #property copyright "2024 Clemence Benjamin"
    #property version "1.00"
    #property link "https://www.mql5.com/en/users/billionaire2024/seller"
    #property description "A script program for drawing risk and rewars rectangles based on Moving Averaage crossover."
    
    
    
    //--- input parameters
    input int FastMAPeriod = 14;
    input int SlowMAPeriod = 50;
    input double RiskHeightPoints = 5000.0; // Default height of the risk rectangle in points
    input double RewardHeightPoints = 15000.0; // Default height of the reward rectangle in points
    input color RiskColor = clrIndianRed; // Default risk color
    input color RewardColor = clrSpringGreen; // Default reward color
    input int MaxBars = 500; // Maximum bars to process
    input int RectangleWidth = 10; // Width of the rectangle in bars
    input bool FillRectangles = true; // Option to fill rectangles
    input int FillTransparency = 128; // Transparency level (0-255), 128 is 50% transparency
    
    //+------------------------------------------------------------------+
    //| Script program start function                                    |
    //+------------------------------------------------------------------+
    void OnStart()
    {
      //--- delete existing rectangles and lines
      DeleteExistingObjects();
    
      //--- declare and initialize variables
      int i, limit;
      double FastMA[], SlowMA[];
      double closePrice, riskLevel, rewardLevel;
    
      //--- calculate moving averages
      if (iMA(NULL, 0, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE) < 0 || iMA(NULL, 0, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE) < 0)
      {
        Print("Error in calculating moving averages.");
        return;
      }
    
      ArraySetAsSeries(FastMA, true);
      ArraySetAsSeries(SlowMA, true);
    
      CopyBuffer(iMA(NULL, 0, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE), 0, 0, MaxBars, FastMA);
      CopyBuffer(iMA(NULL, 0, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE), 0, 0, MaxBars, SlowMA);
    
      limit = MathMin(ArraySize(FastMA), ArraySize(SlowMA));
    
      for (i = 1; i < limit - 1; i++)
      {
        //--- check for crossover
        if (FastMA[i] > SlowMA[i] && FastMA[i - 1] <= SlowMA[i - 1])
        {
          //--- long position entry point (bullish crossover)
          closePrice = iClose(NULL, 0, i);
          riskLevel = closePrice + RiskHeightPoints * Point();
          rewardLevel = closePrice - RewardHeightPoints * Point();
    
          //--- draw risk rectangle
          DrawRectangle("Risk_" + IntegerToString(i), i, closePrice, i - RectangleWidth, riskLevel, RiskColor);
    
          //--- draw reward rectangle
          DrawRectangle("Reward_" + IntegerToString(i), i, closePrice, i - RectangleWidth, rewardLevel, RewardColor);
    
          //--- draw entry, stop loss, and take profit lines
          DrawPriceLine("Entry_" + IntegerToString(i), i, closePrice, clrBlue, "Entry: " + DoubleToString(closePrice, _Digits));
          DrawPriceLine("StopLoss_" + IntegerToString(i), i, riskLevel, clrRed, "Stop Loss: " + DoubleToString(riskLevel, _Digits));
          DrawPriceLine("TakeProfit_" + IntegerToString(i), i, rewardLevel, clrGreen, "Take Profit: " + DoubleToString(rewardLevel, _Digits));
        }
        else if (FastMA[i] < SlowMA[i] && FastMA[i - 1] >= SlowMA[i - 1])
        {
          //--- short position entry point (bearish crossover)
          closePrice = iClose(NULL, 0, i);
          riskLevel = closePrice - RiskHeightPoints * Point();
          rewardLevel = closePrice + RewardHeightPoints * Point();
    
          //--- draw risk rectangle
          DrawRectangle("Risk_" + IntegerToString(i), i, closePrice, i - RectangleWidth, riskLevel, RiskColor);
    
          //--- draw reward rectangle
          DrawRectangle("Reward_" + IntegerToString(i), i, closePrice, i - RectangleWidth, rewardLevel, RewardColor);
    
          //--- draw entry, stop loss, and take profit lines
          DrawPriceLine("Entry_" + IntegerToString(i), i, closePrice, clrBlue, "Entry: " + DoubleToString(closePrice, _Digits));
          DrawPriceLine("StopLoss_" + IntegerToString(i), i, riskLevel, clrRed, "Stop Loss: " + DoubleToString(riskLevel, _Digits));
          DrawPriceLine("TakeProfit_" + IntegerToString(i), i, rewardLevel, clrGreen, "Take Profit: " + DoubleToString(rewardLevel, _Digits));
        }
      }
    }
    
    //+------------------------------------------------------------------+
    //| Function to delete existing rectangles and lines                 |
    //+------------------------------------------------------------------+
    void DeleteExistingObjects()
    {
      int totalObjects = ObjectsTotal(0, 0, -1);
      for (int i = totalObjects - 1; i >= 0; i--)
      {
        string name = ObjectName(0, i, 0, -1);
        if (StringFind(name, "Risk_") >= 0 || StringFind(name, "Reward_") >= 0 ||
            StringFind(name, "Entry_") >= 0 || StringFind(name, "StopLoss_") >= 0 ||
            StringFind(name, "TakeProfit_") >= 0)
        {
          ObjectDelete(0, name);
        }
      }
    }
    
    //+------------------------------------------------------------------+
    //| Function to draw rectangles                                      |
    //+------------------------------------------------------------------+
    void DrawRectangle(string name, int startBar, double startPrice, int endBar, double endPrice, color rectColor)
    {
      if (ObjectFind(0, name) >= 0)
        ObjectDelete(0, name);
    
      datetime startTime = iTime(NULL, 0, startBar);
      datetime endTime = (endBar < 0) ? (TimeCurrent() + (PeriodSeconds() * (-endBar))) : iTime(NULL, 0, endBar);
    
      if (!ObjectCreate(0, name, OBJ_RECTANGLE, 0, startTime, startPrice, endTime, endPrice))
        Print("Failed to create rectangle: ", name);
    
      // Set the color with transparency (alpha value)
      int alphaValue = FillTransparency; // Adjust transparency level (0-255)
      color fillColor = rectColor & 0x00FFFFFF | (alphaValue << 24); // Combine alpha with RGB
    
      ObjectSetInteger(0, name, OBJPROP_COLOR, rectColor);
      ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID);
      ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
      ObjectSetInteger(0, name, OBJPROP_BACK, true); // Set to background
    
      if (FillRectangles)
      {
        ObjectSetInteger(0, name, OBJPROP_COLOR, fillColor); // Fill color with transparency
      }
      else
      {
        ObjectSetInteger(0, name, OBJPROP_COLOR, rectColor & 0x00FFFFFF); // No fill color
      }
    }
    
    //+------------------------------------------------------------------+
    //| Function to draw price lines                                     |
    //+------------------------------------------------------------------+
    void DrawPriceLine(string name, int barIndex, double price, color lineColor, string labelText)
    {
      datetime time = iTime(NULL, 0, barIndex);
      datetime endTime = (barIndex - 2 * RectangleWidth < 0) ? (TimeCurrent() + (PeriodSeconds() * (-barIndex - 2 * RectangleWidth))) : iTime(NULL, 0, barIndex - 2 * RectangleWidth); // Extend line to the right
    
      if (!ObjectCreate(0, name, OBJ_TREND, 0, time, price, endTime, price))
        Print("Failed to create price line: ", name);
    
      ObjectSetInteger(0, name, OBJPROP_COLOR, lineColor);
      ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID);
      ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
      ObjectSetInteger(0, name, OBJPROP_BACK, true); // Set to background
    
      // Create text label
      string labelName = name + "_Label";
      if (ObjectFind(0, labelName) >= 0)
        ObjectDelete(0, labelName);
    
      if (!ObjectCreate(0, labelName, OBJ_TEXT, 0, endTime, price))
        Print("Failed to create label: ", labelName);
    
      ObjectSetInteger(0, labelName, OBJPROP_COLOR, lineColor);
      ObjectSetInteger(0, labelName, OBJPROP_ANCHOR, ANCHOR_LEFT);
      ObjectSetString(0, labelName, OBJPROP_TEXT, labelText);
      ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, 10);
      ObjectSetInteger(0, labelName, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
      ObjectSetInteger(0, labelName, OBJPROP_XOFFSET, 5);
      ObjectSetInteger(0, labelName, OBJPROP_YOFFSET, 0);
    }

    Vamos discutir detalhadamente o desempenho do script antes de prosseguir com o desenvolvimento do Expert Advisor:

    • Permitimos a personalização de aspectos-chave da estratégia de negociação definindo parâmetros de entrada. Oferecemos opções para ajustar os períodos das médias móveis rápidas e lentas, definir as dimensões e cores dos retângulos de risco e recompensa, determinar o número máximo de barras a serem processadas e escolher se os retângulos serão preenchidos com cor. Essa configuração permite que o script seja adaptado a diferentes estratégias de negociação de acordo com as preferências do usuário e formou a seção de parâmetros de entrada do nosso programa:

    //---- Input Parameters
    input int FastMAPeriod = 14;
    input int SlowMAPeriod = 50;
    input double RiskHeightPoints = 5000.0;
    input double RewardHeightPoints = 15000.0;
    input color RiskColor = clrIndianRed;
    input color RewardColor = clrSpringGreen;
    input int MaxBars = 500;
    input int RectangleWidth = 10;
    input bool FillRectangles = true;
    input int FillTransparency = 128;

    • Na função (OnStart), garantimos que o gráfico permanecesse limpo programando o script para primeiro excluir qualquer retângulo de risco/recompensa e linhas de preço existentes. Em seguida, fizemos com que ele calculasse as médias móveis rápidas e lentas usando a função (iMA) e armazenasse esses valores em arrays para processamento posterior. À medida que o script percorre as barras no gráfico, estabelecemos condições para detectar cruzamentos de alta, onde a média móvel rápida cruzou acima da média lenta. Quando essas condições são atendidas, o script calcula o preço de entrada, o nível de risco (stop loss) e o nível de recompensa (take profit). Ele então desenha retângulos e linhas de preço no gráfico, marcando efetivamente esses níveis críticos de negociação, como explicaremos em trechos de subcódigo abaixo:

    //----Onstart Function
    void OnStart()
    {
      //--- delete existing rectangles and lines
      DeleteExistingObjects();
    
      //--- declare and initialize variables
      int i, limit;
      double FastMA[], SlowMA[];
      double closePrice, riskLevel, rewardLevel;
    
      //--- calculate moving averages
      if (iMA(NULL, 0, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE) < 0 || iMA(NULL, 0, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE) < 0)
      {
        Print("Error in calculating moving averages.");
        return;
      }
    

    • Para manter a clareza no gráfico, desenvolvemos a função "Excluir Objetos Existentes", que o script usa para remover qualquer objeto desenhado anteriormente relacionado aos sinais de negociação. Ao verificar os nomes de todos os objetos no gráfico, o script garantiu que apenas as informações mais recentes e relevantes fossem exibidas, mantendo o gráfico focado e livre de desordem:

    //---- DeleteAllExistingObjects Function
    void DeleteExistingObjects()
    {
      int totalObjects = ObjectsTotal(0, 0, -1);
      for (int i = totalObjects - 1; i >= 0; i--)
      {
        string name = ObjectName(0, i, 0, -1);
        if (StringFind(name, "Risk_") >= 0 || StringFind(name, "Reward_") >= 0 ||
            StringFind(name, "Entry_") >= 0 || StringFind(name, "StopLoss_") >= 0 ||
            StringFind(name, "TakeProfit_") >= 0)
        {
          ObjectDelete(0, name);
        }
      }
    }

    • Na função "Desenhar Retângulo", garantimos que o script pudesse representar visualmente os níveis de risco e recompensa, primeiro removendo quaisquer retângulos existentes com o mesmo nome para evitar duplicação. Em seguida, fizemos o script calcular os tempos de início e fim dos retângulos com base nos índices das barras e cuidadosamente definimos as cores e os níveis de transparência. Isso permitiu que os retângulos se destacassem no gráfico sem obscurecer outros detalhes importantes:
    ///---Draw rectangle function
    void DrawRectangle(string name, int startBar, double startPrice, int endBar, double endPrice, color rectColor)
    {
      if (ObjectFind(0, name) >= 0)
        ObjectDelete(0, name);
    
      datetime startTime = iTime(NULL, 0, startBar);
      datetime endTime = (endBar < 0) ? (TimeCurrent() + (PeriodSeconds() * (-endBar))) : iTime(NULL, 0, endBar);
    
      if (!ObjectCreate(0, name, OBJ_RECTANGLE, 0, startTime, startPrice, endTime, endPrice))
        Print("Failed to create rectangle: ", name);
    
      int alphaValue = FillTransparency;
      color fillColor = rectColor & 0x00FFFFFF | (alphaValue << 24);
    
      ObjectSetInteger(0, name, OBJPROP_COLOR, rectColor);
      ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID);
      ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
      ObjectSetInteger(0, name, OBJPROP_BACK, true);
    
      if (FillRectangles)
      {
        ObjectSetInteger(0, name, OBJPROP_COLOR, fillColor);
      }
      else
      {
        ObjectSetInteger(0, name, OBJPROP_COLOR, rectColor & 0x00FFFFFF);
      }
    }

      • Finalmente, implementamos a função "Desenhar Linha de Preço" para instruir o script a adicionar linhas horizontais nos níveis de entrada, stop loss e take profit. O script estendeu essas linhas pelo gráfico e adicionou rótulos de texto que exibiam os níveis de preço correspondentes. Isso forneceu uma referência visual, permitindo que os usuários identificassem e gerenciassem rapidamente os pontos chave para negociações com base nos sinais gerados pelas médias móveis:

      ///---- Draw Price Lines Function
      void DrawPriceLine(string name, int barIndex, double price, color lineColor, string labelText)
      {
        datetime time = iTime(NULL, 0, barIndex);
        datetime endTime = (barIndex - 2 * RectangleWidth < 0) ? (TimeCurrent() + (PeriodSeconds() * (-barIndex - 2 * RectangleWidth))) : iTime(NULL, 0, barIndex - 2 * RectangleWidth);
      
        if (!ObjectCreate(0, name, OBJ_TREND, 0, time, price, endTime, price))
          Print("Failed to create price line: ", name);
      
        ObjectSetInteger(0, name, OBJPROP_COLOR, lineColor);
        ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID);
        ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
        ObjectSetInteger(0, name, OBJPROP_BACK, true);
      
        string labelName = name + "_Label";
        if (ObjectFind(0, labelName) >= 0)
          ObjectDelete(0, labelName);
      
        if (!ObjectCreate(0, labelName, OBJ_TEXT, 0, endTime, price))
          Print("Failed to create label: ", labelName);
      
        ObjectSetInteger(0, labelName, OBJPROP_COLOR, lineColor);
        ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, 10);
        ObjectSetString(0, labelName, OBJPROP_TEXT, labelText);
        ObjectSetInteger(0, labelName, OBJPROP_BACK, true);
      }
      

      Agora, como parte do kit de negociação, esse script pode ser executado regularmente para ver os níveis de negociação visualizados, tanto do passado quanto do tempo atual. Agora, vamos seguir para a criação do nosso Expert Advisor exclusivo. Vou focar em explicar todo o desenvolvimento até o EA final funcionando. Neste artigo, vamos nos concentrar apenas em fazê-lo funcionar com o indicador que fizemos anteriormente, Trend Constraint V1.09.


      Criando um Expert Advisor que funcione com base em um indicador:

      Para criar um Expert Advisor (EA) em MQL5 usando um indicador personalizado, precisamos garantir que o arquivo do indicador personalizado (.ex5) esteja disponível na pasta "Indicators" dentro da plataforma MetaTrader 5, neste caso, é o Trend Constraint V1.09. Usando o MetaEditor, podemos escrever nosso EA, incorporando funções MQL5 para acessar os valores dos buffers do indicador. Utilizamos a função (iCustom()) para chamar o indicador personalizado dentro do EA, especificando os parâmetros necessários, como símbolo e período.

      Para extrair dados dos buffers do indicador, usamos a função (CopyBuffer()), que recupera os valores do buffer que você pretende analisar para sinais de negociação. Depois, implementamos nossa lógica de negociação com base nesses valores de buffer, definindo condições para abrir, fechar ou modificar ordens de acordo com nossa estratégia. Integramos funcionalidades de gerenciamento de risco, como stop-loss e take-profit, para um gerenciamento prudente das negociações. Testamos o EA no MetaTrader 5 usando o Strategy Tester para avaliar seu desempenho e ajustar seus parâmetros. Por fim, verificamos a funcionalidade do EA em um ambiente de conta demo antes de migrar para a negociação ao vivo, para garantir que ele opere efetivamente em condições reais de mercado.

      Podemos começar lançando um modelo de Expert Advisor no MetaEditor e depois desenvolvê-lo ou modificá-lo com base no exemplo mostrado nesta imagem:

      Lançar um modelo de EA no MetaEditor

      Lançando um modelo de Expert Advisor no MetaEditor

      Para guiá-lo na construção do nosso Expert Advisor (EA), vamos dividir o processo em seis etapas. À medida que avançamos, recomendo digitar os trechos de código diretamente no MetaEditor. Essa abordagem prática ajudará você a entender melhor e internalizar os passos, especialmente se você for novo no desenvolvimento de EAs.

      1. Cabeçalho e Metadados

      Na seção de cabeçalho, definimos o nome e o objetivo do nosso Expert Advisor (EA). Incluindo informações de copyright, um link para o nosso perfil e especificando a versão, garantimos que nosso EA seja facilmente identificável e rastreável. Esses metadados nos ajudam a entender a origem e o propósito do EA, especialmente quando ele é compartilhado ou modificado:

      //You can replace the author details with yours.
      //+------------------------------------------------------------------+
      //|                                    Trend Constraint Expert.mq5   |
      //|                                Copyright 2024, Clemence Benjamin |
      //|                                             https://www.mql5.com |
      //+------------------------------------------------------------------+
      #property strict
      #property copyright "Copyright 2024, Clemence Benjamin"
      #property link      "https://www.mql5.com/en/users/billionaire2024/seller"
      #property version   "1.0"
      #property description "An Expert based on the buffer6 and buffer7 of Trend Constraint V1.09"

      2. Parâmetros de Entrada

      Aqui, definimos os principais parâmetros de entrada que nos permitem personalizar o comportamento do EA sem alterar o código em si. Ao definir parâmetros como (Lots, Slippage, Stop Loss, Take Profit e Magic Number), tornamos o EA flexível e adaptável a diferentes estratégias de negociação. O número mágico é particularmente importante, pois nos permite identificar de forma única as negociações feitas por este EA, o que é crucial quando múltiplos EAs ou negociações manuais estão envolvidos:

      ///----------- EA inputs parameters for customizations
      input double Lots = 0.1;          // Lot size
      input int Slippage = 3;           // Slippage
      input double StopLoss = 50;       // Stop Loss in points
      input double TakeProfit = 100;    // Take Profit in points
      input int MagicNumber = 123456;   // Magic number for orders

      3. Função de Inicialização (OnInit)

      Na função OnInit, preparamos o ambiente para a operação do EA, inicializando os componentes necessários. Começamos tentando obter um identificador para o nosso indicador personalizado, "Trend Constraint V1.09". Esse identificador nos permite interagir programaticamente com o indicador. Se o identificador for obtido com sucesso, continuamos configurando os arrays de buffer (Buffer6 e Buffer7) em série, permitindo-nos armazenar e manipular os valores do indicador. Se, no entanto, o identificador não puder ser recuperado, garantimos que o EA retorne uma falha de inicialização, com uma mensagem de erro para nos ajudar a diagnosticar o problema:

      ////-------Initialization Function
      int OnInit()
        {
         //--- Get the indicator handle
         indicator_handle = iCustom(Symbol(), PERIOD_CURRENT, "Trend Constraint V1.09");
         if (indicator_handle < 0)
           {
            Print("Failed to get the indicator handle. Error: ", GetLastError());
            return(INIT_FAILED);
           }
      
         //--- Set the buffer arrays as series
         ArraySetAsSeries(Buffer6, true);
         ArraySetAsSeries(Buffer7, true);
      
         return(INIT_SUCCEEDED);
        }
      

      4. Função de Inicialização (OnDeinit)

      Quando nosso EA é removido do gráfico ou quando a plataforma é fechada, a função (OnDeinit) é executada. Aqui, tomamos cuidado para liberar o identificador do indicador, garantindo que liberamos qualquer recurso alocado durante a operação do EA. Esse passo de limpeza é crucial para manter a eficiência e estabilidade do nosso ambiente de negociação, pois evita o consumo desnecessário de recursos:

      ///------Deinitialization Function(OnDeinit)
      void OnDeinit(const int reason)
        {
         //--- Release the indicator handle
         IndicatorRelease(indicator_handle);
        }
      

      5. Função de Execução Principal (OnTick)

      A função (OnTick) é onde ocorre a verdadeira ação de negociação. Cada vez que um novo tick do mercado é recebido, essa função é chamada. Começamos verificando se já existe uma posição aberta com o mesmo número mágico, garantindo que não colocamos negociações duplicadas. Em seguida, copiamos os valores mais recentes dos buffers do indicador (Buffer6 e Buffer7) para tomar decisões de negociação. Se nossas condições para um sinal de compra ou venda forem atendidas, construímos e enviamos a solicitação de negociação apropriada. Cuidamos de especificar todos os parâmetros necessários, como o tipo de ordem, preço, stop loss, take profit e slippage, para executar nossa estratégia de negociação de forma eficaz:

      ///---Main Execution Function(OnTick)
      void OnTick()
        {
         //--- Check if there is already an open position with the same MagicNumber
         if (PositionSelect(Symbol()))
           {
            if (PositionGetInteger(POSITION_MAGIC) == MagicNumber)
              {
               return; // Exit OnTick if there's an open position with the same MagicNumber
              }
           }
      
         //--- Calculate the indicator
         if (CopyBuffer(indicator_handle, 5, 0, 2, Buffer6) <= 0 || CopyBuffer(indicator_handle, 6, 0, 2, Buffer7) <= 0)
           {
            Print("Failed to copy buffer values. Error: ", GetLastError());
            return;
           }
      
         //--- Check for a buy signal
         if (Buffer7[0] != EMPTY_VALUE)
           {
            double ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
            double sl = NormalizeDouble(ask - StopLoss * _Point, _Digits);
            double tp = NormalizeDouble(ask + TakeProfit * _Point, _Digits);
      
            //--- Prepare the buy order request
            MqlTradeRequest request;
            MqlTradeResult result;
            ZeroMemory(request);
            ZeroMemory(result);
      
            request.action = TRADE_ACTION_DEAL;
            request.symbol = Symbol();
            request.volume = Lots;
            request.type = ORDER_TYPE_BUY;
            request.price = ask;
            request.sl = sl;
            request.tp = tp;
            request.deviation = Slippage;
            request.magic = MagicNumber;
            request.comment = "Buy Order";
      
            //--- Send the buy order
            if (!OrderSend(request, result))
              {
               Print("Error opening buy order: ", result.retcode);
              }
            else
              {
               Print("Buy order opened successfully! Ticket: ", result.order);
              }
           }
      
         //--- Check for a sell signal
         if (Buffer6[0] != EMPTY_VALUE)
           {
            double bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
            double sl = NormalizeDouble(bid + StopLoss * _Point, _Digits);
            double tp = NormalizeDouble(bid - TakeProfit * _Point, _Digits);
      
            //--- Prepare the sell order request
            MqlTradeRequest request;
            MqlTradeResult result;
            ZeroMemory(request);
            ZeroMemory(result);
      
            request.action = TRADE_ACTION_DEAL;
            request.symbol = Symbol();
            request.volume = Lots;
            request.type = ORDER_TYPE_SELL;
            request.price = bid;
            request.sl = sl;
            request.tp = tp;
            request.deviation = Slippage;
            request.magic = MagicNumber;
            request.comment = "Sell Order";
      
            //--- Send the sell order
            if (!OrderSend(request, result))
              {
               Print("Error opening sell order: ", result.retcode);
              }
            else
              {
               Print("Sell order opened successfully! Ticket: ", result.order);
              }
           }
        }
      

      6. Outras Funções

      Também incluímos várias outras funções para lidar com diferentes eventos que nosso EA possa encontrar, e elas vieram como parte de um modelo de EA, mas atualmente não as usamos para simplicidade:

      • (OnTrade): Aqui, podemos lidar com quaisquer ações específicas que precisem ocorrer quando um evento de negociação acontecer. Embora atualmente esteja vazio, essa função oferece um espaço para adicionar lógica, se necessário.
      • (OnTester): Essa função é usada para cálculos personalizados durante o back-testing. Ao retornar um valor, podemos otimizar nossa estratégia com base em métricas específicas.
      • (OnTesterInit, OnTesterPass, OnTesterDeinit): Essas funções estão envolvidas no processo de otimização dentro do Strategy Tester. Elas nos permitem inicializar configurações, realizar ações após cada passagem de otimização e limpar os recursos depois.
      • (OnChartEvent): Essa função nos permite lidar com vários eventos do gráfico, como cliques do mouse ou pressionamentos de teclas. Embora esteja atualmente vazia, podemos usar esse espaço para adicionar recursos interativos ao nosso EA:
      ///----Other Template functions available
      void OnTrade()
        {
         //--- Handle trade events if necessary
        }
      
      double OnTester()
        {
         double ret = 0.0;
         //--- Custom calculations for strategy tester
         return (ret);
        }
      
      void OnTesterInit()
        {
         //--- Initialization for the strategy tester
        }
      
      void OnTesterPass()
        {
         //--- Code executed after each pass in optimization
        }
      
      void OnTesterDeinit()
        {
         //--- Cleanup after tester runs
        }
      
      void OnChartEvent(const int id,
                        const long &lparam,
                        const double &dparam,
                        const string &sparam)
        {
         //--- Handle chart events here
        }
      

      Nosso programa final montado fica assim:

      //+------------------------------------------------------------------+
      //|                                    Trend Constraint Expert.mq5   |
      //|                                Copyright 2024, Clemence Benjamin |
      //|                                             https://www.mql5.com |
      //+------------------------------------------------------------------+
      #property strict
      #property copyright "Copyright 2024, Clemence Benjamin"
      #property link      "https://www.mql5.com/en/users/billionaire2024/seller"
      #property version   "1.0"
      #property description "An Expert based on the buffer6 and buffer7 of Trend Constraint V1.09"
      
      //--- Input parameters for the EA
      input double Lots = 0.1;          // Lot size
      input int Slippage = 3;           // Slippage
      input double StopLoss = 50;       // Stop Loss in points
      input double TakeProfit = 100;    // Take Profit in points
      input int MagicNumber = 123456;   // Magic number for orders
      
      //--- Indicator handle
      int indicator_handle;
      double Buffer6[];
      double Buffer7[];
      
      //+------------------------------------------------------------------+
      //| Expert initialization function                                   |
      //+------------------------------------------------------------------+
      int OnInit()
        {
         //--- Get the indicator handle
         indicator_handle = iCustom(Symbol(), PERIOD_CURRENT, "Trend Constraint V1.09");
         if (indicator_handle < 0)
           {
            Print("Failed to get the indicator handle. Error: ", GetLastError());
            return(INIT_FAILED);
           }
      
         //--- Set the buffer arrays as series
         ArraySetAsSeries(Buffer6, true);
         ArraySetAsSeries(Buffer7, true);
      
         return(INIT_SUCCEEDED);
        }
      
      //+------------------------------------------------------------------+
      //| Expert deinitialization function                                 |
      //+------------------------------------------------------------------+
      void OnDeinit(const int reason)
        {
         //--- Release the indicator handle
         IndicatorRelease(indicator_handle);
        }
      
      //+------------------------------------------------------------------+
      //| Expert tick function                                             |
      //+------------------------------------------------------------------+
      void OnTick()
        {
         //--- Check if there is already an open position with the same MagicNumber
         if (PositionSelect(Symbol()))
           {
            if (PositionGetInteger(POSITION_MAGIC) == MagicNumber)
              {
               return; // Exit OnTick if there's an open position with the same MagicNumber
              }
           }
      
         //--- Calculate the indicator
         if (CopyBuffer(indicator_handle, 5, 0, 2, Buffer6) <= 0 || CopyBuffer(indicator_handle, 6, 0, 2, Buffer7) <= 0)
           {
            Print("Failed to copy buffer values. Error: ", GetLastError());
            return;
           }
      
         //--- Check for a buy signal
         if (Buffer7[0] != EMPTY_VALUE)
           {
            double ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
            double sl = NormalizeDouble(ask - StopLoss * _Point, _Digits);
            double tp = NormalizeDouble(ask + TakeProfit * _Point, _Digits);
      
            //--- Prepare the buy order request
            MqlTradeRequest request;
            MqlTradeResult result;
            ZeroMemory(request);
            ZeroMemory(result);
      
            request.action = TRADE_ACTION_DEAL;
            request.symbol = Symbol();
            request.volume = Lots;
            request.type = ORDER_TYPE_BUY;
            request.price = ask;
            request.sl = sl;
            request.tp = tp;
            request.deviation = Slippage;
            request.magic = MagicNumber;
            request.comment = "Buy Order";
      
            //--- Send the buy order
            if (!OrderSend(request, result))
              {
               Print("Error opening buy order: ", result.retcode);
              }
            else
              {
               Print("Buy order opened successfully! Ticket: ", result.order);
              }
           }
      
         //--- Check for a sell signal
         if (Buffer6[0] != EMPTY_VALUE)
           {
            double bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
            double sl = NormalizeDouble(bid + StopLoss * _Point, _Digits);
            double tp = NormalizeDouble(bid - TakeProfit * _Point, _Digits);
      
            //--- Prepare the sell order request
            MqlTradeRequest request;
            MqlTradeResult result;
            ZeroMemory(request);
            ZeroMemory(result);
      
            request.action = TRADE_ACTION_DEAL;
            request.symbol = Symbol();
            request.volume = Lots;
            request.type = ORDER_TYPE_SELL;
            request.price = bid;
            request.sl = sl;
            request.tp = tp;
            request.deviation = Slippage;
            request.magic = MagicNumber;
            request.comment = "Sell Order";
      
            //--- Send the sell order
            if (!OrderSend(request, result))
              {
               Print("Error opening sell order: ", result.retcode);
              }
            else
              {
               Print("Sell order opened successfully! Ticket: ", result.order);
              }
           }
        }
      
      //+------------------------------------------------------------------+
      //| Trade function                                                   |
      //+------------------------------------------------------------------+
      void OnTrade()
        {
         //--- Handle trade events if necessary
        }
      
      //+------------------------------------------------------------------+
      //| Tester function                                                  |
      //+------------------------------------------------------------------+
      double OnTester()
        {
         double ret = 0.0;
         //--- Custom calculations for strategy tester
         return (ret);
        }
      
      //+------------------------------------------------------------------+
      //| TesterInit function                                              |
      //+------------------------------------------------------------------+
      void OnTesterInit()
        {
         //--- Initialization for the strategy tester
        }
      
      //+------------------------------------------------------------------+
      //| TesterPass function                                              |
      //+------------------------------------------------------------------+
      void OnTesterPass()
        {
         //--- Code executed after each pass in optimization
        }
      
      //+------------------------------------------------------------------+
      //| TesterDeinit function                                            |
      //+------------------------------------------------------------------+
      void OnTesterDeinit()
        {
         //--- Cleanup after tester runs
        }
      
      //+------------------------------------------------------------------+
      //| ChartEvent function                                              |
      //+------------------------------------------------------------------+
      void OnChartEvent(const int id,
                        const long &lparam,
                        const double &dparam,
                        const string &sparam)
        {
         //--- Handle chart events here
        }
      //+------------------------------------------------------------------+
      

      No próximo segmento, após uma compilação bem-sucedida, vamos testar nosso programa.


      Testando

      No MetaEditor, podemos usar o botão "Compilar" ou "Executar" para preparar nosso programa para teste. Neste caso, a compilação foi bem-sucedida e lançamos o teste no índice Boom 500 usando o Strategy Tester.

      Lançando o Strategy Tester

      Lançando o Tester a partir do navegador

      Um painel do Strategy Tester é aberto, permitindo que você ajuste algumas configurações antes de clicar no botão "Iniciar" no canto inferior direito. Por exemplo, o tamanho do lote padrão no EA está definido para 0,1 lotes, mas para o índice Boom 500, precisei aumentá-lo para um mínimo de 0,2 lotes neste caso.

      Strategy Testor

      Painel Strategy Tester

      Surpreendentemente, nosso sistema teve um bom desempenho no Strategy Tester, como mostrado na imagem abaixo:

      Replay MetaTester

      Visualização do Strategy Tester: Expert Trend Constraint


      Conclusão

      A adição de retângulos de risco e recompensa fornece aos traders uma representação gráfica clara de suas negociações, facilitando o monitoramento e o gerenciamento das posições abertas. Essa ajuda visual é particularmente útil em mercados de rápido movimento, onde decisões rápidas são necessárias. Os retângulos servem como um lembrete constante dos resultados potenciais da negociação, ajudando os traders a manterem-se alinhados com seu plano original de negociação.

      A colaboração bem-sucedida entre o indicador (Trend Constraint V1.09) e o Expert Advisor destaca a importância da sinergia entre ferramentas em uma estratégia de negociação. O indicador identifica tendências e reversões potenciais, enquanto o EA executa negociações e gerencia riscos com base nessas informações. Essa abordagem integrada leva a uma estratégia de negociação mais coesa e eficaz.

      Abaixo estão os arquivos do indicador, script e EA usados. Ainda há espaço para melhorias e modificações. Espero que você tenha achado esta informação valiosa. Fique à vontade para compartilhar suas opiniões na seção de comentários. Feliz Negociação!

      Arquivo Anexo Descrição
      (Trend_Constraint V1.09.mq5) Código fonte do indicador para funcionar com o EA.
      (Trend Constraint R-R.mq5) Código fonte para o Script de Retângulo de Risco-Recompensa.
      (Trend Constraint Expert.mq5) Código fonte para o Expert Advisor que funciona estritamente com (Trend Constraint V1.09)

      Voltar ao conteúdo

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

      Últimos Comentários | Ir para discussão (2)
      Helga Gustana Argita
      Helga Gustana Argita | 14 ago. 2024 em 19:50
      Olá, estou com um erro e como corrigi-lo?

      2024.08.15 00:47:15.123 2024.08.01 00:00:00 não é possível carregar o indicador personalizado 'Trend Constraint V1.09' [4802]
      2024.08.15 00:47:15.123 2024.08.01 00:00:00 erro de criação de indicador em 'Trend_Constraint_Expert.mq5' (1,1)

      Clemence Benjamin
      Clemence Benjamin | 15 ago. 2024 em 22:43
      argatafx28 o indicador personalizado 'Trend Constraint V1.09' [4802]
      2024.08.15 00:47:15.123 2024.08.01 00:00:00 erro de criação de indicador em 'Trend_Constraint_Expert.mq5' (1,1)

      Olá @argatafx28

      1. Certifique-se de que o indicador Trend Constraint V1.09 esteja instalado para que o EA funcione.
      2. O Trend Constraint V1.09 usa o ShellExecute para integrar o telegrama. Você poderia se certificar de permitir a DLL nas dependências ao iniciar o indicador?


      Habilitar Permitir DLL

      A propósito, qual sistema operacional você está usando?
      Integração MQL5: Python Integração MQL5: Python
      Python é uma linguagem de programação bem conhecida e popular, com muitos recursos, especialmente nas áreas de finanças, ciência de dados, Inteligência Artificial e Aprendizado de Máquina. Python é uma ferramenta poderosa que também pode ser útil no trading. O MQL5 nos permite usar essa poderosa linguagem como uma integração para alcançar nossos objetivos de forma eficaz. Neste artigo, compartilharemos como podemos usar Python como uma integração no MQL5, depois de aprender algumas informações básicas sobre Python.
      Implementação do EA Deus: Negociação automatizada com RSI e médias móveis em MQL5 Implementação do EA Deus: Negociação automatizada com RSI e médias móveis em MQL5
      O artigo descreve as etapas para a implementação do EA Deus baseado nos indicadores RSI e média móvel para gerenciar a negociação automatizada.
      Reconhecimento de Padrões Usando Dynamic Time Warping em MQL5 Reconhecimento de Padrões Usando Dynamic Time Warping em MQL5
      Neste artigo, discutimos o conceito de dynamic time warping como uma forma de identificar padrões preditivos em séries temporais financeiras. Veremos como ele funciona e também apresentaremos sua implementação em MQL5 puro.
      Funcionalidades do Assistente MQL5 que você precisa conhecer (Parte 30): Normalização em Lote no Aprendizado de Máquina Funcionalidades do Assistente MQL5 que você precisa conhecer (Parte 30): Normalização em Lote no Aprendizado de Máquina
      A normalização em lote é um pré-processamento dos dados antes de sua entrada em um algoritmo de aprendizado de máquina, como uma rede neural. Ao aplicá-la, é essencial levar em conta o tipo de ativação que será usado pelo algoritmo. Exploraremos diferentes abordagens para extrair vantagens com um EA construído no Assistente.