English Русский 中文 Español Deutsch 日本語
preview
Desenvolvimento do Kit de Ferramentas de Análise de Ação de Preço (Parte 14): Ferramenta de Stop Parabolic e Reversão

Desenvolvimento do Kit de Ferramentas de Análise de Ação de Preço (Parte 14): Ferramenta de Stop Parabolic e Reversão

MetaTrader 5Indicadores |
17 0
Christian Benjamin
Christian Benjamin

Conteúdo:


Introdução

Indicadores técnicos são sinais gerados por meio da análise de padrões históricos de dados, como preço, volume e interesse em aberto. Essas ferramentas heurísticas permitem que os traders avaliem o comportamento do mercado e projetem movimentos futuros com base em tendências comprovadas e modelos estatísticos.

Neste artigo, focamos no desenvolvimento de um Expert Advisor (EA) utilizando MQL5, projetado para identificar possíveis reversões de mercado. O EA utiliza o Parabolic SAR para detecção de sinais, gerando sinais de negociação ao monitorar indicadores técnicos, avaliar sua validade em tempo real e identificar pontos ideais de saída quando níveis predefinidos são alcançados.

Nossa discussão começa com uma visão geral da estratégia subjacente e da justificativa para o uso de indicadores técnicos no trading. Em seguida, detalharemos o processo de implementação em MQL5, analisaremos de forma abrangente os resultados dos testes e concluiremos com insights e recomendações para traders que desejam integrar essas técnicas em seus sistemas.


Compreendendo a Estratégia

Parabolic SAR

No indicador Parabolic SAR, o termo "parabolic" refere-se ao formato da curva plotada. À medida que a tendência avança, os pontos do indicador aceleram em um padrão curvo, parabólico, refletindo o aumento do momentum conforme os preços se afastam dos extremos recentes.

Por outro lado, "SAR" significa "Stop and Reverse." Esse componente do indicador sinaliza possíveis reversões de tendência. Quando os pontos mudam de um lado do preço para o outro, isso sugere que a tendência atual pode estar chegando ao fim, levando os traders a considerar encerrar sua posição atual e se preparar para uma possível reversão na direção do mercado.

Antes de aprofundarmos nosso conceito, é essencial adicionar o Parabolic SAR ao seu gráfico para fácil referência. Existem dois métodos para fazer isso, mas explicarei uma abordagem. Em seu aplicativo MetaTrader 5, clique no menu Insert, depois navegue até Indicators e selecione Trend. Localize e insira o Parabolic SAR. Após adicioná-lo, configure os parâmetros conforme sua preferência, garantindo que estejam alinhados com aqueles utilizados em seu Expert Advisor (EA).

Para mais detalhes sobre como adicionar o indicador, consulte a Figura 1 abaixo.

Adicionando o indicador

Fig 1. Adicionando o indicador

Lógica de Geração de Sinais

Trabalhar com o indicador Parabolic SAR envolve monitorar de perto a interação entre a parábola do SAR e a ação do preço. Nesta estratégia, os sinais são gerados com base na seguinte lógica:

Sinal de Compra

Um sinal de compra é acionado quando:

  • A barra atual é de alta (seu fechamento é maior que sua abertura) e seu valor PSAR está abaixo do fechamento.
  • As duas barras anteriores confirmam uma tendência de baixa, pois seus pontos PSAR estão acima dos preços de fechamento.
  • A diferença entre os valores de PSAR das barras anteriores está dentro de uma faixa aceitável, garantindo a consistência.

CONDIÇÕES DE COMPRA

Fig 2. Condições de Compra

Sinal de Venda

Um sinal de venda é acionado quando:

  • A barra atual é bearish (seu fechamento é menor que sua abertura) e seu valor de PSAR está acima do fechamento.
  • As duas barras anteriores confirmam uma tendência de alta ao apresentarem seus pontos de PSAR abaixo de seus preços de fechamento.
  • Da mesma forma, a diferença entre os valores de PSAR das barras anteriores deve estar dentro de um limite predefinido.

SINAL DE VENDA

Fig 3. Condições de Venda


Implementação em MQL5

Cabeçalho do Arquivo e Propriedades

No topo do código, começamos com um cabeçalho que inclui informações essenciais do arquivo, como o nome do arquivo, detalhes de copyright e um link para a página do autor, neste caso, forneci a minha. Isso é imediatamente seguido por várias diretivas #property, que configuram propriedades críticas de compilação, como o número da versão e o modo estrito. 

//+--------------------------------------------------------------------+
//|                                              Parabolic SAR EA.mql5 |
//|                                 Copyright 2025, Christian Benjamin |
//|                                               https://www.mql5.com |
//+--------------------------------------------------------------------+
#property copyright "2025, Christian Benjamin"
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.0"
#property strict

