English Русский 中文 Español Deutsch 日本語
preview
Construindo um Modelo de Restrição de Tendência com Candlestick (Parte 10): Golden Cross e Death Cross Estratégicos (EA)

Construindo um Modelo de Restrição de Tendência com Candlestick (Parte 10): Golden Cross e Death Cross Estratégicos (EA)

MetaTrader 5Exemplos |
84 1
Clemence Benjamin
Clemence Benjamin

Introdução

Neste artigo, exploramos a integração das estratégias Golden Cross e Death Cross Estratégicas no Expert Advisor de Restrição de Tendência, desbloqueando o potencial dessas técnicas de cruzamento de médias móveis comprovadas ao longo do tempo. Nosso objetivo é aprimorar as capacidades de acompanhamento de tendência no trading algorítmico, automatizando essas estratégias, garantindo precisão, consistência e compatibilidade perfeita com sistemas de trading mais amplos.

Muitos traders enfrentam desafios para identificar e aproveitar efetivamente tendências fortes de alta e baixa. Enquanto o Golden Cross, sinalizando impulso de alta, e o Death Cross, indicando sentimento de baixa, demonstraram seu valor no trading manual, sua falta de automação frequentemente resulta em oportunidades perdidas e execução inconsistente.

Ao incorporar as estratégias Golden e Death Cross em um Expert Advisor automatizado, os traders podem executar sinais de reversão sistematicamente sem as limitações impostas a outras estratégias de acompanhamento de tendência. Ao contrário de estratégias restritas que dependem do sentimento diário do mercado, essas estratégias de cruzamento operam de forma independente para identificar e agir sobre reversões à medida que ocorrem. Isso garante que potenciais pontos de virada sejam capturados mais cedo, aumentando a capacidade de resposta e o desempenho geral do trading, ao mesmo tempo em que mantém o alinhamento com estratégias de tendência mais amplas.

Conteúdo principal:

  1. Entendendo a estratégia Golden e Death Cross
  2. Analisando sua relevância dentro do contexto mais amplo de acompanhamento de tendência
  3. Adaptação às Condições de Restrição de Tendência
  4. Implementação da estratégia usando MQL5
  5. Teste Inicial da Estratégia
  6. Mesclando a nova estratégia na Restrição de Tendência
  7. Resultados de Teste e Otimização
  8. Conclusão


Entendendo a estratégia Golden e Death Cross

A estratégia Golden Cross e Death Cross é um conceito fundamental na análise técnica usada para sinalizar potenciais tendências de alta ou de baixa no mercado com base em cruzamentos de médias móveis. Um Golden Cross ocorre quando uma média móvel de curto prazo, normalmente a média móvel de 50 dias, cruza acima de uma média móvel de longo prazo, frequentemente a média móvel de 200 dias. Esse evento é considerado um forte sinal de alta, sugerindo que uma tendência de alta de longo prazo pode estar começando. Investidores e traders podem ver isso como uma oportunidade de comprar ou manter ações, antecipando um aumento no preço. 

Por outro lado, o Death Cross é o cenário oposto, em que a média móvel de curto prazo cai abaixo da média móvel de longo prazo, sinalizando uma potencial tendência de baixa. Isso é visto como um aviso de que o mercado pode entrar em um declínio prolongado. O Death Cross pode levar investidores a vender ou operar vendido, ou pelo menos a agir com cautela, pois indica o enfraquecimento das condições de mercado. Ambos os sinais não são usados apenas para decisões diretas de negociação, mas também para uma análise mais ampla do sentimento do mercado, embora não sejam infalíveis e devam ser utilizados com outros indicadores ou formas de análise para confirmar tendências.


Analisando sua relevância dentro do contexto mais amplo de acompanhamento de tendência

No contexto mais amplo de estratégias seguidoras de tendência, o Golden Cross e o Death Cross servem como ferramentas fundamentais para identificar o início e a potencial reversão de tendências de mercado. Trend-following é uma estratégia onde os traders buscam lucrar com movimentos sustentados nos preços de mercado, alinhando suas operações com a direção da tendência estabelecida. Aqui está como o Golden e o Death Cross se encaixam nessa abordagem:

1. Identificação de Tendência: A função principal desses cruzamentos é fornecer sinais claros para o início de novas tendências. O Golden Cross sinaliza o início de uma tendência de alta, incentivando seguidores de tendência a entrarem em posições compradas ou aumentarem sua exposição. Por outro lado, o Death Cross indica o início de uma tendência de baixa, sugerindo que é hora de sair de posições compradas ou considerar vendas a descoberto.
2. Confirmação de Tendências: Esses sinais atuam como confirmações dentro de estratégias seguidoras de tendência. Um seguidor de tendência pode usar esses cruzamentos juntamente com outros indicadores como ação de preço, volume ou indicadores de momento para verificar se uma tendência está realmente se desenvolvendo. Essa abordagem com múltiplos indicadores ajuda a reduzir falsos sinais, o que é crucial em trend-following, onde o objetivo é acompanhar a tendência pelo maior tempo possível.
3. Gestão de Risco: Em acompanhamento de tendência, gerenciar risco é essencial, já que tendências podem reverter ou pausar inesperadamente. O Golden e o Death Cross podem ser usados para definir níveis de stop-loss ou para decidir quando reduzir ou aumentar tamanhos de posição. Por exemplo, uma quebra abaixo das médias móveis após um Golden Cross pode sugerir o aperto de stops ou redução de exposição.
4. Perspectiva de Longo Prazo: Esses sinais são inerentemente de longo prazo devido ao uso de períodos mais longos de médias móveis, alinhando-se bem com a filosofia do trend-following de capturar grandes movimentos de mercado em vez de flutuações de curto prazo. Esse foco de longo prazo ajuda a filtrar ruídos do mercado e a concentrar-se em movimentos significativos de preço.
5. Adaptabilidade: Embora tradicionalmente configuradas com médias móveis de 50 e 200 dias, a estratégia pode ser adaptada para diferentes períodos ou condições de mercado. Em mercados de rápida movimentação, traders podem usar períodos menores para sinais mais rápidos, enquanto em mercados mais estáveis, períodos maiores podem ser preferidos para evitar ser enganado por pequenas correções.

