English Русский 中文 Español Deutsch 日本語
preview
Desenvolvimento de um indicador Heiken Ashi personalizado usando MQL5

Desenvolvimento de um indicador Heiken Ashi personalizado usando MQL5

MetaTrader 5Negociação | 9 outubro 2023, 14:40
432 0
Mohamed Abdelmaaboud
Mohamed Abdelmaaboud

Introdução

Todos nós precisamos interpretar gráficos. Entre as ferramentas que podem facilitar essa tarefa estão os indicadores, calculados com base nos preços, volume, outro indicador técnico ou sua combinação. Temos muitos indicadores prontos, integrados na plataforma de negociação, mas se precisarmos adicionar algumas funções que se adequem ao nosso estilo de negociação, precisaremos recorrer a soluções personalizadas.

Neste artigo, usaremos a função iCustom e criaremos um indicador personalizado de acordo com suas condições e preferências. Também criaremos um indicador técnico personalizado Heiken Ashi e o usaremos em sistemas de negociação. Os seguintes tópicos são abordados:

O material deste artigo pode ser usado como um exemplo para criar seus próprios indicadores personalizados. Usaremos a linguagem MQL5 (MetaQuotes Language), integrada na plataforma de negociação MetaTrader 5, para escrever códigos de indicadores e Expert Advisors criados. Se você não sabe como baixá-los e usá-los, leia a seção "Como escrever código MQL5 no MetaEditor" em um dos artigos anteriores.

Atenção! Todo o conteúdo deste artigo é apresentado "como está", apenas para fins educacionais e não constitui uma recomendação de negociação. O artigo não fornece qualquer garantia de resultados. Tudo o que você colocar em prática com base neste artigo, você faz exclusivamente por sua conta e risco, o autor não garante nenhum resultado.

Definição do indicador Heiken Ashi personalizado

Como mencionei na introdução na seção anterior, um indicador personalizado é uma ferramenta de análise técnica que pode ser criada pelo usuário usando a linguagem de programação MQL5. Pode ser usado no MetaTrader 5 para analisar e entender o movimento do mercado, bem como auxiliar na tomada de decisões de investimento fundamentadas. Existem muitos indicadores técnicos integrados úteis, mas às vezes precisamos analisar e entender como o mercado se comporta com base em algumas ideias matemáticas, estatísticas ou técnicas adicionais que não são cobertas pelos indicadores existentes. Nestes casos, precisamos criar nosso próprio indicador, e esta é uma das características distintivas da plataforma MetaTrader 5, pois nos ajuda a criar nossas próprias ferramentas analíticas ou de negociação, atendendo às nossas preferências e objetivos específicos.

Vamos analisar as etapas necessárias para criar seu próprio indicador:

Abra o MetaEditor e selecione a pasta Indicators no Navegador.

Pasta Indicators

Clique em "Criar" para criar um novo programa, conforme mostrado na figura abaixo.

Novo botão

Em seguida, abrirá uma janela onde você deve selecionar o tipo de programa que deseja criar. Escolha "Indicador Personalizado".

Seleção do tipo de programa

Após clicar no botão "Avançar", a próxima janela abrirá com informações sobre o indicador. Aqui, você deve especificar o nome do indicador personalizado e clicar em "Avançar".

Informações sobre o indicador

Nas janelas seguintes, forneceremos informações mais detalhadas sobre o indicador.

Informações sobre o indicador 2

Informações sobre o indicador 3

Após concluir todas as configurações e clicar no botão "Concluir", a janela do editor será aberta.

Vamos aprender a desenvolver nosso próprio indicador com base no exemplo do Heiken Ashi. Portanto, precisamos entender mais sobre ele. Este é um método de construção de gráficos de velas que pode ser usado para representar e analisar o movimento do mercado. Ele pode ser usado em conjunto com outras ferramentas para oferecer informações detalhadas que auxiliarão na tomada de decisões de negociação informadas.