O uso de #property strict é fundamental, pois impõe verificação rigorosa de tipos e validação de parâmetros dentro do EA. Essa precaução ajuda a identificar possíveis erros de codificação antes que se transformem em erros em tempo de execução. Seja você esteja planejando publicar o EA ou utilizá-lo em um ambiente de negociação ao vivo, essa configuração atua como uma salvaguarda, garantindo operação fluida e conformidade futura com atualizações do MetaTrader 5. Pense nisso como uma medida essencial de controle de qualidade para o seu código.

Parâmetros de Entrada

Em seguida, o código define uma série de parâmetros de entrada que você pode personalizar diretamente pela interface do MetaTrader 5. Essas entradas incluem parâmetros para o indicador Parabolic SAR, como SARStep e SARMaximum, que controlam o fator de aceleração e a aceleração máxima, respectivamente. Há também configurações para refinar a detecção de sinais, como MinConsecutiveDots e MaxDotGapPercentage, que ajudam a garantir que apenas tendências fortes acionem sinais. Você também pode habilitar alertas, notificações sonoras e o desenho de setas no gráfico.

// Input parameters for the Parabolic SAR indicator
input double SARStep    = 0.02;  // Acceleration factor for PSAR
input double SARMaximum = 0.2;   // Maximum acceleration for PSAR

// Input parameters for refining the signal based on PSAR dots
input int    MinConsecutiveDots = 2;          // Require at least 2 consecutive bars in one trend before reversal
input double MaxDotGapPercentage  = 1.0;      // Maximum allowed gap between consecutive PSAR dots (% of current close)

// Input parameters for alerts and arrow drawing
input bool   EnableAlerts  = true;            // Enable popup alerts
input bool   EnableSound   = true;            // Enable sound alerts
input bool   EnableArrows  = true;            // Draw arrows on chart
input string BuyArrowSymbol  = "233";         // Wingdings up arrow (as string)
input string SellArrowSymbol = "234";         // Wingdings down arrow (as string)
input int    ArrowWidth    = 2;               // Arrow thickness
input double ArrowOffsetMultiplier = 5;       // Multiplier for arrow placement offset

Essas entradas permitem personalizar o EA para diferentes condições de mercado e suas preferências de negociação. Um aspecto importante aqui é a versatilidade dos símbolos de seta no MetaTrader 5. Esses símbolos, provenientes da fonte Wingdings, são facilmente personalizáveis. Por exemplo, você pode escolher um sinal de verificação para sinais de compra ou um “X” para sinais de venda, dependendo do seu estilo de negociação. Ajustar parâmetros como a largura da seta melhora ainda mais a visibilidade dos sinais, permitindo que você ajuste os elementos visuais do gráfico para maior clareza e reconhecimento imediato.

Variáveis Globais e Enumerações

Para gerenciar o estado interno do EA, várias variáveis globais e uma enumeração são declaradas. Por exemplo, armazenamos o handle do indicador Parabolic SAR na variável sarHandle, o que nos permite referenciar o indicador ao longo do código. Por exemplo, armazenamos o handle do indicador Parabolic SAR na variável sarHandle, o que nos permite referenciar o indicador ao longo do código. A enumeração SignalType define os possíveis estados de sinal: nenhum sinal, sinal de compra ou sinal de venda.

// Global indicator handle for PSAR
int sarHandle = INVALID_HANDLE;

// Global variable to track last processed bar time
datetime lastBarTime = 0;

// Enumeration for signal types
enum SignalType
  {
   NO_SIGNAL,
   BUY_SIGNAL,
   SELL_SIGNAL
  };

// Global variables for pending signal mechanism
SignalType pendingSignal = NO_SIGNAL;
int        waitCount     = 0;          // Counts new closed bars since signal detection
double     pendingReversalLevel = 0.0; // Stores the PSAR value at signal detection

Além disso, variáveis como pendingSignal, waitCount e pendingReversalLevel são utilizadas para gerenciar sinais pendentes que aguardam confirmação adicional ao longo de algumas barras antes que uma ação final seja tomada.Uma variável crítica é pendingReversalLevel, que captura o valor do PSAR no momento em que um sinal é gerado. Servindo como ponto de referência, esse nível ajuda o EA a monitorar os movimentos subsequentes do preço para determinar se a reversão é genuína ou apenas um falso sinal. Esse mecanismo de verificação é vital para reduzir negociações desnecessárias e aprimorar a precisão geral do EA.

Desenhando Setas no Gráfico