No entanto, a relevância do Golden e do Death Cross dentro do trend-following pode ser analisada criticamente da seguinte forma:

  • Atraso: Uma das principais críticas é o atraso associado às médias móveis. Quando esses cruzamentos ocorrem, partes significativas da tendência podem já ter ocorrido, potencialmente reduzindo a lucratividade de operações baseadas apenas nesses sinais.
  • Sinais Falsos: O trend-following carrega inerentemente o risco de falsos rompimentos ou reversões prematuras de tendência. O Golden e o Death Cross não estão imunes a isso e, portanto, devem fazer parte de uma estratégia mais ampla que inclua outras formas de análise ou sinais de confirmação.
  • Ambiente de Mercado: Sua eficácia pode variar significativamente com as condições de mercado. Em mercados com tendência definida, esses sinais podem ser altamente eficazes, mas em mercados laterais ou voláteis podem gerar inúmeros falsos começos


Adaptação às Condições de Restrição de Tendência

Em estratégias de longo prazo, impor restrições excessivas pode limitar seu potencial. Por exemplo, considere um cenário onde o sentimento diário do mercado é de baixa. Um sinal de golden cross aparecendo em timeframes menores dentro do mesmo dia pode indicar uma possível reversão, sugerindo que o mercado pode se tornar altista. Quando essas reversões ocorrem, outras estratégias restritas frequentemente se adaptam ao sentimento de tendência emergente, alinhando-se à nova direção do mercado.

Para aproveitar essa dinâmica, as estratégias death cross e golden cross podem ser incorporadas ao EA Trend Constraint como módulos independentes. Ao fazer isso, o EA pode maximizar seu desempenho capturando entradas de reversão que se alinham com a tendência recém-emergente.

Essa abordagem garante:

  1. Flexibilidade entre Timeframes: O EA pode detectar reversões de curto prazo (por exemplo, golden crosses) e alinhá-las com movimentos mais amplos do mercado, aumentando a adaptabilidade.
  2. Melhores Pontos de Entrada: Identificar mudanças no sentimento da tendência cedo permite ao EA assumir posições estratégicas, minimizando o atraso na resposta às mudanças do mercado.
  3. Sinergia entre Estratégias: Integrar as estratégias golden e death cross de forma independente permite ao EA aproveitar seus pontos fortes sem substituir os mecanismos principais de acompanhamento de tendência

Ao adotar essa abordagem de duas camadas, o EA Trend Constraint ganha a capacidade de navegar reversões de mercado de forma eficaz enquanto mantém a lucratividade de longo prazo. Agora vamos prosseguir para a próxima etapa, onde implementaremos e integraremos essa estratégia.


Implementação da estratégia usando MQL5

Na minha abordagem de desenvolvimento, ao criar um EA com múltiplas estratégias, sempre projeto cada estratégia como um EA independente primeiro. Isso permite testes focados e refinamento antes de mesclar tudo em uma única base de código unificada. Seguindo esse método, primeiro iremos decompor e desenvolver o EA Estratégico Golden e Death Cross de forma independente antes de integrá-lo ao Expert Advisor principal.

Como de costume, abra o aplicativo MetaEditor 5 em sua área de trabalho ou pressione F4 no seu terminal MetaTrader 5 para iniciá-lo diretamente. Siga as etapas de desenvolvimento descritas abaixo. Para iniciantes, é recomendado digitar o código manualmente em vez de copiar e colar, pois isso ajuda a reforçar a habilidade e aprofundar o entendimento.

Começaremos com nosso Golden e Death Cross aqui:

Cabeçalho e Metadados:

Esta é a parte superior do programa; começamos definindo os metadados para garantir clareza e profissionalismo. Os metadados identificam o programa como o EA Estratégico Golden & Death Cross, incluindo detalhes de direitos autorais, uma descrição e o número da versão. Essa etapa nos ajuda a organizar o projeto e garante que nosso trabalho seja devidamente atribuído quando implantado no MetaTrader 5. Ao configurar os metadados dessa forma, estabelecemos uma base profissional e bem documentada para nosso EA.

//+------------------------------------------------------------------+ 
//|                       Strategic Golden & Death Cross EA.mq5      |
//|                           Copyright 2024, Clemence Benjamin      |
//|        https://www.mql5.com/en/users/billionaire2024/seller      |
//+------------------------------------------------------------------+
#property copyright "Clemence Benjamin"
#property description "GOLDEN AND DEATH CROSS"
#property version "1.0"

Includes e Inicialização do Objeto de Trade:

Para simplificar a execução de operações, incluímos a biblioteca de trade do MQL5 com #include<Trade\Trade.mqh>. Essa biblioteca fornece acesso a funções de negociação poderosas. Instanciamos a classe CTrade como trade, permitindo que o EA execute operações como comprar, vender e fechar posições sem implementar manualmente essas rotinas. Isso reduz a complexidade e torna o código mais confiável. Com essa configuração, podemos focar na estratégia e confiar na biblioteca de gerenciamento de operações para executar nossas ordens.

#include<Trade\Trade.mqh>;
CTrade trade;

Parâmetros de Entrada:

Começamos definindo parâmetros ajustáveis pelo usuário para tornar o EA flexível e personalizável.