Os gráficos do Heiken Ashi são semelhantes aos gráficos de velas tradicionais, mas os métodos de cálculo das velas são diferentes. Como sabemos, um gráfico de velas tradicional calcula os preços com base nos preços reais de abertura, máxima, mínima e fechamento durante um período específico, mas o Heiken Ashi leva em consideração os preços das velas anteriores ao calcular suas próprias velas.

Aqui está como os valores do Heiken Ashi são calculados:

  • Open = (abertura da vela anterior + fechamento da vela anterior) / 2
  • Close = (abertura + fechamento + máximo + mínimo da vela atual) / 4
  • High = o valor mais alto da máxima, da abertura ou do fechamento do período atual
  • Low = o valor mais baixo do mínimo, da abertura ou do fechamento do período atual

Com base nesses cálculos, o indicador cria velas de alta e baixa, e as cores dessas velas indicam a direção correspondente do mercado: alta ou baixa. Para efeito de comparação, abaixo são apresentadas velas japonesas tradicionais e o Heiken Ashi.

 Heiken Ashi

Na parte superior, são mostradas velas tradicionais, e na parte inferior, o indicador Heiken Ashi, que é exibido como velas azuis e vermelhas, indicando a direção do mercado. O objetivo do indicador é filtrar e eliminar parte do ruído no movimento do mercado, suavizando os dados para evitar sinais falsos.


Indicador Heiken Ashi simples

Vamos criar um indicador Heiken Ashi simples para uso no MetaTrader 5. O indicador deve constantemente verificar os preços (abertura, máxima, mínima e fechamento) e realizar cálculos para gerar valores de haOpen, haHigh, haLow e haClose. Com base nesses cálculos, o indicador deve exibir os valores no gráfico na forma de velas de cores diferentes: azul para movimento de alta e vermelho para movimento de baixa. As velas devem ser exibidas em uma janela separada abaixo do gráfico tradicional como uma sub-janela.

Vamos analisar todos os passos que precisamos seguir para criar este indicador personalizado.

Vamos definir as configurações do indicador especificando parâmetros adicionais por meio das valores #property e identificador:

  • (indicator_separate_window) - mostra o indicador em uma janela separada.
  • (indicator_buffers) - número de buffers de cálculo do indicador.
  • (indicator_plots) - número de séries gráficas no indicador. As séries gráficas são estilos de desenho que podem ser usados na criação de um indicador personalizado.
  • (indicator_typeN) - tipo de construção gráfica de acordo com os valores (ENUM_DRAW_TYPE). N - número de séries de gráficos que definimos no último parâmetro. Começa em 1.
  • (indicator_colorN) - cor N. N também é o número de séries gráficas que definimos anteriormente. Começa em 1.
  • (indicator_widthN) - espessura de N ou da série gráfica.
  • (indicator_labelN) - define o rótulo N de uma determinada série gráfica.
#property indicator_separate_window
#property indicator_buffers 5
#property indicator_plots   1
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_color1  clrBlue, clrRed
#property indicator_width1  2
#property indicator_label1  "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"

Criaremos cinco arrays para cinco buffers do indicador (haOpen, haHigh, haLow, haClose, haColor) do tipo double.

double haOpen[];
double haHigh[];
double haLow[];
double haClose[];
double haColor[];

Dentro da função OnInit(), esta função é usada para inicializar o indicador em funcionamento.

int OnInit()

Vamos classificar os buffers do indicador usando um array dinâmico unidimensional do tipo double com a função (SetIndexBuffer). Os parâmetros são os seguintes:

  • índice - número do buffer de indicador, a partir de 0. O número deve ser menor que o valor declarado no parâmetro (indicator_buffers).
  • buffer[] - array declarado no indicador personalizado.
  • data_type - tipo de dados que precisamos armazenar no array de indicadores.
   SetIndexBuffer(0,haOpen,INDICATOR_DATA);
   SetIndexBuffer(1,haHigh,INDICATOR_DATA);
   SetIndexBuffer(2,haLow,INDICATOR_DATA);
   SetIndexBuffer(3,haClose,INDICATOR_DATA);
   SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);