Para uma representação visual mais intuitiva, o EA inclui uma função chamada DrawSignalArrow. Essa função é responsável por desenhar uma seta no gráfico quando um sinal é detectado. Ela funciona gerando um nome de objeto exclusivo com base no horário da barra, verificando se já existe um objeto com esse nome e excluindo-o para evitar duplicação.

void DrawSignalArrow(string prefix, datetime barTime, double price, color arrowColor, long arrowCode)
  {
   string arrowName = prefix + "_" + TimeToString(barTime, TIME_SECONDS);
   // Remove existing object with the same name to prevent duplicates
   if(ObjectFind(0, arrowName) != -1)
      ObjectDelete(0, arrowName);

   if(ObjectCreate(0, arrowName, OBJ_ARROW, 0, barTime, price))
     {
      ObjectSetInteger(0, arrowName, OBJPROP_COLOR, arrowColor);
      ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, arrowCode);
      ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, ArrowWidth);
     }
   else
     {
      Print("Failed to create arrow object: ", arrowName);
     }
  }

O EA utiliza o objeto OBJ_ARROW para representar visualmente os sinais no gráfico. Para evitar poluição visual com marcadores duplicados, o código primeiro verifica e remove quaisquer setas existentes antes de desenhar uma nova. Essa abordagem mantém o gráfico limpo e legível, algo crucial para decisões de negociação em tempo real. Você também pode personalizar diversos aspectos, como o símbolo da seta, a cor e o deslocamento, para corresponder à sua preferência pessoal de sinalização visual.

Função de Detecção de Sinais

O coração do EA está na função CheckForSignal. Aqui, o código examina as três barras mais recentes de dados de preço e PSAR. Para que um sinal de compra seja reconhecido, a função verifica se a barra atual é bullish (ou seja, seu preço de fechamento é maior que o de abertura) e se o ponto do PSAR está abaixo do candle, enquanto as duas barras anteriores são bearish com seus pontos de PSAR acima dos candles. A lógica inversa se aplica para um sinal de venda.

SignalType CheckForSignal(const double &sarArray[], const double &openArray[], const double &closeArray[])
  {
   // Mapping indices:
   // Index 0: Last closed bar (current candidate)
   // Index 1: Previous bar
   // Index 2: Bar before previous
   
   double sar0 = sarArray[0], sar1 = sarArray[1], sar2 = sarArray[2];
   double open0 = openArray[0], close0 = closeArray[0];
   double open1 = openArray[1], close1 = closeArray[1];
   double open2 = openArray[2], close2 = closeArray[2];
   
   // Check for BUY signal:
   if((close0 > open0) && (sar0 < close0) &&
      (sar1 > close1) && (sar2 > close2))
     {
      int countBearish = 0;
      if(sar1 > close1) countBearish++;
      if(sar2 > close2) countBearish++;
      double dotGap = MathAbs(sar1 - sar2);
      double gapThreshold = (MaxDotGapPercentage / 100.0) * close0;
      if(countBearish >= MinConsecutiveDots && dotGap <= gapThreshold)
         return BUY_SIGNAL;
     }
   
   // Check for SELL signal:
   if((close0 < open0) && (sar0 > close0) &&
      (sar1 < close1) && (sar2 < close2))
     {
      int countBullish = 0;
      if(sar1 < close1) countBullish++;
      if(sar2 < close2) countBullish++;
      double dotGap = MathAbs(sar1 - sar2);
      double gapThreshold = (MaxDotGapPercentage / 100.0) * close0;
      if(countBullish >= MinConsecutiveDots && dotGap <= gapThreshold)
         return SELL_SIGNAL;
     }
   
   return NO_SIGNAL;
  }

A função também utiliza um limite de diferença para garantir que o espaçamento entre pontos consecutivos do PSAR permaneça dentro de níveis aceitáveis. Se as condições forem atendidas, ela retorna o tipo de sinal apropriado (buy ou sell); caso contrário, retorna nenhum sinal. A função de detecção de sinais identifica reversões de forma eficaz utilizando o posicionamento do PSAR e padrões de candlestick. No entanto, seu design permite aprimoramentos adicionais por meio da incorporação de filtros extras, como médias móveis, RSI ou até mesmo índice de volatilidade. Adicionar essas camadas pode ajudar a eliminar sinais falsos durante mercados laterais ou períodos influenciados por grandes eventos de notícias. Essencialmente, o EA foi construído para ser adaptável, oferecendo liberdade para ajustar sua lógica à sua estratégia exclusiva de negociação e às condições de mercado.

Detecção de Nova Barra