Por exemplo:

  • LotSize permite controlar o volume das operações.
  • Slippage especifica desvios de preço aceitáveis durante a execução.
  • FastEMAPeriod e SlowEMAPeriod definem os períodos das médias móveis que formam a base da estratégia Golden e Death Cross.
input double LotSize = 1.0;            // Trade volume (lots)
input int Slippage = 20;               // Slippage in points
input int TimerInterval = 10000;       // Timer interval in seconds
input double TakeProfitPips = 100;     // Take Profit in pips
input double StopLossPips = 50;        // Stop Loss in pips
input int FastEMAPeriod = 50;          // Fast EMA period (default 50)
input int SlowEMAPeriod = 200;         // Slow EMA period (default 200)

Definindo esses parâmetros, permitimos que os usuários ajustem o EA conforme suas condições específicas de negociação.

Inicialização e Configuração do Timer:

Vamos garantir que o EA inicialize corretamente. Na função OnInit(), adicionamos uma verificação para confirmar se há barras suficientes para calcular a EMA lenta. Se não houver, o EA registra um erro e interrompe a execução. Isso garante que a estratégia rode apenas quando houver dados suficientes disponíveis.

int OnInit()
{
   //--- create timer
   EventSetTimer(TimerInterval);

   //--- Check if there are enough bars for EMA calculation
   if(Bars(_Symbol,PERIOD_CURRENT)<SlowEMAPeriod)
   {
      Print("Not enough bars for EMA calculation");
      return(INIT_FAILED);
   }
   return(INIT_SUCCEEDED);
}

Além disso, usamos EventSetTimer() para chamar a função OnTimer() periodicamente, executando a lógica de negociação. A função OnDeinit() garante que o timer seja desativado quando o EA for removido, liberando recursos.

void OnDeinit(const int reason)
{
   //--- delete timer
   EventKillTimer();
}

Lógica de Negociação em OnTimer():

Agora vamos ao núcleo da estratégia dentro da função OnTimer():

Cálculo das EMAs:

Começamos criando os handles para as EMAs rápida e lenta usando iMA() e recuperando seus valores com CopyBuffer(). Essas EMAs são essenciais para detectar sinais de entrada.

int fastEMAHandle = iMA(_Symbol, PERIOD_CURRENT, FastEMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
int slowEMAHandle = iMA(_Symbol, PERIOD_CURRENT, SlowEMAPeriod, 0, MODE_EMA, PRICE_CLOSE);

double fastEMAArray[], slowEMAArray[];
CopyBuffer(fastEMAHandle, 0, 0, 2, fastEMAArray);
CopyBuffer(slowEMAHandle, 0, 0, 2, slowEMAArray);

Coleta de Dados de Mercado:

Em seguida, recuperamos dados importantes do mercado, como ask, bid e o valor do point, para garantir cálculos precisos de stop-loss e take-profit.

double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

Sinais de Entrada:

Aqui definimos as condições para abrir operações de compra e venda. Um Golden Cross (EMA rápida cruzando acima da lenta) sinaliza compra, enquanto um Death Cross (EMA rápida cruzando abaixo da lenta) sinaliza venda.

if(fastEMAArray[0] > slowEMAArray[0] && fastEMAArray[1] <= slowEMAArray[1]) // Death Cross 
{
   double sl = NormalizeDouble(ask + StopLossPips * point, _Digits);
   trade.Sell(LotSize, _Symbol, ask, sl);
}
else if(fastEMAArray[0] < slowEMAArray[0] && fastEMAArray[1] >= slowEMAArray[1]) // Golden Cross
{
   double sl = NormalizeDouble(bid - StopLossPips * point, _Digits);
   trade.Buy(LotSize, _Symbol, bid, sl);
}

Sinais de Saída:

Vamos garantir que posições existentes sejam fechadas quando o sinal oposto aparecer aqui. Isso mantém a estratégia alinhada com as mudanças das condições de mercado.

if((PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && fastEMAArray[0] < slowEMAArray[0]) ||
   (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && fastEMAArray[0] > slowEMAArray[0]))
{
   trade.PositionClose(PositionGetInteger(POSITION_TICKET));
}

Tratamento de Erros:

Agora adicionamos rotinas de tratamento de erros para registrar qualquer problema com execução de ordens ou fechamento de posições, o que ajuda na depuração e garante um desempenho fluido.

if(!trade.Sell(LotSize, _Symbol, ask, sl))
{
   Print("Sell order error: ", GetLastError());
}

Aqui está nosso código completo:

//+------------------------------------------------------------------+ 
//|                          Golden & Death Cross Strategy.mq5       |
//|                           Copyright 2024, Clemence Benjamin      |
//|        https://www.mql5.com/en/users/billionaire2024/seller      |
//+------------------------------------------------------------------+

#property copyright "Clemence Benjamin"
#property description "GOLDEN AND DEATH CROSS"
#property version "1.0"


//+------------------------------------------------------------------+
//| Includes                                                         |
//+------------------------------------------------------------------+
#include<Trade\Trade.mqh>;
CTrade trade;

//+------------------------------------------------------------------+
//| Input parameters                                                 |
//+------------------------------------------------------------------+
input double LotSize = 1.0;            // Trade volume (lots)
input int Slippage = 20;               // Slippage in points
input int TimerInterval = 1000;          // Timer interval in seconds
input double StopLossPips = 1500;        // Stop Loss in pips
input int FastEMAPeriod = 50;          // Fast EMA period (default 50)
input int SlowEMAPeriod = 200;         // Slow EMA period (default 200)

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- create timer
   EventSetTimer(TimerInterval);
   
   //--- Check if there are enough bars to calculate the EMA
   if(Bars(_Symbol,PERIOD_CURRENT)<SlowEMAPeriod)
     {
      Print("Not enough bars for EMA calculation");
      return(INIT_FAILED);
     }
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   //--- delete timer
   EventKillTimer();
  }