Vamos definir o valor da propriedade do indicador correspondente usando a função (IndicatorSetInteger) com uma variante de chamada na qual especificamos o identificador da propriedade. Os parâmetros são os seguintes:

  • prop_id - identificador da propriedade, que pode ser um dos (ENUM_CUSTOMIND_PROPERTY_INTEGER). Especificamos (INDICATOR_DIGITS).
  • prop_value - valor da propriedade. Especificamos (_Digits).
IndicatorSetInteger(INDICATOR_DIGITS,_Digits);

Vamos definir o valor da propriedade do tipo string com uma variante de chamada na qual também especificamos o identificador da propriedade. Os parâmetros são os seguintes:

  • prop_id - identificador da propriedade, que pode ser um dos (ENUM_CUSTOMIND_PROPERTY_STRING). Especificamos (INDICATOR_SHORTNAME) para usar um nome curto para o indicador.
  • prop_value - valor da propriedade. Especificamos ("Simple Heiken Ashi").
   IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");

Vamos definir o valor da propriedade do tipo double correspondente ao indicador usando a função (PlotIndexSetDouble). Os parâmetros são os seguintes:

  • plot_index - índice do gráfico. Vamos especificar 0.
  • prop_id - um dos valores (ENUM_PLOT_PROPERTY_DOUBLE). (PLOT_EMPTY_VALUE) - sem exibição.
  • prop_value - valor da propriedade.
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);

Em seguida, retornaremos (INIT_SUCCEEDED) como parte da função OnInit(), para concluí-la com uma inicialização bem-sucedida.

   return(INIT_SUCCEEDED);

Dentro da função OnCalculate, que é chamada no indicador para processar dados de preços, o tipo de cálculos é alterado com base na série temporal do período atual.

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])

Vamos criar uma variável inteira chamada start. O valor será atribuído posteriormente:

int start;

Usaremos um operador if para retornar os valores dos índices (baixo, alto, aberto e fechado) e start=1, se prev_calculated for igual a 0, ou retornaremos o valor inicial atribuído (prev_calculated-1):

   if(prev_calculated==0)
     {
      haLow[0]=low[0];
      haHigh[0]=high[0];
      haOpen[0]=open[0];
      haClose[0]=close[0];
      start=1;
     }
   else
      start=prev_calculated-1;

A função for é usada no laço de cálculos principal. O operador for consiste em três expressões e operações executadas.

Três expressões:

  • i=start - posição inicial.
  • i<rates_total && !IsStopped() - condições de encerramento do laço. IsStopped() verifica se o indicador é forçado a parar.
  • i++ - adição de 1 para obter um novo i.

Operações que devemos realizar a cada iteração do laço:

Cálculo para quatro variáveis do tipo double

  • haOpenVal - valor de abertura do Heiken Ashi.
  • haCloseVal - valor de fechamento do Heiken Ashi.
  • haHighVal - máximo do Heiken Ashi.
  • haLowVal - mínimo do Heiken Ashi.

Atribuição dos valores calculados no passo anterior aos próximos:

  • haLow[i]=haLowVal
  • haHigh[i]=haHighVal
  • haOpen[i]=haOpenVal
  • haClose[i]=haCloseVal

Verificamos se o valor de abertura do Heiken Ashi é menor que o valor de fechamento. Se sim, o indicador deve desenhar uma vela azul, caso contrário, uma vela vermelha.

   for(int i=start; i<rates_total && !IsStopped(); i++)
     {
      double haOpenVal =(haOpen[i-1]+haClose[i-1])/2;
      double haCloseVal=(open[i]+high[i]+low[i]+close[i])/4;
      double haHighVal =MathMax(high[i],MathMax(haOpenVal,haCloseVal));
      double haLowVal  =MathMin(low[i],MathMin(haOpenVal,haCloseVal));

      haLow[i]=haLowVal;
      haHigh[i]=haHighVal;
      haOpen[i]=haOpenVal;
      haClose[i]=haCloseVal;

      //--- set candle color
      if(haOpenVal<haCloseVal)
         haColor[i]=0.0;
      else
         haColor[i]=1.0;
     }