Antes de processar qualquer dado, o EA precisa determinar se uma nova barra foi fechada. A função IsNewBar lida com isso recuperando o horário da barra fechada mais recente e comparando-o com o lastBarTime armazenado. Se os horários forem diferentes, significa que uma nova barra foi formada, então a função atualiza lastBarTime e retorna true.

bool IsNewBar()
  {
   datetime times[];
   if(CopyTime(_Symbol, _Period, 1, 1, times) <= 0)
     {
      Print("Failed to retrieve bar time in IsNewBar().");
      return false;
     }
   if(times[0] != lastBarTime)
     {
      lastBarTime = times[0];
      return true;
     }
   return false;
  }

Essa verificação é crucial, pois garante que o EA processe os dados apenas uma vez por nova barra, evitando processamento repetitivo ou incorreto de sinais. A função IsNewBar é um reforço inteligente de eficiência para o EA. Ao garantir que os sinais sejam processados apenas uma vez por nova barra, ela evita cálculos redundantes e alertas repetidos. Essa simples verificação mantém o EA funcionando de forma eficiente e reduz o risco de interpretar incorretamente movimentos de preço dentro de uma única barra. No geral, isso ajuda a manter um desempenho consistente e previsível na plataforma MetaTrader.

Inicialização e Desinicialização

Quando o EA é carregado, a função OnInit é executada primeiro. Sua principal tarefa é criar um handle para o indicador Parabolic SAR embutido utilizando os parâmetros fornecidos pelo usuário. Se o indicador for inicializado com sucesso, uma mensagem de confirmação é exibida; caso contrário, uma mensagem de erro é gerada e a inicialização falha. Por outro lado, a função OnDeinit é chamada quando o EA é removido do gráfico ou quando o terminal é fechado.

int OnInit()
  {
   // Create the built-in Parabolic SAR indicator handle
   sarHandle = iSAR(_Symbol, _Period, SARStep, SARMaximum);
   if(sarHandle == INVALID_HANDLE)
     {
      Print("Error creating PSAR handle");
      return INIT_FAILED;
     }
   Print("SAR EA initialized successfully.");
   return INIT_SUCCEEDED;
  }

Essa função é responsável por liberar o handle do indicador e limpar quaisquer objetos gráficos (como setas) que foram criados durante a operação do EA, garantindo que nenhuma poluição visual desnecessária permaneça. Um EA bem projetado dá atenção à limpeza durante a desinicialização. Remover setas ou outros elementos visuais criados durante a operação evita que o gráfico fique sobrecarregado com marcadores obsoletos. Esse processo de limpeza é semelhante a uma boa organização, garantindo que, sempre que você iniciar o EA, esteja trabalhando com um gráfico limpo e desempenho ideal do sistema.

Lógica Principal (Função OnTick )

Por fim, a função OnTick é o mecanismo principal que é executado a cada tick. Primeiro, ela verifica se uma nova barra acabou de ser fechada utilizando a função IsNewBar . Se nenhuma nova barra for detectada, a função é encerrada antecipadamente para evitar processamento redundante. Uma vez confirmada uma nova barra, o EA recupera os valores mais recentes do PSAR juntamente com os preços de abertura e fechamento correspondentes das barras recentes. Nesse ponto, o EA avalia se existe um sinal pendente aguardando confirmação. Se houver um sinal pendente, um contador (waitCount) é incrementado para acompanhar quantas barras se passaram.

void OnTick()
  {
   // Process only once per new closed bar
   if(!IsNewBar())
      return;
   
   // Retrieve PSAR and price data
   double sarArray[4];
   if(CopyBuffer(sarHandle, 0, 1, 4, sarArray) < 3) { /* error handling */ }
   double openArray[4], closeArray[4];
   if(CopyOpen(_Symbol, _Period, 1, 4, openArray) < 3 ||
      CopyClose(_Symbol, _Period, 1, 4, closeArray) < 3) { /* error handling */ }
   
   // Pending Signal Logic...
   if(pendingSignal != NO_SIGNAL)
     {
      waitCount++; // Increment waiting counter
      
      if(pendingSignal == BUY_SIGNAL)
        {
         if(closeArray[0] <= pendingReversalLevel)
           {
            // Confirm reversal: Close alert for BUY signal
           }
         else if(waitCount >= 3)
           {
            // Warn about a possible fake BUY signal
           }
        }
      else if(pendingSignal == SELL_SIGNAL)
        {
         if(closeArray[0] >= pendingReversalLevel)
           {
            // Confirm reversal: Close alert for SELL signal
           }
         else if(waitCount >= 3)
           {
            // Warn about a possible fake SELL signal
           }
        }
      return; // Wait until pending signal is resolved
     }
   
   // Check for a new reversal signal if no pending signal exists
   SignalType newSignal = CheckForSignal(sarArray, openArray, closeArray);
   if(newSignal != NO_SIGNAL)
     {
      pendingSignal = newSignal;
      waitCount = 0; // Reset counter
      pendingReversalLevel = sarArray[0]; // Store current PSAR value
      
      // Alert and optionally draw an arrow based on the new signal
      if(newSignal == BUY_SIGNAL) { /* process BUY signal */ }
      else if(newSignal == SELL_SIGNAL) { /* process SELL signal */ }
     }
  }