//+------------------------------------------------------------------+
//| Expert timer function                                            |
//+------------------------------------------------------------------+
void OnTimer()
{
   bool hasPosition = PositionSelect(_Symbol);
   
   int fastEMAHandle = iMA(_Symbol, PERIOD_CURRENT, FastEMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   int slowEMAHandle = iMA(_Symbol, PERIOD_CURRENT, SlowEMAPeriod, 0, MODE_EMA, PRICE_CLOSE);

   if(fastEMAHandle < 0 || slowEMAHandle < 0)
   {
      Print("Failed to create EMA handles. Error: ", GetLastError());
      return;
   }

   double fastEMAArray[], slowEMAArray[];
   if(CopyBuffer(fastEMAHandle, 0, 0, 2, fastEMAArray) <= 0 ||
      CopyBuffer(slowEMAHandle, 0, 0, 2, slowEMAArray) <= 0)
   {
      Print("Failed to copy EMA data. Error: ", GetLastError());
      return;
   }

   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

   if(!hasPosition)
   {
      if(fastEMAArray[0] > slowEMAArray[0] && fastEMAArray[1] <= slowEMAArray[1]) // Death Cross 
      {
         
         double sl = NormalizeDouble(ask + StopLossPips * point, _Digits);
         if(!trade.Sell(LotSize, _Symbol, ask, sl ))
            Print("Buy order error ", GetLastError());
         else
            Print("Buy order opened with TP ", " and SL ", StopLossPips, " pips");
      }
      else if(fastEMAArray[0] < slowEMAArray[0] && fastEMAArray[1] >= slowEMAArray[1]) // Golden Cross
      {
         
         double sl = NormalizeDouble(bid - StopLossPips * point, _Digits);
         if(!trade.Buy(LotSize, _Symbol, bid, sl ))
            Print("Sell order error ", GetLastError());
         else
            Print("Sell order opened with TP ",  " and SL ", StopLossPips, " pips");
      }
   }
   else
   {
     if((PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && fastEMAArray[0] < slowEMAArray[0]) ||
         (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && fastEMAArray[0] > slowEMAArray[0]))
    {
         ulong ticket = PositionGetInteger(POSITION_TICKET);
         if(!trade.PositionClose(ticket))
            Print("Failed to close position (Ticket: ", ticket, "). Error: ", GetLastError());
         else  
            Print("Position closed : ", ticket);
      }
   }
}

//+------------------------------------------------------------------+


Teste Inicial da Estratégia

Após compilar o código com sucesso, estamos agora prontos para testar o desempenho da estratégia usando o Strategy Tester. Abaixo estão imagens dos resultados do teste antes de integrarmos a estratégia no Expert Advisor de Restrição de Tendência.

strategy tester settings.PNG

Configurações do Strategy Tester: Boom 500 Index

Configurações de Entrada

Configurações de Entrada: Boom 500 Index

Boom 500 Index M5: Testando Estratégia Golden & Death Cross

A partir do teste inicial, a lógica de execução de ordens está funcionando bem, mas há necessidade de melhorar a estratégia de saída. Com observação manual no testador de estratégia, notei muitas posições que poderiam ter garantido lucro, mas acabaram sendo fechadas com pequenos ganhos ou até prejuízos. Isso ocorreu porque reversões apresentaram cruzamentos após rebaixamentos significativos, limitando os lucros. Durante consolidação de mercado, muitos cruzamentos falsos resultaram em perdas. Para evitar tais rebaixamentos expressivos, a estratégia de saída precisa ser aprimorada.


Mesclando a nova estratégia na Restrição de Tendência

Finalmente, alcançamos o objetivo de criar um Expert Advisor de Múltiplas Estratégias ao integrar a estratégia que desenvolvemos anteriormente. Para relembrar as estratégias existentes, você pode revisitar (Part 9). Aqui está uma lista das estratégias que já foram integradas:

  • Trend Following
  • Rompimento do Canal de Donchian
  • Estratégia de Divergência

Hoje, estamos adicionando a quarta estratégia, que, como expliquei anteriormente, funciona de forma independente e é livre de condições de restrição, permitindo capturar todas as oportunidades de reversão. Para isso, modificaremos o Expert Advisor Trend Constraint atual, adicionando um interruptor Booleano para a nova estratégia Golden e Death Cross. Além disso, refatoraremos outras seções do código em funções relevantes do código principal.

Para evitar conflitos com outros termos já presentes no programa principal, adicionamos um prefixo exclusivo às variáveis associadas à estratégia Golden e Death Cross. Por exemplo, renomeamos LotSize para GDC_LotSize = 1.0; para garantir clareza e evitar confusão.

Abaixo está o código completo, livre de erros. As novas adições e modificações estão claramente destacadas para melhor compreensão e clareza.

//+------------------------------------------------------------------+
//|                                      Trend Constraint Expert.mq5 |
//|                                Copyright 2024, Clemence Benjamin |
//|             https://www.mql5.com/en/users/billionaire2024/seller |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, Clemence Benjamini"
#property link      "https://www.mql5.com/en/users/billionaire2024/seller"
#property version   "1.03"

#include <Trade\Trade.mqh>
CTrade trade;

// Input parameters for controlling strategies
input bool UseTrendFollowingStrategy = false;   // Enable/Disable Trend Following Strategy
input bool UseBreakoutStrategy = false;         // Enable/Disable Breakout Strategy
input bool UseDivergenceStrategy = false;       // Enable/Disable Divergence Strategy
input bool UseGoldenDeathCrossStrategy = true;  // Enable/Disable Golden/Death Cross Strategy

// Input parameters for Golden/Death Cross Strategy
input double GDC_LotSize = 1.0;            // Trade volume (lots) for Golden Death Cross
input int GDC_Slippage = 20;               // Slippage in points for Golden Death Cross
input int GDC_TimerInterval = 1000;        // Timer interval in seconds for Golden Death Cross
input double GDC_StopLossPips = 1500;      // Stop Loss in pips for Golden Death Cross
input int GDC_FastEMAPeriod = 50;          // Fast EMA period for Golden Death Cross
input int GDC_SlowEMAPeriod = 200;         // Slow EMA period for Golden Death Cross

int GDC_fastEMAHandle, GDC_slowEMAHandle;  // Handles for EMA indicators in Golden Death Cross

// Global variables
double prevShortMA, prevLongMA;

// Input parameters for Trend Constraint Strategy
input int    RSI_Period = 14;            // RSI period
input double RSI_Overbought = 70.0;     // RSI overbought level
input double RSI_Oversold = 30.0;       // RSI oversold level
input double Lots = 0.1;                // Lot size
input double StopLoss = 100;            // Stop Loss in points
input double TakeProfit = 200;          // Take Profit in points
input double TrailingStop = 50;         // Trailing Stop in points
input int    MagicNumber = 12345678;    // Magic number for the Trend Constraint EA
input int    OrderLifetime = 43200;     // Order lifetime in seconds (12 hours)

// Input parameters for Breakout Strategy
input int InpDonchianPeriod = 20;       // Period for Donchian Channel
input double RiskRewardRatio = 1.5;     // Risk-to-reward ratio
input double LotSize = 0.1;             // Default lot size for trading
input double pipsToStopLoss = 15;       // Stop loss in pips for Breakout
input double pipsToTakeProfit = 30;     // Take profit in pips for Breakout

// Input parameters for Divergence Strategy
input int DivergenceMACDPeriod = 12;    // MACD Fast EMA period
input int DivergenceSignalPeriod = 9;   // MACD Signal period
input double DivergenceLots = 1.0;      // Lot size for Divergence trades
input double DivergenceStopLoss = 300;   // Stop Loss in points for Divergence
input double DivergenceTakeProfit = 500; // Take Profit in points for Divergence
input int DivergenceMagicNumber = 87654321;     // Magic number for Divergence Strategy
input int DivergenceLookBack = 8;       // Number of periods to look back for divergence
input double profitLockerPoints  = 20;  // Number of profit points to lock

// Indicator handle storage
int rsi_handle;                         
int handle;                             // Handle for Donchian Channel
int macd_handle;

double ExtUpBuffer[];                   // Upper Donchian buffer
double ExtDnBuffer[];                   // Lower Donchian buffer
double ExtMacdBuffer[];                 // MACD buffer
double ExtSignalBuffer[];               // Signal buffer
int globalMagicNumber;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
    prevShortMA = 0.0;
    prevLongMA = 0.0;
    // Initialize RSI handle
    rsi_handle = iRSI(_Symbol, PERIOD_CURRENT, RSI_Period, PRICE_CLOSE);
    if (rsi_handle == INVALID_HANDLE)
    {
        Print("Failed to create RSI indicator handle. Error: ", GetLastError());
        return INIT_FAILED;
    }

    // Create a handle for the Donchian Channel
    handle = iCustom(_Symbol, PERIOD_CURRENT, "Free Indicators\\Donchian Channel", InpDonchianPeriod);
    if (handle == INVALID_HANDLE)
    {
        Print("Failed to load the Donchian Channel indicator. Error: ", GetLastError());
        return INIT_FAILED;
    }

    // Initialize MACD handle for divergence
    globalMagicNumber = DivergenceMagicNumber;
    macd_handle = iMACD(_Symbol, PERIOD_CURRENT, DivergenceMACDPeriod, 26, DivergenceSignalPeriod, PRICE_CLOSE);
    if (macd_handle == INVALID_HANDLE)
    {
        Print("Failed to create MACD indicator handle for divergence strategy. Error: ", GetLastError());
        return INIT_FAILED;
    }
    
    
    if(UseGoldenDeathCrossStrategy)
{
    // Check if there are enough bars to calculate the EMA
    if(Bars(_Symbol, PERIOD_CURRENT) < GDC_SlowEMAPeriod)
    {
        Print("Not enough bars for EMA calculation for Golden Death Cross");
        return INIT_FAILED;
    }
    GDC_fastEMAHandle = iMA(_Symbol, PERIOD_CURRENT, GDC_FastEMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
    GDC_slowEMAHandle = iMA(_Symbol, PERIOD_CURRENT, GDC_SlowEMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
    if(GDC_fastEMAHandle < 0 || GDC_slowEMAHandle < 0)
    {
        Print("Failed to create EMA handles for Golden Death Cross. Error: ", GetLastError());
        return INIT_FAILED;
    }
}

    // Resize arrays for MACD buffers
    ArrayResize(ExtMacdBuffer, DivergenceLookBack);
    ArrayResize(ExtSignalBuffer, DivergenceLookBack);

    Print("Trend Constraint Expert initialized.");
    return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    IndicatorRelease(rsi_handle);
    IndicatorRelease(handle);
    IndicatorRelease(macd_handle);
    Print("Trend Constraint Expert deinitialized.");
}

//+------------------------------------------------------------------+
//| Check Golden/Death Cross Trading Logic                           |
//+------------------------------------------------------------------+
void CheckGoldenDeathCross()
{
    double fastEMAArray[2], slowEMAArray[2];
    double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
    double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
    double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

    if(CopyBuffer(GDC_fastEMAHandle, 0, 0, 2, fastEMAArray) <= 0 ||
       CopyBuffer(GDC_slowEMAHandle, 0, 0, 2, slowEMAArray) <= 0)
    {
        Print("Failed to copy EMA data for Golden Death Cross. Error: ", GetLastError());
        return;
    }

    bool hasPosition = PositionSelect(_Symbol);

    if(!hasPosition)
    {
        if(fastEMAArray[0] > slowEMAArray[0] && fastEMAArray[1] <= slowEMAArray[1]) // Death Cross 
        {
            double sl = NormalizeDouble(ask + GDC_StopLossPips * point, _Digits);
            if(!trade.Sell(GDC_LotSize, _Symbol, ask, sl ))
                Print("Sell order error for Golden Death Cross ", GetLastError());
            else
                Print("Sell order opened for Golden Death Cross with SL ", GDC_StopLossPips, " pips");
        }
        else if(fastEMAArray[0] < slowEMAArray[0] && fastEMAArray[1] >= slowEMAArray[1]) // Golden Cross
        {
            double sl = NormalizeDouble(bid - GDC_StopLossPips * point, _Digits);
            if(!trade.Buy(GDC_LotSize, _Symbol, bid, sl ))
                Print("Buy order error for Golden Death Cross ", GetLastError());
            else
                Print("Buy order opened for Golden Death Cross with SL ", GDC_StopLossPips, " pips");
        }
    }
    else
    {
        if((PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY && fastEMAArray[0] < slowEMAArray[0]) ||
           (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && fastEMAArray[0] > slowEMAArray[0]))
        {
            ulong ticket = PositionGetInteger(POSITION_TICKET);
            if(!trade.PositionClose(ticket))
                Print("Failed to close position for Golden Death Cross (Ticket: ", ticket, "). Error: ", GetLastError());
            else  
                Print("Position closed for Golden Death Cross: ", ticket);
        }
    }
}

//+------------------------------------------------------------------+
//| Check Trend Following Strategy                                   |
//+------------------------------------------------------------------+
void CheckTrendFollowing()
{
   if (PositionsTotal() >= 2) return; // Ensure no more than 2 orders from this strategy

    double rsi_value;
    double rsi_values[];
    if (CopyBuffer(rsi_handle, 0, 0, 1, rsi_values) <= 0)
    {
        Print("Failed to get RSI value. Error: ", GetLastError());
        return;
    }
    rsi_value = rsi_values[0];

    double ma_short = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_EMA, PRICE_CLOSE);
    double ma_long = iMA(_Symbol, PERIOD_CURRENT, 200, 0, MODE_EMA, PRICE_CLOSE);

    bool is_uptrend = ma_short > ma_long;
    bool is_downtrend = ma_short < ma_long;

    if (is_uptrend && rsi_value < RSI_Oversold)
    {
        double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
        double stopLossPrice = currentPrice - StopLoss * _Point;
        double takeProfitPrice = currentPrice + TakeProfit * _Point;

        // Corrected Buy method call with 6 parameters
        if (trade.Buy(Lots, _Symbol, 0, stopLossPrice, takeProfitPrice, "Trend Following Buy"))
        {
            Print("Trend Following Buy order placed.");
        }
    }
    else if (is_downtrend && rsi_value > RSI_Overbought)
    {
        double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
        double stopLossPrice = currentPrice + StopLoss * _Point;
        double takeProfitPrice = currentPrice - TakeProfit * _Point;

        // Corrected Sell method call with 6 parameters
        if (trade.Sell(Lots, _Symbol, 0, stopLossPrice, takeProfitPrice, "Trend Following Sell"))
        {
            Print("Trend Following Sell order placed.");
        }
    }
}

//+------------------------------------------------------------------+
//| Check Breakout Strategy                                          |
//+------------------------------------------------------------------+
void CheckBreakoutTrading()
{
    if (PositionsTotal() >= 2) return; // Ensure no more than 2 orders from this strategy

    ArrayResize(ExtUpBuffer, 2);
    ArrayResize(ExtDnBuffer, 2);

    if (CopyBuffer(handle, 0, 0, 2, ExtUpBuffer) <= 0 || CopyBuffer(handle, 2, 0, 2, ExtDnBuffer) <= 0)
    {
        Print("Error reading Donchian Channel buffer. Error: ", GetLastError());
        return;
    }

    double closePrice = iClose(_Symbol, PERIOD_CURRENT, 0);
    double lastOpen = iOpen(_Symbol, PERIOD_D1, 1);
    double lastClose = iClose(_Symbol, PERIOD_D1, 1);

    bool isBullishDay = lastClose > lastOpen;
    bool isBearishDay = lastClose < lastOpen;

    if (isBullishDay && closePrice > ExtUpBuffer[1])
    {
        double stopLoss = closePrice - pipsToStopLoss * _Point;
        double takeProfit = closePrice + pipsToTakeProfit * _Point;
        if (trade.Buy(LotSize, _Symbol, 0, stopLoss, takeProfit, "Breakout Buy") > 0)
        {
            Print("Breakout Buy order placed.");
        }
    }
    else if (isBearishDay && closePrice < ExtDnBuffer[1])
    {
        double stopLoss = closePrice + pipsToStopLoss * _Point;
        double takeProfit = closePrice - pipsToTakeProfit * _Point;
        if (trade.Sell(LotSize, _Symbol, 0, stopLoss, takeProfit, "Breakout Sell") > 0)
        {
            Print("Breakout Sell order placed.");
        }
    }
}

//+------------------------------------------------------------------+
//| Check Divergence Trading                                         |
//+------------------------------------------------------------------+
bool CheckBullishRegularDivergence()
{
    double priceLow1 = iLow(_Symbol, PERIOD_CURRENT, 2);
    double priceLow2 = iLow(_Symbol, PERIOD_CURRENT, DivergenceLookBack);
    double macdLow1 = ExtMacdBuffer[2];
    double macdLow2 = ExtMacdBuffer[DivergenceLookBack - 1];

    return (priceLow1 < priceLow2 && macdLow1 > macdLow2);
}

bool CheckBullishHiddenDivergence()
{
    double priceLow1 = iLow(_Symbol, PERIOD_CURRENT, 2);
    double priceLow2 = iLow(_Symbol, PERIOD_CURRENT, DivergenceLookBack);
    double macdLow1 = ExtMacdBuffer[2];
    double macdLow2 = ExtMacdBuffer[DivergenceLookBack - 1];

    return (priceLow1 > priceLow2 && macdLow1 < macdLow2);
}

bool CheckBearishRegularDivergence()
{
    double priceHigh1 = iHigh(_Symbol, PERIOD_CURRENT, 2);
    double priceHigh2 = iHigh(_Symbol, PERIOD_CURRENT, DivergenceLookBack);
    double macdHigh1 = ExtMacdBuffer[2];
    double macdHigh2 = ExtMacdBuffer[DivergenceLookBack - 1];

    return (priceHigh1 > priceHigh2 && macdHigh1 < macdHigh2);
}

bool CheckBearishHiddenDivergence()
{
    double priceHigh1 = iHigh(_Symbol, PERIOD_CURRENT, 2);
    double priceHigh2 = iHigh(_Symbol, PERIOD_CURRENT, DivergenceLookBack);
    double macdHigh1 = ExtMacdBuffer[2]; 
    double macdHigh2 = ExtMacdBuffer[DivergenceLookBack - 1];

    return (priceHigh1 < priceHigh2 && macdHigh1 > macdHigh2);
}

void CheckDivergenceTrading()
{
    if (!UseDivergenceStrategy) return;

    // Check if no position is open or if less than 3 positions are open
    int openDivergencePositions = CountOrdersByMagic(DivergenceMagicNumber);
    if (openDivergencePositions == 0 || openDivergencePositions < 3)
    {
        int barsAvailable = Bars(_Symbol, PERIOD_CURRENT);
        if (barsAvailable < DivergenceLookBack * 2)
        {
            Print("Not enough data bars for MACD calculation.");
            return;
        }

        int attempt = 0;
        while(attempt < 6)
        {
            if (CopyBuffer(macd_handle, 0, 0, DivergenceLookBack, ExtMacdBuffer) > 0 &&
                CopyBuffer(macd_handle, 1, 0, DivergenceLookBack, ExtSignalBuffer) > 0)
                break; 
            
            Print("Failed to copy MACD buffer, retrying...");
            Sleep(1000);
            attempt++;
        }
        if(attempt == 6)
        {
            Print("Failed to copy MACD buffers after ", attempt, " attempts.");
            return;
        }

        if(TimeCurrent() == iTime(_Symbol, PERIOD_CURRENT, 0))
        {
            Print("Skipping trade due to incomplete bar data.");
            return;
        }

        double currentClose = iClose(_Symbol, PERIOD_CURRENT, 0);
        double dailyClose = iClose(_Symbol, PERIOD_D1, 0);
        double dailyOpen = iOpen(_Symbol, PERIOD_D1, 0);
        bool isDailyBullish = dailyClose > dailyOpen;
        bool isDailyBearish = dailyClose < dailyOpen;

        // Only proceed with buy orders if D1 is bullish
        if (isDailyBullish)
        {
            if ((CheckBullishRegularDivergence() && ExtMacdBuffer[0] > ExtSignalBuffer[0]) ||
                CheckBullishHiddenDivergence())
            {
                ExecuteDivergenceOrder(true);
            }
        }

        // Only proceed with sell orders if D1 is bearish
        if (isDailyBearish)
        {
            if ((CheckBearishRegularDivergence() && ExtMacdBuffer[0] < ExtSignalBuffer[0]) ||
                CheckBearishHiddenDivergence())
            {
                ExecuteDivergenceOrder(false);
            }
        }
    }
    else
    {
        Print("Divergence strategy: Maximum number of positions reached.");
    }
}

void ExecuteDivergenceOrder(bool isBuy)
{
    // Ensure the magic number is set for the trade
    trade.SetExpertMagicNumber(DivergenceMagicNumber);
    
    double currentPrice = isBuy ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) : SymbolInfoDouble(_Symbol, SYMBOL_BID);
    double stopLossPrice = isBuy ? currentPrice - DivergenceStopLoss * _Point : currentPrice + DivergenceStopLoss * _Point;
    double takeProfitPrice = isBuy ? currentPrice + DivergenceTakeProfit * _Point : currentPrice - DivergenceTakeProfit * _Point;

    if (isBuy)
    {
        if (trade.Buy(DivergenceLots, _Symbol, 0, stopLossPrice, takeProfitPrice, "Divergence Buy"))
        {
            Print("Divergence Buy order placed.");
        }
    }
    else
    {
        if (trade.Sell(DivergenceLots, _Symbol, 0, stopLossPrice, takeProfitPrice, "Divergence Sell"))
        {
            Print("Divergence Sell order placed.");
        }
    }
}