Finalizamos a função retornando (rates_total) como prev_calculated para a próxima chamada.

return(rates_total);

Compilamos o código para garantir a ausência de erros. O código completo é o seguinte:

//+------------------------------------------------------------------+
//|                                             simpleHeikenAshi.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 5
#property indicator_plots   1
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_color1  clrBlue, clrRed
#property indicator_width1  2
#property indicator_label1  "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"
double haOpen[];
double haHigh[];
double haLow[];
double haClose[];
double haColor[];
int OnInit()
  {
   SetIndexBuffer(0,haOpen,INDICATOR_DATA);
   SetIndexBuffer(1,haHigh,INDICATOR_DATA);
   SetIndexBuffer(2,haLow,INDICATOR_DATA);
   SetIndexBuffer(3,haClose,INDICATOR_DATA);
   SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
   IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
   return(INIT_SUCCEEDED);
  }
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   int start;
   if(prev_calculated==0)
     {
      haLow[0]=low[0];
      haHigh[0]=high[0];
      haOpen[0]=open[0];
      haClose[0]=close[0];
      start=1;
     }
   else
      start=prev_calculated-1;
   for(int i=start; i<rates_total && !IsStopped(); i++)
     {
      double haOpenVal =(haOpen[i-1]+haClose[i-1])/2;
      double haCloseVal=(open[i]+high[i]+low[i]+close[i])/4;
      double haHighVal =MathMax(high[i],MathMax(haOpenVal,haCloseVal));
      double haLowVal  =MathMin(low[i],MathMin(haOpenVal,haCloseVal));

      haLow[i]=haLowVal;
      haHigh[i]=haHighVal;
      haOpen[i]=haOpenVal;
      haClose[i]=haCloseVal;
      if(haOpenVal<haCloseVal)
         haColor[i]=0.0;
      else
         haColor[i]=1.0;
     }
   return(rates_total);
  }

Após a compilação bem-sucedida, o indicador estará disponível na pasta "Indicadores" na janela "Navegador", conforme mostrado abaixo.

simpleHA nav

Vamos iniciá-lo. A janela de configurações padrão será aberta:

 simpleHA win

Na guia "Cores", as configurações padrão são mostradas: azul para movimento ascendente e vermelho para movimento descendente. Você pode alterar esses valores conforme necessário.

 simpleHA win2

Após clicar em OK, o indicador é anexado ao gráfico e parece assim:

simpleHA em execução

Como podemos ver, o indicador funciona em uma janela separada. As velas azuis e vermelhas indicam a direção dos preços (alta e baixa). Agora temos nosso próprio indicador que criamos no MetaTrader 5. Podemos usá-lo em qualquer sistema de negociação. É isso que faremos agora.


EA baseado no indicador Heiken Ashi personalizado

Nesta seção, aprenderemos a usar indicadores personalizados em um EA. Criaremos um sistema simples Heiken Ashi que poderá nos mostrar os preços do indicador (abertura, máxima, mínima e fechamento), pois já sabemos que eles diferem dos preços reais de acordo com o cálculo do indicador.

Vamos criar um EA. O código completo é o seguinte:

//+------------------------------------------------------------------+
//|                                             heikenAshiSystem.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
int heikenAshi;
int OnInit()
  {
   heikenAshi=iCustom(_Symbol,_Period,"My Files\\Heiken Ashi\\simpleHeikenAshi");
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("Heiken Ashi System Removed");
  }