O EA então verifica se o preço atual atingiu o nível de reversão armazenado: se atingiu, um alerta é emitido para “fechar aqui” referente ao sinal; se três barras se passarem sem confirmação, o EA alerta sobre um possível sinal falso. Se nenhum sinal pendente estiver ativo, o EA chama a função CheckForSignal para verificar se surgiu um novo sinal. Se isso ocorrer, ele armazena o sinal, redefine o contador de espera, define o nível de reversão pendente com base no valor atual do PSAR e aciona os alertas e marcadores visuais apropriados. Um recurso inovador dentro da função OnTick é seu método de filtragem de possíveis sinais falsos.

Ao utilizar um contador (waitCount) para monitorar quantas barras passam após a geração de um sinal, o EA permite tempo para confirmação antes de tomar qualquer ação. Esse atraso é particularmente útil em mercados voláteis, onde oscilações rápidas de preço poderiam acionar sinais prematuros. Ajustar o número de barras de confirmação permite equilibrar entre rapidez e cautela, tornando o EA flexível o suficiente para suportar tanto estratégias de scalping de curto prazo quanto estratégias de tendência de longo prazo.

Código Completo do EA em MQL5

//+--------------------------------------------------------------------+
//|                                              Parabolic SAR EA.mql5 |
//|                                 Copyright 2025, Christian Benjamin |
//|                                               https://www.mql5.com |
//+--------------------------------------------------------------------+

#property copyright "2025, Christian Benjamin"
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.2"
#property strict

// Input parameters for the Parabolic SAR indicator
input double SARStep    = 0.1;  // Acceleration factor for PSAR
input double SARMaximum = 1;   // Maximum acceleration for PSAR

// Input parameters for refining the signal based on PSAR dots
input int    MinConsecutiveDots = 2;         // Require at least 2 consecutive bars in one trend before reversal
input double MaxDotGapPercentage  = 1.0;     // Maximum allowed gap between consecutive PSAR dots (% of current close)

// Input parameters for alerts and arrow drawing
input bool   EnableAlerts  = true;            // Enable popup alerts
input bool   EnableSound   = true;            // Enable sound alerts
input bool   EnableArrows  = true;            // Draw arrows on chart
input string BuyArrowSymbol  = "233";         // Wingdings up arrow (as string)
input string SellArrowSymbol = "234";         // Wingdings down arrow (as string)
input int    ArrowWidth    = 2;               // Arrow thickness
input double ArrowOffsetMultiplier = 5;       // Multiplier for arrow placement offset

// Global indicator handle for PSAR
int sarHandle = INVALID_HANDLE;

// Global variable to track last processed bar time
datetime lastBarTime = 0;

// Enumeration for signal types
enum SignalType
  {
   NO_SIGNAL,
   BUY_SIGNAL,
   SELL_SIGNAL
  };

// Global variables for pending signal mechanism
SignalType pendingSignal = NO_SIGNAL;
int        waitCount     = 0;        // Counts new closed bars since signal detection
double     pendingReversalLevel = 0.0; // Stores the PSAR value at signal detection

//+------------------------------------------------------------------+
//| DrawSignalArrow - Draws an arrow object on the chart             |
//+------------------------------------------------------------------+
void DrawSignalArrow(string prefix, datetime barTime, double price, color arrowColor, long arrowCode)
  {
   string arrowName = prefix + "_" + TimeToString(barTime, TIME_SECONDS);
// Remove existing object with the same name to prevent duplicates
   if(ObjectFind(0, arrowName) != -1)
      ObjectDelete(0, arrowName);

   if(ObjectCreate(0, arrowName, OBJ_ARROW, 0, barTime, price))
     {
      ObjectSetInteger(0, arrowName, OBJPROP_COLOR, arrowColor);
      ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, arrowCode);
      ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, ArrowWidth);
     }
   else
     {
      Print("Failed to create arrow object: ", arrowName);
     }
  }