int CountOrdersByMagic(int magic)
{
    int count = 0;
    for (int i = 0; i < PositionsTotal(); i++)
    {
        ulong ticket = PositionGetTicket(i);
        if (PositionSelectByTicket(ticket))
        {
            if (PositionGetInteger(POSITION_MAGIC) == magic)
            {
                count++;
            }
        }
    }
    return count;
}

//+------------------------------------------------------------------+
//| Profit Locking Logic                                             |
//+------------------------------------------------------------------+
void LockProfits()
{
    for (int i = PositionsTotal() - 1; i >= 0; i--)
    {
        ulong ticket = PositionGetTicket(i);
        if (PositionSelectByTicket(ticket))
        {
            double entryPrice = PositionGetDouble(POSITION_PRICE_OPEN);
            double currentProfit = PositionGetDouble(POSITION_PROFIT);
            double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT);
            
            // Convert profit to points
            double profitPoints = MathAbs(currentProfit / _Point);

            // Check if profit has exceeded 100 points
            if (profitPoints >= 100)
            {
                double newStopLoss;
                
                if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
                {
                    newStopLoss = entryPrice + profitLockerPoints * _Point; // 20 points above entry for buys
                }
                else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
                {
                    newStopLoss = entryPrice - profitLockerPoints * _Point; // 20 points below entry for sells
                }
                else
                {
                    continue; // Skip if not a buy or sell position
                }

                // Modify stop loss only if the new stop loss is more protective
                double currentStopLoss = PositionGetDouble(POSITION_SL);
                if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
                {
                    if (currentStopLoss < newStopLoss || currentStopLoss == 0)
                    {
                        if (trade.PositionModify(ticket, newStopLoss, PositionGetDouble(POSITION_TP)))
                        {
                            Print("Profit locking for buy position: Stop Loss moved to ", newStopLoss);
                        }
                    }
                }
                else // POSITION_TYPE_SELL
                {
                    if (currentStopLoss > newStopLoss || currentStopLoss == 0)
                    {
                        if (trade.PositionModify(ticket, newStopLoss, PositionGetDouble(POSITION_TP)))
                        {
                            Print("Profit locking for sell position: Stop Loss moved to ", newStopLoss);
                        }
                    }
                }
            }
        }
    }
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
    if (UseTrendFollowingStrategy)
        CheckTrendFollowing();
    if (UseBreakoutStrategy)
        CheckBreakoutTrading();
    if (UseDivergenceStrategy)
        CheckDivergenceTrading();
    if(UseGoldenDeathCrossStrategy)
        CheckGoldenDeathCross();

}