void OnTick()
  {
   double heikenAshiOpen[], heikenAshiHigh[], heikenAshiLow[], heikenAshiClose[];
   CopyBuffer(heikenAshi,0,0,1,heikenAshiOpen);
   CopyBuffer(heikenAshi,1,0,1,heikenAshiHigh);
   CopyBuffer(heikenAshi,2,0,1,heikenAshiLow);
   CopyBuffer(heikenAshi,3,0,1,heikenAshiClose);
   Comment("heikenAshiOpen ",DoubleToString(heikenAshiOpen[0],_Digits),
           "\n heikenAshiHigh ",DoubleToString(heikenAshiHigh[0],_Digits),
           "\n heikenAshiLow ",DoubleToString(heikenAshiLow[0],_Digits),
           "\n heikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));
  }

Essas são as diferenças neste código:

O tipo de programa é um EA. A estrutura do programa será diferente, pois consiste em três partes, a saber:

  • int OnInit() - inicialização do EA começa com o tipo recomendado, que retorna um valor inteiro.
  • void OnDeinit - desinicialização do trabalho do EA, que não retorna nenhum valor.
  • void OnTick() - processamento de uma nova cotação em cada tick, não retorna valores.

Fora das funções anteriores e antes delas, criamos uma variável inteira (heikenAshi).

int heikenAshi;

Dentro do escopo do OnInit(), atribuímos o valor da função iCustom à variável heikenAshi. A função iCustom retorna o identificador do indicador personalizado, que aqui será "Simple Heiken Ashi", mas você pode usar qualquer indicador personalizado na pasta "Indicadores". Parâmetros:

  • symbol - nome do símbolo, usamos (_Symbol) para o símbolo atual.
  • period - período de tempo, usamos (_Period) para o período de tempo atual.
  • name (nome) - nome do indicador personalizado com o caminho para ele na pasta "Indicators" (Indicadores). Aqui usamos o My Files\\\Heiken Ashi\\\\simpleHeikenAshi.

Em seguida, concluímos a função, retornando (INIT_SUCCEEDED) para uma inicialização bem-sucedida.

int OnInit()
  {
   heikenAshi=iCustom(_Symbol,_Period,"My Files\\Heiken Ashi\\simpleHeikenAshi");
   return(INIT_SUCCEEDED);
  }

Dentro da função OnDeinit(), usamos a função print para informar que o EA foi removido.

void OnDeinit(const int reason)
  {
   Print("Heiken Ashi System Removed");
  }

Dentro da função OnTick(), para concluir nosso código, fizemos o seguinte:

Criamos quatro variáveis do tipo double para os preços do Heiken Ashi (Open, High, Low e Close).

   double heikenAshiOpen[], heikenAshiHigh[], heikenAshiLow[], heikenAshiClose[];

Obtemos os dados dos buffers do indicador personalizado usando a função CopyBuffer. Parâmetros:

  • indicator_handle - identificador do indicador, que usamos (heikenAshi).
  • buffer_num - número do buffer do indicador que usamos (0 para abertura, 1 para alta, 2 para baixa e 3 para fechamento).
  • start_pos - a primeira posição do elemento copiado, usamos 0 para o elemento atual.
  • count - a quantidade de dados a serem copiados; usamos 1. Isso é o suficiente aqui.
  • buffer[] - array usado para cópia. Usamos (heikenAshiOpen para abertura, heikenAshiHigh para máximo, heikenAshiLow para mínimo e heikenAshiClose para fechamento).

Obtemos o comentário no gráfico com os preços atuais Heiken Ashi (Open, High, Low e Close) usando a função comment:

   Comment("heikenAshiOpen ",DoubleToString(heikenAshiOpen[0],_Digits),
           "\n heikenAshiHigh ",DoubleToString(heikenAshiHigh[0],_Digits),
           "\n heikenAshiLow ",DoubleToString(heikenAshiLow[0],_Digits),
           "\n heikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));

Após compilar e executar esse código sem erros, podemos encontrar o EA anexado ao gráfico. Podemos obter o mesmo sinal no exemplo a seguir:

 haSystem

Como podemos ver, os preços do indicador são exibidos como um comentário no canto superior esquerdo do gráfico.


Heiken Ashi - Sistema EMA

Nesta seção, adicionaremos mais uma ferramenta técnica para ver se o resultado será melhor ou não. A ideia é filtrar os sinais do indicador personalizado usando uma média móvel exponencial (EMA) com preços. Existem muitas maneiras de fazer isso: podemos criar outro indicador personalizado para a EMA, se desejarmos adicionar mais recursos à EMA. Em seguida, podemos usá-lo no EA como iCustom, assim como fizemos para obter os sinais desejados. Também podemos criar um indicador suavizado, suavizando os valores do indicador e, em seguida, usando nossos sinais. Podemos usar a função iMA embutida em nosso EA para obter sinais dele. Vamos usar esse método aqui para simplificar.

Precisamos permitir que o EA verifique constantemente os valores das duas EMAs (rápida e lenta), a EMA rápida anterior e o fechamento do Heiken Ashi para determinar as posições de cada valor. Se o valor anterior de heikenAshiClose for maior que o array rápido anterior EMA, e o valor atual da EMA rápida for maior que o valor atual da EMA lenta, o EA deve emitir um sinal de compra e esses valores devem ser exibidos no gráfico. Se o valor anterior de heikenAshiClose for menor que o array rápido anterior EMA, e o valor atual da EMA rápida for menor que o valor atual da EMA lenta, o EA deve emitir um sinal de venda e esses valores devem ser exibidos no gráfico.

O código completo para criar o EA é o seguinte:

//+------------------------------------------------------------------+
//|                                          heikenAsh-EMASystem.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
input int fastEMASmoothing=9; // Fast EMA Period
input int slowEMASmoothing=18; // Slow EMA Period
int heikenAshi;
double fastEMAarray[], slowEMAarray[];
int OnInit()
  {
   heikenAshi=iCustom(_Symbol,_Period,"My Files\\Heiken Ashi\\simpleHeikenAshi");
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("Heiken Ashi-EMA System Removed");
  }
void OnTick()
  {
   double heikenAshiOpen[], heikenAshiHigh[], heikenAshiLow[], heikenAshiClose[];
   CopyBuffer(heikenAshi,0,0,3,heikenAshiOpen);
   CopyBuffer(heikenAshi,1,0,3,heikenAshiHigh);
   CopyBuffer(heikenAshi,2,0,3,heikenAshiLow);
   CopyBuffer(heikenAshi,3,0,3,heikenAshiClose);
   int fastEMA = iMA(_Symbol,_Period,fastEMASmoothing,0,MODE_SMA,PRICE_CLOSE);
   int slowEMA = iMA(_Symbol,_Period,slowEMASmoothing,0,MODE_SMA,PRICE_CLOSE);
   ArraySetAsSeries(fastEMAarray,true);
   ArraySetAsSeries(slowEMAarray,true);
   CopyBuffer(fastEMA,0,0,3,fastEMAarray);
   CopyBuffer(slowEMA,0,0,3,slowEMAarray);
   if(heikenAshiClose[1]>fastEMAarray[1])
     {
      if(fastEMAarray[0]>slowEMAarray[0])
        {
         Comment("Buy Signal",
                 "\nfastEMA ",DoubleToString(fastEMAarray[0],_Digits),
                 "\nslowEMA ",DoubleToString(slowEMAarray[0],_Digits),
                 "\nprevFastEMA ",DoubleToString(fastEMAarray[1],_Digits),
                 "\nprevHeikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));
        }
     }
   if(heikenAshiClose[1]<fastEMAarray[1])
     {
      if(fastEMAarray[0]<slowEMAarray[0])
        {
         Comment("Sell Signal",
                 "\nfastEMA ",DoubleToString(fastEMAarray[0],_Digits),
                 "\nslowEMA ",DoubleToString(slowEMAarray[0],_Digits),
                 "\nprevFastEMA ",DoubleToString(fastEMAarray[1],_Digits),
                 "\nheikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));
        }
     }
  }

O que mudou no código em comparação com o anterior:

Criamos entradas personalizadas para definir o período da EMA rápida e o período da EMA lenta de acordo com as preferências do usuário.

input int fastEMASmoothing=9; // Fast EMA Period
input int slowEMASmoothing=18; // Slow EMA Period

Criamos dois arrays para fastEMA e slowEMA.

double fastEMAarray[], slowEMAarray[];

Definimos o número de dados a serem copiados para 3 em CopyBuffer para obter os valores anteriores do fechamento do indicador Heiken Ashi.

   CopyBuffer(heikenAshi,0,0,3,heikenAshiOpen);
   CopyBuffer(heikenAshi,1,0,3,heikenAshiHigh);
   CopyBuffer(heikenAshi,2,0,3,heikenAshiLow);
   CopyBuffer(heikenAshi,3,0,3,heikenAshiClose);

Definimos fastEMA e slowEMA usando a função integrada iMA, que retorna o identificador do indicador da média móvel. Parâmetros:

  • symbol - nome do símbolo, usamos (_Symbol) para o símbolo atual.
  • period - tempo, usamos (_Period) para o tempo atual.
  • ma_period - período para suavizar o valor médio, usamos (fastEMASmoothing e slowEMASmoothing).
  • ma_shift - deslocamento do indicador, usamos 0.
  • ma_method - tipo de média móvel, usamos MODE_SMA para média móvel simples.
  • applied_price - tipo de preço necessário para os cálculos, usamos PRICE_CLOSE.
   int fastEMA = iMA(_Symbol,_Period,fastEMASmoothing,0,MODE_SMA,PRICE_CLOSE);
   int slowEMA = iMA(_Symbol,_Period,slowEMASmoothing,0,MODE_SMA,PRICE_CLOSE);

Usamos a função ArraySetAsSeries para definir a flag AS_SERIES. Parâmetros:

  • array[] - array, usamos (fastEMAarray e slowEMA).
  • flag - direção de indexação do array, usamos true.
   ArraySetAsSeries(fastEMAarray,true);
   ArraySetAsSeries(slowEMAarray,true);

Obtemos dados do buffer do indicador EMA usando a função CopyBuffer.

   CopyBuffer(fastEMA,0,0,3,fastEMAarray);
   CopyBuffer(slowEMA,0,0,3,slowEMAarray);

Condições para retornar sinais usando o operador if:

No caso de um sinal de compra

Se o heikenAshiClose anterior for maior que o array fastEMA anterior e o array fastEMA atual for maior que o array slowEMA atual, o EA deve emitir um sinal de compra e os seguintes valores:

  • fastEMA
  • slowEMA
  • prevFastEMA
  • prevHeikenAshiClose
   if(heikenAshiClose[1]>fastEMAarray[1])
     {
      if(fastEMAarray[0]>slowEMAarray[0])
        {
         Comment("Buy Signal",
                 "\nfastEMA ",DoubleToString(fastEMAarray[0],_Digits),
                 "\nslowEMA ",DoubleToString(slowEMAarray[0],_Digits),
                 "\nprevFastEMA ",DoubleToString(fastEMAarray[1],_Digits),
                 "\nprevHeikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));
        }

No caso de um sinal de venda

Se o heikenAshiClose anterior for menor que o array fastEMA anterior e o array fastEMA atual for menor que o array slowEMA atual, o EA deve emitir um sinal de venda e os valores de preço:

  • fastEMA
  • slowEMA
  • prevFastEMA
  • prevHeikenAshiClose
   if(heikenAshiClose[1]<fastEMAarray[1])
     {
      if(fastEMAarray[0]<slowEMAarray[0])
        {
         Comment("Sell Signal",
                 "\nfastEMA ",DoubleToString(fastEMAarray[0],_Digits),
                 "\nslowEMA ",DoubleToString(slowEMAarray[0],_Digits),
                 "\nprevFastEMA ",DoubleToString(fastEMAarray[1],_Digits),
                 "\nheikenAshiClose ",DoubleToString(heikenAshiClose[0],_Digits));
        }
     }

Após compilar o código e executá-lo, podemos obter nossos sinais, como mostrado nos exemplos de teste a seguir.

No caso de sinal de compra:

HA com 2EMA - sinal de compra

Conforme visto no gráfico anterior, no canto superior esquerdo, temos o seguinte comentário como sinal:

  • Sinal de compra
  • fastEMA
  • prevFastEMA
  • prevHeikenAshiClose

No caso de sinal de venda:

HA com 2EMA - um sinal de venda

Como sinal no gráfico, temos os seguintes valores:

  • Sinal de venda
  • fastEMA
  • prevFastEMA
  • prevHeikenAshiClose

Considerações finais

Se você compreendeu tudo o que discutimos neste artigo, poderá criar seu próprio indicador Heiken Ashi ou até adicionar algumas funcionalidades extras de acordo com suas preferências. Isso facilitará a leitura dos gráficos e a tomada de decisões eficazes. Além disso, você poderá usar o indicador criado em seus sistemas de negociação como parte de Expert Advisors, pois mencionamos e o utilizamos em dois sistemas de negociação como exemplos.

  • Sistema Heiken Ashi
  • Sistema Heiken Ashi-EMA

Espero que o artigo tenha sido útil para você e o ajude a alcançar seus objetivos de negociação. Também espero que você tenha tentado aplicar o que aprendeu neste artigo, pois a prática é um fator muito importante no processo de aprendizado. Lembre-se de que você deve testar tudo o que aprendeu neste artigo ou em outras fontes antes de usar as informações adquiridas na negociação real. O principal objetivo deste artigo é puramente educacional, portanto, você deve ser cauteloso.

Em meu perfil, você pode encontrar links para outros artigos meus. Espero que eles também sejam úteis para você.

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

Estratégia de negociação simples: Reversão à média Estratégia de negociação simples: Reversão à média
A reversão à média é um tipo de negociação contra-tendência em que o trader espera que o preço retorne a algum tipo de equilíbrio, geralmente medido por uma média ou outra estatística de tendência central.
Como detectar tendências e padrões gráficos usando MQL5 Como detectar tendências e padrões gráficos usando MQL5
Neste artigo, é apresentado um método de detecção automática de padrões de ação de preços usando o MQL5, como tendências (de alta, de baixa e laterais) e padrões gráficos (topo duplo, fundo duplo).
Desenvolvendo um sistema de Replay (Parte 30): Projeto Expert Advisor - Classe C_Mouse (IV) Desenvolvendo um sistema de Replay (Parte 30): Projeto Expert Advisor - Classe C_Mouse (IV)
Aqui demonstrarei uma técnica que pode lhe ajudar muito, em vários momentos durante a sua vida como programador. Diferente do que muitos dizem, não é a plataforma que é limitada, mas sim o conhecimento do individuo que diz que tal coisa. O que será explicado aqui, mostrar que com um pouco de bom senso e criatividade, você pode tornar a plataforma MetaTrader 5 muito mais interessante e versátil. E sem precisar de fato criar programas malucos ou coisas do estilo. Você pode criar um código simples, porém seguro e confiável. Usando de perspicácia, domar o código a fim de modificar algo já existente, sem se quer remover ou adicionar uma única linha se quer, no código original.
Desenvolvendo um sistema de Replay (Parte 29): Projeto Expert Advisor — Classe C_Mouse (III) Desenvolvendo um sistema de Replay (Parte 29): Projeto Expert Advisor — Classe C_Mouse (III)
Agora que a classe C_Mouse foi melhorada. Podemos focar em criar uma classe que será usada para promover uma base completamente diferente de estudos. Mas como expliquei no inicio do artigo, não iremos usar herança ou polimorfismo para gerar esta nova classe. Iremos modificar, ou melhor dizendo, agregar alguns objetos novos a linha de preço. Isto neste primeiro momento, no próximo artigo mostrarei como modificar os estudos. Mas faremos isto sem mexer no código da classe C_Mouse. Sei que na pratica, isto seria mais simples ser feito usando herança ou polimorfismo. No entanto, existem técnicas diferentes para se conseguir a mesma coisa.