//+-------------------------------------------------------------------+
//| CheckForSignal - Evaluates PSAR and price data to determine signal|
//+-------------------------------------------------------------------+
SignalType CheckForSignal(const double &sarArray[], const double &openArray[], const double &closeArray[])
  {
// Mapping indices:
// Index 0: Last closed bar (current candidate)
// Index 1: Previous bar
// Index 2: Bar before previous

   double sar0 = sarArray[0], sar1 = sarArray[1], sar2 = sarArray[2];
   double open0 = openArray[0], close0 = closeArray[0];
   double open1 = openArray[1], close1 = closeArray[1];
   double open2 = openArray[2], close2 = closeArray[2];

// Check for BUY signal:
   if((close0 > open0) && (sar0 < close0) &&
      (sar1 > close1) && (sar2 > close2))
     {
      int countBearish = 0;
      if(sar1 > close1)
         countBearish++;
      if(sar2 > close2)
         countBearish++;
      double dotGap = MathAbs(sar1 - sar2);
      double gapThreshold = (MaxDotGapPercentage / 100.0) * close0;
      if(countBearish >= MinConsecutiveDots && dotGap <= gapThreshold)
         return BUY_SIGNAL;
     }

// Check for SELL signal:
   if((close0 < open0) && (sar0 > close0) &&
      (sar1 < close1) && (sar2 < close2))
     {
      int countBullish = 0;
      if(sar1 < close1)
         countBullish++;
      if(sar2 < close2)
         countBullish++;
      double dotGap = MathAbs(sar1 - sar2);
      double gapThreshold = (MaxDotGapPercentage / 100.0) * close0;
      if(countBullish >= MinConsecutiveDots && dotGap <= gapThreshold)
         return SELL_SIGNAL;
     }

   return NO_SIGNAL;
  }

//+------------------------------------------------------------------+
//| IsNewBar - Determines if a new closed bar is available           |
//+------------------------------------------------------------------+
bool IsNewBar()
  {
   datetime times[];
   if(CopyTime(_Symbol, _Period, 1, 1, times) <= 0)
     {
      Print("Failed to retrieve bar time in IsNewBar().");
      return false;
     }
   if(times[0] != lastBarTime)
     {
      lastBarTime = times[0];
      return true;
     }
   return false;
  }

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
// Create the built-in Parabolic SAR indicator handle
   sarHandle = iSAR(_Symbol, _Period, SARStep, SARMaximum);
   if(sarHandle == INVALID_HANDLE)
     {
      Print("Error creating PSAR handle");
      return INIT_FAILED;
     }
   Print("SAR EA initialized successfully.");
   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   if(sarHandle != INVALID_HANDLE)
      IndicatorRelease(sarHandle);

// Remove all arrow objects from the current chart window
   ObjectsDeleteAll(0, (int)OBJ_ARROW, 0);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
// Process only once per new closed bar
   if(!IsNewBar())
      return;

// Retrieve the last 4 PSAR values (we require at least 3 values)
   double sarArray[4];
   if(CopyBuffer(sarHandle, 0, 1, 4, sarArray) < 3)
     {
      Print("Failed to retrieve PSAR data.");
      return;
     }

// Retrieve the last 4 bars' price data (Open and Close)
   double openArray[4], closeArray[4];
   if(CopyOpen(_Symbol, _Period, 1, 4, openArray) < 3 ||
      CopyClose(_Symbol, _Period, 1, 4, closeArray) < 3)
     {
      Print("Failed to retrieve price data.");
      return;
     }

// Process pending signal logic if a signal is waiting confirmation
   if(pendingSignal != NO_SIGNAL)
     {
      waitCount++; // Increment the waiting counter

      if(pendingSignal == BUY_SIGNAL)
        {
         if(closeArray[0] <= pendingReversalLevel)
           {
            Print("Reversal level reached for BUY signal. Close here.");
            if(EnableAlerts)
               Alert("Close here for BUY signal on ", _Symbol, " at price ", DoubleToString(closeArray[0], _Digits));
            if(EnableSound)
               PlaySound("alert.wav");
            pendingSignal = NO_SIGNAL;
            waitCount = 0;
           }
         else
            if(waitCount >= 3)
              {
               Print("Warning: Possible fake BUY signal - reversal not confirmed in 3 candles.");
               if(EnableAlerts)
                  Alert("Warning: Possible fake BUY signal on ", _Symbol);
               pendingSignal = NO_SIGNAL;
               waitCount = 0;
              }
        }
      else
         if(pendingSignal == SELL_SIGNAL)
           {
            if(closeArray[0] >= pendingReversalLevel)
              {
               Print("Reversal level reached for SELL signal. Close here.");
               if(EnableAlerts)
                  Alert("Close here for SELL signal on ", _Symbol, " at price ", DoubleToString(closeArray[0], _Digits));
               if(EnableSound)
                  PlaySound("alert.wav");
               pendingSignal = NO_SIGNAL;
               waitCount = 0;
              }
            else
               if(waitCount >= 3)
                 {
                  Print("Warning: Possible fake SELL signal - reversal not confirmed in 3 candles.");
                  if(EnableAlerts)
                     Alert("Warning: Possible fake SELL signal on ", _Symbol);
                  pendingSignal = NO_SIGNAL;
                  waitCount = 0;
                 }
           }
      return;
     }