Resultados de Teste e Otimização

iniciando o Trend Constraint EA.

Expert Trend Constraint: Adicionando ao gráfico nas configurações padrão

Visualizador de Estratégia

Estratégia Golden and Death Cross visualizada como parte de outras estratégias no Strategy Tester


Conclusão

É possível expandir continuamente o código do nosso EA, mas isso pode torná-lo cada vez mais complexo e intensivo em recursos para processar. Isso destaca a necessidade de aprimorarmos nossas técnicas de gerenciamento de recursos. A integração de modelos de IA nesses conceitos é particularmente benéfica, pois eles podem lidar com essas complexidades de forma eficaz. Neste projeto, integramos com sucesso uma das estratégias mais populares para gerenciar oportunidades de reversão — a estratégia Golden and Death Cross — dentro do Expert Advisor Trend Constraint.

As etapas fundamentais que cobrimos desde Part(1) até agora estabeleceram a base para este EA. No entanto, para alcançar resultados ideais, o modelo de EA deve ser refinado, otimizando várias configurações e modificando recursos estruturais específicos. Essa abordagem o torna uma ferramenta valiosa para fins educacionais e experimentais. Observe que este EA não garante lucratividade; ele é destinado exclusivamente a fins educacionais e de pesquisa.

Nas próximas partes, pretendo refinar ainda mais as estratégias estabelecidas e introduzir técnicas de aprendizado de máquina para aprimorar as capacidades e o desempenho do EA.