// Check for a new reversal signal
   SignalType newSignal = CheckForSignal(sarArray, openArray, closeArray);
   if(newSignal != NO_SIGNAL)
     {
      pendingSignal = newSignal;
      waitCount = 0; // Reset waiting counter
      pendingReversalLevel = sarArray[0]; // Set reversal level from current PSAR value

      if(newSignal == BUY_SIGNAL)
        {
         Print("Buy signal detected on ", TimeToString(lastBarTime, TIME_DATE|TIME_SECONDS),
               ". Waiting for reversal confirmation (up to 3 candles).");
         if(EnableAlerts)
            Alert("Buy signal detected on ", _Symbol, " at price ", DoubleToString(closeArray[0], _Digits));
         if(EnableArrows)
           {
            double lowVal[];
            if(CopyLow(_Symbol, _Period, 1, 1, lowVal) > 0)
              {
               double offset = _Point * ArrowOffsetMultiplier;
               DrawSignalArrow("BuyArrow", lastBarTime, lowVal[0] - offset, clrGreen, StringToInteger(BuyArrowSymbol));
              }
            else
               Print("Failed to retrieve low price for arrow placement.");
           }
        }
      else
         if(newSignal == SELL_SIGNAL)
           {
            Print("Sell signal detected on ", TimeToString(lastBarTime, TIME_DATE|TIME_SECONDS),
                  ". Waiting for reversal confirmation (up to 3 candles).");
            if(EnableAlerts)
               Alert("Sell signal detected on ", _Symbol, " at price ", DoubleToString(closeArray[0], _Digits));
            if(EnableArrows)
              {
               double highVal[];
               if(CopyHigh(_Symbol, _Period, 1, 1, highVal) > 0)
                 {
                  double offset = _Point * ArrowOffsetMultiplier;
                  DrawSignalArrow("SellArrow", lastBarTime, highVal[0] + offset, clrRed, StringToInteger(SellArrowSymbol));
                 }
               else
                  Print("Failed to retrieve high price for arrow placement.");
              }
           }
     }
  }
//+------------------------------------------------------------------+


Testes e Resultados

Antes de migrar para negociação ao vivo, recomendo realizar backtesting em uma conta demo. Veja como você pode ajustar seu EA com base nos resultados dos testes:
  • Após compilar com sucesso seu EA no MetaEditor, abra o MetaTrader.
  • No MetaTrader, navegue até o Strategy Tester. Selecione o EA que deseja testar, depois escolha o timeframe desejado, o período de teste e quaisquer outros parâmetros relevantes.
  • Após configurar suas definições, clique em ‘Start’ para iniciar o backtest.

Inicializando o Tester

Fig 4. Inicializando o Tester

Abaixo, forneci imagens e vários GIFs capturados durante minhas sessões de backtesting. A primeira imagem é um diagrama do índice Volatility 25, destacando onde sinais de venda e compra foram confirmados durante o teste. Em seguida, há vários GIFs para visualização adicional, que podem ajudá-lo a compreender melhor o desempenho do EA.

Compra e Venda

Fig 5. Backtesting no Índice Volatility 25

Backtesting no Índice Volatility 25 GIF.

Teste no Índice Volatility 25

Fig 6: Backtesting no Índice Volatility 25 

Backtesting no Step Index.

Backtesting Step Index

Fig 7: Backtesting no Step Index

Negociação ao vivo no Step Index.

Índice Step

Fig 8: Negociação ao Vivo



Conclusão

Desenvolvemos e testamos o EA, alcançando resultados positivos. No entanto, alguns sinais podem exigir filtragem adicional. Lembre-se de que este EA foi projetado para complementar suas próprias estratégias de negociação, e não para substituí-las. Sempre verifique todas as condições relevantes antes de executar quaisquer negociações com base em seus sinais. Além disso, trabalhar com timeframes maiores pode ser crucial para minimizar sinais falsos.