Voltar à Introdução

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

Arquivos anexados |
Últimos Comentários | Ir para discussão (1)
Christian Paul Anasco
Christian Paul Anasco | 20 dez. 2024 em 03:15
Isso é exatamente o que eu gosto. Um código muito limpo. Fácil de ler e entender.
MQL5 Trading Toolkit (Parte 5): Expandindo a Biblioteca EX5 de Gerenciamento de Histórico com Funções de Posição MQL5 Trading Toolkit (Parte 5): Expandindo a Biblioteca EX5 de Gerenciamento de Histórico com Funções de Posição
Descubra como criar funções exportáveis em EX5 para consultar e salvar de forma eficiente dados históricos de posições. Neste guia passo a passo, ampliaremos a biblioteca EX5 de gerenciamento de histórico desenvolvendo módulos que recuperam propriedades-chave da posição fechada mais recentemente. Isso inclui lucro líquido, duração da negociação, stop loss em pips, take profit, valores de lucro e vários outros detalhes importantes.
Simulação de mercado: Position View (XX) Simulação de mercado: Position View (XX)
Neste artigo iremos ver como modificar o código do indicador de posição a fim de conseguir, criar um tipo de sombra para que possamos visualizar onde o preço se encontra atualmente no servidor de negociação. Tal principio tem como finalidade facilitar o planejamento de operações. Onde temos uma movimentação das linhas de stop loss ou take profit. Porém adicionar tal funcionalidade, ou seja sombras de preço. Pode parecer algo extremamente complexo. Mas neste artigo mostrarei que você conseguirá fazer isto de maneira muito simples e prática.
Gerenciamento de riscos (Parte 1): Fundamentos da construção de uma classe de gerenciamento de riscos Gerenciamento de riscos (Parte 1): Fundamentos da construção de uma classe de gerenciamento de riscos
Neste artigo, analisaremos os fundamentos do gerenciamento de riscos no trading e veremos como criar nossas primeiras funções para calcular o lote adequado para uma operação, assim como o stop loss. Além disso, examinaremos em detalhes como essas funções funcionam, explicando cada etapa. Nosso objetivo é fornecer uma compreensão clara de como aplicar esses conceitos na negociação automática. No final, aplicaremos tudo na prática, criando um script simples com o arquivo incluível que desenvolveremos.
Do básico ao intermediário: Sobrecarga de operadores (I) Do básico ao intermediário: Sobrecarga de operadores (I)
Neste artigo começaremos a ver como seria a implementação da chamada sobrecarga de operadores. Iremos começar vendo a motivação por detrás de tal implementação. Assim como também veremos que nem sempre as coisas são tão complicadas como parecem.