Data Nome da Ferramenta  Descrição Versão  Atualizações  Notas
01/10/24 Projetor de Gráficos Script para sobrepor a ação do preço do dia anterior com efeito fantasma. 1.0 Lançamento Inicial Ferramenta número 1
18/11/24 Comentário Analítico Ele fornece informações do dia anterior em formato tabular, além de antecipar a direção futura do mercado. 1.0 Lançamento Inicial Ferramenta número 2
27/11/24 Mestre em Análise Atualização regular das métricas de mercado a cada duas horas  1.01 Segundo Lançamento Ferramenta número 3
02/12/24 Previsor Analítico  Atualização regular das métricas de mercado a cada duas horas com integração ao Telegram 1.1 Terceira Edição Ferramenta número 4
09/12/24 Navegador de Volatilidade O EA analisa as condições de mercado usando os indicadores Bandas de Bollinger, RSI e ATR 1.0 Lançamento Inicial Ferramenta número 5
19/12/24 Reversão à Média Ceifador de Sinal  Analisa o mercado usando a estratégia de reversão à média e fornece sinais  1.0  Lançamento Inicial  Ferramenta número 6 
9/01/25  Pulso de sinal  Analisador de múltiplos períodos de tempo 1.0  Lançamento Inicial  Ferramenta número 7 
17/01/25  Quadro de Métricas  Painel com botão para análise  1.0  Lançamento Inicial Ferramenta número 8 
21/01/25 Fluxo externo Análises por meio de bibliotecas externas 1.0  Lançamento Inicial Ferramenta número 9 
27/01/25 VWAP Preço médio ponderado por volume   1.3  Lançamento Inicial  Ferramenta número 10 
02/02/25  Heikin Ashi  Suavização de Tendência e identificação de sinais de reversão  1.0  Lançamento Inicial  Ferramenta número 11
04/02/25  FibVWAP  Geração de sinais por meio de análise em Python  1.0  Lançamento Inicial  Ferramenta número 12
14/02/25  DIVERGÊNCIA RSI  Divergências entre ação do preço e RSI  1.0  Lançamento Inicial  Ferramenta número 13 
17/02/2025  Parabolic Stop and Reverse (PSAR)  Automatizando a estratégia PSAR 1.0 Lançamento Inicial  Ferramenta número 14

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

Arquivos anexados |
Parabolic_SAR.mq5 (12.72 KB)
Construindo Expert Advisors Auto Otimizáveis em MQL5 (Parte 6): Prevenção de Stop Out Construindo Expert Advisors Auto Otimizáveis em MQL5 (Parte 6): Prevenção de Stop Out
Junte-se a nós na discussão de hoje enquanto buscamos um procedimento algorítmico para minimizar o número total de vezes em que somos estopados em negociações vencedoras. O problema que enfrentamos é significativamente desafiador, e a maioria das soluções apresentadas em discussões da comunidade carece de regras fixas e bem definidas. Nossa abordagem algorítmica para resolver o problema aumentou a lucratividade de nossas negociações e reduziu nossa perda média por operação. No entanto, ainda há avanços a serem feitos para filtrar completamente todas as negociações que serão estopadas; nossa solução é um bom primeiro passo para qualquer pessoa experimentar.
Algoritmo de ecolocalização de golfinhos — Dolphin Echolocation Algorithm (DEA) Algoritmo de ecolocalização de golfinhos — Dolphin Echolocation Algorithm (DEA)
Neste artigo, analisaremos detalhadamente o algoritmo DEA, um método metaheurístico de otimização inspirado na capacidade única dos golfinhos de encontrar presas por meio da ecolocalização. Das bases matemáticas à implementação prática em MQL5, da análise à comparação com algoritmos clássicos, vamos examinar minuciosamente por que esse método relativamente jovem merece um lugar no arsenal de quem enfrenta tarefas de otimização.
Automatizando Estratégias de Trading em MQL5 (Parte 8): Construindo um Expert Advisor com Padrões Harmônicos Butterfly Automatizando Estratégias de Trading em MQL5 (Parte 8): Construindo um Expert Advisor com Padrões Harmônicos Butterfly
Neste artigo, construímos um Expert Advisor em MQL5 para detectar padrões harmônicos Butterfly. Identificamos pontos de pivô e validamos níveis de Fibonacci para confirmar o padrão. Em seguida, visualizamos o padrão no gráfico e executamos negociações automaticamente quando confirmado.
Aplicação do modelo Grey na análise técnica de séries temporais financeiras Aplicação do modelo Grey na análise técnica de séries temporais financeiras
Este artigo é dedicado ao estudo do modelo Grey, uma ferramenta promissora, capaz de ampliar as possibilidades do trader. Vamos considerar algumas formas de aplicar esse modelo na análise técnica e na construção de estratégias de negociação.