English Русский Español Deutsch 日本語
preview
Como construir e otimizar um sistema de negociação baseado em volatilidade (Chaikin Volatility - CHV)

Como construir e otimizar um sistema de negociação baseado em volatilidade (Chaikin Volatility - CHV)

MetaTrader 5Negociação | 17 setembro 2024, 08:49
14 0
Mohamed Abdelmaaboud
Mohamed Abdelmaaboud

Introdução

No universo da negociação, o fator de volatilidade é muito importante, pois é conhecido que existem várias ferramentas que podem ser usadas para medir esse fator. De acordo com o que medimos, podemos tomar decisões de negociação que podem ser melhores se considerarmos a volatilidade como parte do nosso sistema de negociação.

Neste artigo, vamos analisar um desses indicadores técnicos de volatilidade chamado Chaikin Volatility (CHV). Ao longo do artigo, você aprenderá o que é importante sobre o Chaikin Volatility, o que ele significa, como podemos calculá-lo e como podemos usá-lo a nosso favor para obter melhores resultados de negociação. Usaremos o indicador com base em estratégias de negociação simples (CHV Crossover e CHV e MA Crossover).

Nossa abordagem é entender como podemos considerar o Indicador de Volatilidade Chaikin como uma ferramenta de volatilidade para obter melhores resultados de negociação, que podem ser confiáveis em termos de medição de volatilidade e fazer parte do nosso sistema de negociação. Assim, aprenderemos a criar sistemas de negociação com base em estratégias baseadas em volatilidade e daremos um exemplo de como otimizar nosso sistema de negociação, adicionando táticas simples ou combinando outras ferramentas para obter melhores resultados em comparação ao que podemos obter sem essa otimização. Também aprenderemos a criar nosso próprio indicador CHV para ser usado como parte do nosso sistema de negociação.

Como você sabe, é muito importante que qualquer sistema de negociação seja testado em diferentes ambientes antes de usá-lo para negociação real, para garantir que será útil e adequado ao seu estilo de negociação, já que não há uma estratégia que sirva para todos. Portanto, faremos alguns testes simples para nosso sistema de negociação, com base nessas duas estratégias mencionadas, e eu encorajo você a fazer seus próprios testes usando diferentes aspectos dos que eu utilizei neste artigo para ver como isso pode melhorar seu sistema para obter melhores resultados do que eu consegui, ou até mesmo descobrir que essa ferramenta não é adequada ou aplicável ao seu sistema de negociação.

Cobriremos tudo isso nos seguintes tópicos:

Também é importante saber que, se você está aprendendo a programar para negociação ou programação em geral, é muito importante praticar e escrever código por conta própria. Então, eu encorajo você a codificar o que aprende, pois isso pode melhorar suas habilidades e conhecimentos em programação.

Aviso Legal: Todas as informações fornecidas "como estão" são apenas para fins educacionais e não são preparadas para fins de negociação ou aconselhamento. As informações não garantem nenhum tipo de resultado. Se você optar por usar esses materiais em qualquer uma de suas contas de negociação, fará isso por sua própria conta e risco e será o único responsável.


Chaikin Volatility

Nesta parte, identificaremos o Indicador de Volatilidade Chaikin em detalhes. O Chaikin Volatility foi criado por Marc Chaikin, que desenvolveu muitos indicadores técnicos que levam seu nome. O CHV é usado para medir a volatilidade nos movimentos dos mercados financeiros e pode ser útil para antecipar potenciais reversões de mercado. Pode ser útil para determinar o intervalo de valor entre os preços altos e baixos ao longo de um período de tempo, a fim de medir potenciais movimentos ou oscilações do mercado em qualquer direção. O CHV não leva em consideração lacunas (gaps) da mesma forma, como veremos ao calculá-lo. É muito importante observar que o aumento da volatilidade pode significar alto risco ou alto retorno, e vice-versa.

O indicador CHV pode registrar valores altos ou baixos. Valores crescentes significam que os preços estão mudando muito rapidamente, enquanto valores baixos indicam que os preços estão constantes e não há muita volatilidade no ativo subjacente. Acredito que seja muito importante mencionar que a volatilidade pode ser registrada em mercados com tendência ou sem tendência, não apenas em mercados com tendência, pois estamos medindo a volatilidade e não a tendência ou direção dos preços. Ao usar outras ferramentas técnicas como confirmação, isso trará melhores resultados, e é o que faremos, como mencionado, ao tentar tomar nossas decisões acompanhadas do indicador técnico de média móvel, para dar a direção do mercado e realizar negociações com tendência sempre que possível.

Como mencionamos, podemos usar o indicador CHV para prever reversões de mercado, pois às vezes, quando o indicador registra valores relativamente altos, isso pode ser usado para prever reversões e potenciais topos ou fundos no mercado. Agora precisamos entender como o indicador CHV é calculado para aprofundar nossa compreensão do conceito principal por trás do indicador.

H-L (i) = HIGH (i) - LOW (i)

H-L (i - 10) = HIGH (i - 10) - LOW (i - 10)

CHV = (EMA (H-L (i), 10) - EMA (H-L (i - 10), 10)) / EMA (H-L (i - 10), 10) * 100

onde:

  • HIGH (i) - refere-se ao preço máximo do candle atual.
  • LOW (i) - refere-se ao preço mínimo do candle atual.
  • HIGH (i - 10) - refere-se ao preço máximo do candle de dez posições atrás.
  • LOW (i - 10) - refere-se ao preço mínimo do candle de dez posições atrás.
  • H-L (i) - refere-se à diferença entre o preço máximo e o preço mínimo do candle atual.
  • H-L (i - 10) - refere-se à diferença entre os preços máximos e mínimos de dez candles atrás.
  • EMA - refere-se à média móvel exponencial.


Indicador personalizado de volatilidade Chaikin

Nesta seção, aprenderemos a codificar um indicador personalizado de volatilidade Chaikin usando MQL5, o que pode ser útil, pois podemos personalizar o indicador para atender aos nossos objetivos. A seguir estão os passos para codificar nosso indicador personalizado de volatilidade Chaikin (CHV):

Use o pré-processador #include para poder usar o arquivo de inclusão de médias móveis no programa e no cálculo.

#include <MovingAverages.mqh>

Usando o pré-processador #property para especificar parâmetros adicionais que são os mesmos que os valores de identificadores a seguir:

  • descrição: para definir um texto breve para o programa MQL5.
  • indicator_separate_window: para definir o local do indicador em uma janela separada.
  • indicator_buffers: para definir o número de buffers para o cálculo do indicador.
  • indicator_plots: para definir o número de séries gráficas no indicador.
  • indicator_type1: para especificar o tipo de plotagem gráfica, especificada pelos valores de ENUM_DRAW_TYPE. N é o número de séries gráficas; os números podem começar a partir de 1.
  • indicator_color1: para especificar a cor para exibir a linha N, N é o número de séries gráficas; os números podem começar a partir de 1.
  • indicator_width1: para especificar a espessura da linha do indicador, N é o número de séries gráficas; os números podem começar a partir de 1.
#property description "Chaikin Volatility"
#property indicator_separate_window
#property indicator_buffers 3

#property indicator_plots   1
#property indicator_type1   DRAW_HISTOGRAM
#property indicator_color1  MediumBlue
#property indicator_width1  3

Usando a palavra-chave enum para definir um conjunto de dados para o modo de suavização da média móvel:

enum smoothMode
  {
   SMA=0,// Simple MA
   EMA=1 // Exponential MA
  };

Configurando entradas para as configurações do indicador usando a palavra-chave input:

input int          smoothPeriodInp=10;  // Smoothing Period
input int          chvPeriodInp=10;     // Chaikin Volatility Period
input smoothMode   InpSmoothType=EMA;   // Smoothing Mode

Declarando três arrays de buffers chv, hl, e shl:

double             chvBuffer[];
double             hlBuffer[];
double             shlBuffer[];

Declarando duas variáveis globais para o período de suavização e o período CHV:

int                smoothPeriod,chvPeriod;

Na parte OnInit(), verificaremos e especificaremos as variáveis de entrada.

Nome da Média Móvel: Após declarar o maName, o programa verifica se a entrada é SMA, caso em que o nome será SMA (média móvel simples), ou se a entrada for EMA, o nome será EMA (média móvel exponencial).

   string maName;
   if(InpSmoothType==SMA)
      maName="SMA";
   else
      maName="EMA";

Período de suavização: O programa verificará o período de suavização, se for menor ou igual a zero, o valor será especificado com um valor padrão de 10 e uma mensagem será exibida. Se o valor for diferente, ou seja, maior que 10, será considerado conforme inserido.

   if(smoothPeriodInp<=0)
     {
      smoothPeriod=10;
      printf("Incorrect value for Smoothing Period input = %d. Default value = %d.",smoothPeriodInp,smoothPeriod);
     }
   else smoothPeriod=smoothPeriodInp;

Período CHV: O programa verificará se o período CHV é menor ou igual a zero, o valor será configurado para 10 por padrão e uma mensagem será exibida. Se for diferente, ou seja, maior que 10, será considerado conforme inserido.

   if(chvPeriodInp<=0)
     {
      chvPeriod=10;
      printf("Incorrect value for Chaikin Volatility Period input = %d. Default value = %d.",chvPeriodInp,chvPeriod);
     }
   else chvPeriod=chvPeriodInp;

Define buffers declarados usando a palavra-chave SetIndexBuffer para retornar um valor bool. Seus parâmetros são:

  • index: número do buffer do indicador, começa do zero e é menor que o valor do identificador #property de indicator_buffers.
  • buffer[]: para especificar o array declarado no indicador personalizado.
  • data_type: para especificar o que está sendo armazenado. O padrão é INDICATOR_DATA para chvBuffer e especificaremos INDICATOR_CALCULATIONS para ser usado no cálculo intermediário, e não no desenho.
   SetIndexBuffer(0,chvBuffer);
   SetIndexBuffer(1,hlBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,shlBuffer,INDICATOR_CALCULATIONS);

Especificando a configuração de desenho:

   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,smoothPeriod+chvPeriod-1);
   PlotIndexSetString(0,PLOT_LABEL,"CHV("+string(smoothPeriod)+","+maName+")");
   IndicatorSetString(INDICATOR_SHORTNAME,"Chaikin Volatility("+string(smoothPeriod)+","+maName+")");
   IndicatorSetInteger(INDICATOR_DIGITS,1);

Na parte OnCalculate, vamos declarar três variáveis inteiras da seguinte forma:

   int    i,pos,posCHV;

Definindo a variável posCHV para ser igual ao resultado de 2 - chvPeriod e smoothPeriod:

   posCHV=chvPeriod+smoothPeriod-2;

Para verificar se rateTotal é menor que o valor de posCHV, precisaremos de um valor de retorno de zero:

   if(rates_total<posCHV)
      return(0);

Definir o valor de pos após verificar se prev_calculated é menor que 1, o valor de pos será zero ou, se a condição não for verdadeira, pos será o resultado de prev_calculated - 1.

   if(prev_calculated<1)
      pos=0;
   else pos=prev_calculated-1;

Definindo o hlBuffer[i]

   for(i=pos;i<rates_total && !IsStopped();i++)
     {
      hlBuffer[i]=High[i]-Low[i];
     }

Definindo o buffer smoothedhl (shl):

   if(pos<smoothPeriod-1)
     {
      pos=smoothPeriod-1;
      for(i=0;i<pos;i++)
        {
         shlBuffer[i]=0.0;
        }
     }

Definindo as MAs simples e exponenciais usando as funções SimpleMAOnBuffer e ExponentialMAOnBuffer:

   if(InpSmoothType==SMA)
     {
      SimpleMAOnBuffer(rates_total,prev_calculated,0,smoothPeriod,hlBuffer,shlBuffer);
     }
   else
      ExponentialMAOnBuffer(rates_total,prev_calculated,0,smoothPeriod,hlBuffer,shlBuffer);

Atualizando o pos após verificar se o pos é menor que o posCHV:

   if(pos<posCHV)
     {
      pos=posCHV;
     }

Definindo o buffer CHV:

   for(i=pos;i<rates_total && !IsStopped();i++)
     {
      if(shlBuffer[i-chvPeriod]!=0.0)
         chvBuffer[i]=100.0*(shlBuffer[i]-shlBuffer[i-chvPeriod])/shlBuffer[i-chvPeriod];
      else
         chvBuffer[i]=0.0;
     }

Retornando o rates_total:

return(rates_total);

Então, o código completo em um bloco será o seguinte:

//+------------------------------------------------------------------+
//|                                           Chaikin Volatility.mq5 |
//+------------------------------------------------------------------+
#include <MovingAverages.mqh>
#property description "Chaikin Volatility"
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_plots   1
#property indicator_type1   DRAW_HISTOGRAM
#property indicator_color1  MediumBlue
#property indicator_width1  3
enum smoothMode
  {
   SMA=0,// Simple MA
   EMA=1 // Exponential MA
  };
input int          smoothPeriodInp=10;  // Smoothing Period
input int          chvPeriodInp=10;     // Chaikin Volatility Period
input smoothMode InpSmoothType=EMA;   // Smoothing Mode
double             chvBuffer[];
double             hlBuffer[];
double             shlBuffer[];
int                smoothPeriod,chvPeriod;
void OnInit()
  {
   string maName;
   if(InpSmoothType==SMA)
      maName="SMA";
   else
      maName="EMA";
   if(smoothPeriodInp<=0)
     {
      smoothPeriod=10;
      printf("Incorrect value for Smoothing Period input = %d. Default value = %d.",smoothPeriodInp,smoothPeriod);
     }
   else
      smoothPeriod=smoothPeriodInp;
   if(chvPeriodInp<=0)
     {
      chvPeriod=10;
      printf("Incorrect value for Chaikin Volatility Period input = %d. Default value = %d.",chvPeriodInp,chvPeriod);
     }
   else
      chvPeriod=chvPeriodInp;
   SetIndexBuffer(0,chvBuffer);
   SetIndexBuffer(1,hlBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,shlBuffer,INDICATOR_CALCULATIONS);
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,smoothPeriod+chvPeriod-1);
   PlotIndexSetString(0,PLOT_LABEL,"CHV("+string(smoothPeriod)+","+maName+")");
   IndicatorSetString(INDICATOR_SHORTNAME,"Chaikin Volatility("+string(smoothPeriod)+","+maName+")");
   IndicatorSetInteger(INDICATOR_DIGITS,1);
  }
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 &TickVolume[],
                const long &Volume[],
                const int &Spread[])
  {
   int    i,pos,posCHV;
   posCHV=chvPeriod+smoothPeriod-2;
   if(rates_total<posCHV)
      return(0);
   if(prev_calculated<1)
      pos=0;
   else
      pos=prev_calculated-1;
   for(i=pos;i<rates_total && !IsStopped();i++)
     {
      hlBuffer[i]=High[i]-Low[i];
     }
   if(pos<smoothPeriod-1)
     {
      pos=smoothPeriod-1;
      for(i=0;i<pos;i++)
        {
         shlBuffer[i]=0.0;
        }
     }
   if(InpSmoothType==SMA)
     {
      SimpleMAOnBuffer(rates_total,prev_calculated,0,smoothPeriod,hlBuffer,shlBuffer);
     }
   else
      ExponentialMAOnBuffer(rates_total,prev_calculated,0,smoothPeriod,hlBuffer,shlBuffer);
   if(pos<posCHV)
     {
      pos=posCHV;
     }
   for(i=pos;i<rates_total && !IsStopped();i++)
     {
      if(shlBuffer[i-chvPeriod]!=0.0)
         chvBuffer[i]=100.0*(shlBuffer[i]-shlBuffer[i-chvPeriod])/shlBuffer[i-chvPeriod];
      else
         chvBuffer[i]=0.0;
     }
   return(rates_total);
  }

Após compilar este código, seremos capazes de encontrar o mesmo indicador conforme o gráfico a seguir, se o anexarmos ao gráfico:

CHVInda

Como podemos ver no gráfico anterior, o indicador na janela inferior do gráfico é mostrado como um histograma, oscilando ou registrando valores acima e abaixo de zero.


Estratégias de negociação Chaikin Volatility

Nesta parte, veremos como podemos usar o indicador Chaikin Volatility a nosso favor, e isso pode ser parte do nosso sistema de negociação para considerar a volatilidade ao negociar. Usaremos apenas o CHV e tomaremos decisões de negociação com base no valor do indicador, e então testaremos isso para ver se os resultados podem ser lucrativos ou não.

Usaremos outra estratégia e combinaremos outro indicador para filtrar as decisões com base na direção da média móvel como uma otimização da estratégia para ver se é lucrativa ou melhor do que usar apenas o CHV, ou não, com base nos testes dessa estratégia.

Abaixo estão essas estratégias:

Crossover do CHV:

Essa estratégia pode gerar sinais de compra e venda e colocar ordens automaticamente. Quando o valor do CHV estiver acima de zero, o EA colocará uma posição de compra. Se o valor do CHV estiver abaixo de zero, o EA colocará uma posição de venda.

Simplificando,

Valor do CHV > 0 => posição de compra

Valor do CHV < 0 => posição de venda

Crossover do CHV e da MA:

A estratégia gerará sinais e colocará posições de compra e venda com base no cruzamento entre o valor do CHV e o nível zero, levando em consideração a direção da média móvel. Se o CHV estiver acima de zero e a média móvel estiver abaixo do preço de fechamento, uma posição de compra será gerada e colocada. Por outro lado, se o CHV estiver abaixo de zero e a média móvel estiver acima do preço de fechamento, uma posição de venda será gerada e colocada.

Simplificando,

CHV > 0 e preço de fechamento > MA => posição de compra

CHV < 0 e preço de fechamento < MA => posição de venda


Sistema de negociação Chaikin Volatility

Nesta parte, criaremos um sistema de negociação com MQL5 baseado nas estratégias mencionadas e testaremos cada uma para ver como podemos otimizar a estratégia para obter melhores resultados. Primeiro, criaremos um EA simples para ser a base de nossos sistemas de negociação das duas estratégias, e esse EA mostrará os valores do CHV como um comentário no gráfico. A seguir estão os passos para fazer isso:

Declarar as entradas do sistema de negociação com base no indicador:

enum SmoothMethod
  {
   SMA=0,// Simple MA
   EMA=1 // Exponential MA
  };
input int          InpSmoothPeriod=10;  // Smoothing period
input int          InpCHVPeriod=10;     // Chaikin Volatility period
input SmoothMethod InpSmoothType=EMA;   // Smoothing method

Declarar uma variável inteira para o chv:

int chv;

Na parte OnInit() do EA, definiremos a variável chv para ser igual à função iCustom, que retorna o identificador do indicador CHV. Os parâmetros de iCustom são:

  • símbolo: para especificar o nome do símbolo, usaremos (_Symbol) para ser aplicado ao símbolo atual.
  • período: para especificar o período, usaremos o PERIOD_CURRENT para ser aplicado ao período atual.
  • nome: para especificar o nome do indicador.
  • Especificação da lista de entradas (smoothPeriodInp, chvPeriodInp e smoothTypeInp).
chv = iCustom(_Symbol,PERIOD_CURRENT,"Custom_CHV",smoothPeriodInp,chvPeriodInp, smoothTypeInp);

Na parte OnDeinit(), imprimiremos a mensagem quando o EA for removido:

Print("EA is removed");

Na parte OnTick(), declarando o array chvInd:

double chvInd[];

Obtendo os dados do buffer especificado do indicador CHV usando a palavra-chave CopyBuffer. Seus parâmetros são:

  • handle do indicador: para especificar o handle do indicador, que é o chv. 
  • buffer_num: para especificar o número do buffer do indicador, que será 0.
  • start_pos: para especificar a posição inicial, que será 0.
  • contagem: para especificar a quantidade a ser copiada, que será 3.
  • buffer[]: para especificar o array de destino, que será chvInd.
CopyBuffer(chv,0,0,3,chvInd);

Definindo a flag AS_SERIES para o array selecionado usando a palavra-chave ArraySetAsSeries e seus parâmetros são:

  • array[]: para especificar o array por referência, que será chvInd. 
  • flag: definir como true, o que denota a ordem inversa de indexação. 
ArraySetAsSeries(chvInd,true);

Declarar e definir o chvVal para retornar o valor atual do indicador:

double chvVal = NormalizeDouble(chvInd[0], 1);

Comentar o valor atual no gráfico:

Comment("CHV value = ",chvVal);

Então, podemos ver o código completo em um bloco igual ao seguinte:

//+------------------------------------------------------------------+
//|                                                       chvVal.mq5 |
//+------------------------------------------------------------------+
enum SmoothMethod
  {
   SMA=0,// Simple MA
   EMA=1 // Exponential MA
  };
input int          smoothPeriodInp=10;  // Smoothing period
input int          chvPeriodInp=10;     // Chaikin Volatility period
input SmoothMethod smoothTypeInp=EMA;   // Smoothing method
int chv;
int OnInit()
  {
   chv = iCustom(_Symbol,PERIOD_CURRENT,"Custom_CHV",smoothPeriodInp,chvPeriodInp, smoothTypeInp);
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("EA is removed");
  }
void OnTick()
  {
    double chvInd[];
    CopyBuffer(chv,0,0,3,chvInd);
    ArraySetAsSeries(chvInd,true);
    double chvVal = NormalizeDouble(chvInd[0], 1);
    Comment("CHV value = ",chvVal);
  }
//+------------------------------------------------------------------+

Após compilar este código, podemos encontrar o valor do CHV atual conforme mostrado no gráfico a seguir:

chvVal

Podemos garantir que o valor impresso no gráfico está correto inserindo o indicador no mesmo gráfico para ver se há alguma diferença entre os dois valores ou não. O gráfico a seguir mostra isso para garantir que tudo está correto antes de prosseguirmos na criação do nosso sistema de negociação:

chvValSame

Como podemos ver, o valor impresso do CHV atual é o mesmo que o valor do indicador anexado. Agora, vamos criar nosso sistema de negociação para a primeira estratégia (Crossover do CHV).

Crossover do CHV:

De acordo com a estratégia de Crossover do CHV, o código completo para ela é o seguinte:

//+------------------------------------------------------------------+
//|                                                 chvCrossover.mq5 |
//+------------------------------------------------------------------+
#include <trade/trade.mqh>
enum smoothMode
  {
   SMA=0,// Simple MA
   EMA=1 // Exponential MA
  };
input int          smoothPeriodInp=10;  // Smoothing period
input int          chvPeriodInp=10;     // Chaikin Volatility period
input smoothMode   smoothTypeInp=EMA;   // Smoothing Mode
input double       lotSize=1;
input double slPips = 300;
input double tpPips = 600;

int chv;
int barsTotal;
CTrade trade;
int OnInit()
  {
   barsTotal=iBars(_Symbol,PERIOD_CURRENT);
   chv = iCustom(_Symbol,PERIOD_CURRENT,"Custom_CHV",smoothPeriodInp,chvPeriodInp, smoothTypeInp, lotSize, slPips, tpPips);
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("EA is removed");
  }
void OnTick()
  {
   int bars=iBars(_Symbol,PERIOD_CURRENT);
   if(barsTotal < bars)
     {
      barsTotal=bars;
      double chvInd[];
      CopyBuffer(chv,0,0,3,chvInd);
      ArraySetAsSeries(chvInd,true);
      double chvVal = NormalizeDouble(chvInd[0], 1);
      double chvValPrev = NormalizeDouble(chvInd[1], 1);
      if(chvVal>0)
        {
         double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
         double slVal = ask - slPips*_Point;
         double tpVal = ask + tpPips*_Point;
         trade.Buy(lotSize,_Symbol,ask,slVal,tpVal);
        }
      if(chvVal<0)
        {
         double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
         double slVal = bid + slPips*_Point;
         double tpVal = bid - tpPips*_Point;
         trade.Sell(lotSize,_Symbol,bid,slVal,tpVal);
        }
     }
  }
//+------------------------------------------------------------------+

As diferenças neste código são as seguintes:

Incluir o arquivo de negociação para funções de trade.

#include <trade/trade.mqh>

Declarar entradas para lotSize, slPips e tpPips para serem editáveis pelo usuário.

input double      lotSize=1;
input double slPips = 300;
input double tpPips = 600;

Declaração de uma variável inteira barsTotal a ser usada como código para cada novo candle.

int barsTotal;

Declaração do objeto de trade.

CTrade trade;

Na parte OnInit(), teremos a definição da variável barsTotal.

barsTotal=iBars(_Symbol,PERIOD_CURRENT);

Adicionando as três entradas de lotSize, slPips e tpPips à palavra-chave iCustom.

chv = iCustom(_Symbol,PERIOD_CURRENT,"Custom_CHV",smoothPeriodInp,chvPeriodInp, smoothTypeInp, lotSize, slPips, tpPips);

Declaração e definição da variável inteira bars.

int bars=iBars(_Symbol,PERIOD_CURRENT);

Verificando se barsTotal é menor que bars, precisamos executar o seguinte:

Atualizar o valor de barsTotal para ser igual ao valor de bars.

barsTotal=bars;

Declaração do array chvInd.

double chvInd[];

Recuperação dos dados do buffer especificado do indicador CHV por meio da palavra-chave CopyBuffer.

CopyBuffer(chv,0,0,3,chvInd);

Definir a flag AS_SERIES no array selecionado usando a palavra-chave ArraySetAsSeries, conforme o seguinte.

ArraySetAsSeries(chvInd,true);

Declaração e definição de chvVal para o retorno do valor atual e o valor anterior do indicador.

      double chvVal = NormalizeDouble(chvInd[0], 1);
      double chvValPrev = NormalizeDouble(chvInd[1], 1);

Definindo a condição para a posição de compra, precisamos que o EA coloque automaticamente uma posição de compra quando verificar o valor do CHV e encontrar que ele é maior que zero.

      if(chvVal>0)
        {
         double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
         double slVal = ask - slPips*_Point;
         double tpVal = ask + tpPips*_Point;
         trade.Buy(lotSize,_Symbol,ask,slVal,tpVal);
        }

Definindo a condição para a posição de venda, precisamos que o EA coloque automaticamente uma posição de venda quando verificar o valor do CHV e encontrar que ele é menor que zero.

      if(chvVal<0)
        {
         double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
         double slVal = bid + slPips*_Point;
         double tpVal = bid - tpPips*_Point;
         trade.Sell(lotSize,_Symbol,bid,slVal,tpVal);
        }

Após compilar este código, podemos ver que a colocação da posição de compra pode ser a mesma que a seguinte:

chvCrossover_buySignal

Podemos verificar que a posição de venda também pode ser colocada da mesma maneira que a seguinte:

chvCrossover_sellSignal

Como sabemos, não há uma boa estratégia sem testar e obter resultados lucrativos. Vamos nos concentrar nas seguintes métricas-chave:

  • Lucro Líquido: É calculado subtraindo a perda bruta do lucro bruto. O valor mais alto é o melhor.
  • DD Relativo do Saldo: É a perda máxima que a conta experimenta durante as negociações. O menor é o melhor.
  • Fator de Lucro: É a razão do lucro bruto para a perda bruta. O valor mais alto é o melhor.
  • Payoff Esperado: É o lucro ou perda média de uma negociação. O valor mais alto é o melhor.
  • Fator de recuperação: Mede o quão bem a estratégia testada se recupera após perdas. O valor mais alto é o melhor.
  • Índice de Sharpe: Determina o risco e a estabilidade do sistema de negociação testado comparando o retorno com o retorno livre de risco. O Índice de Sharpe mais alto é o melhor.

A seguir estão os gráficos dos resultados dos testes. Vamos testá-lo por um ano (1-1-2023 a 31-12-2023) em EURUSD e um período de 1 hora.

chvCrossover_result

chvCrossover_result2

chvCrossover_result1

De acordo com os resultados dos testes, podemos encontrar os seguintes valores importantes:

  • Lucro Líquido: -35936.34 USD.
  • DD relativo do saldo: 48.12%.
  • Fator de Lucro: 0.94.
  • Payoff Esperado: -6.03.
  • Fator de Recuperação: -0.62.
  • Índice de Sharpe: -1.22.

De acordo com os resultados anteriores, podemos ver que os resultados não são bons ou lucrativos, então precisamos otimizá-los para melhorar e obter melhores resultados. A seguir, faremos isso por meio da estratégia.

Crossover do CHV e da MA:

De acordo com esta estratégia, usaremos o indicador CHV, mas combinaremos outro indicador técnico, a média móvel, para filtrar as negociações com base na direção da média móvel. Abaixo está o código completo para fazer isso:

//+------------------------------------------------------------------+
//|                                             chv_MA_Crossover.mq5 |
//+------------------------------------------------------------------+
#include <trade/trade.mqh>
enum smoothMode
  {
   SMA=0,// Simple MA
   EMA=1 // Exponential MA
  };
input int          InpSmoothPeriod=10;  // Smoothing period
input int          InpCHVPeriod=10;     // Chaikin Volatility period
input smoothMode smoothTypeInp=EMA;   // Smoothing Mode
input int InpMAPeriod=10; //MA Period
input ENUM_MA_METHOD InpMAMode=MODE_EMA; // MA Mode
input double      lotSize=1;
input double slPips = 300;
input double tpPips = 600;
int chv;
int ma;
int barsTotal;
CTrade trade;
int OnInit()
  {
   barsTotal=iBars(_Symbol,PERIOD_CURRENT);
   chv = iCustom(_Symbol,PERIOD_CURRENT,"Custom_CHV",InpSmoothPeriod,InpCHVPeriod, smoothTypeInp, lotSize, slPips, tpPips);
   ma=iMA(_Symbol,PERIOD_CURRENT, InpMAPeriod, 0, InpMAMode, PRICE_CLOSE);
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("EA is removed");
  }
void OnTick()
  {
   int bars=iBars(_Symbol,PERIOD_CURRENT);
   if(barsTotal < bars)
     {
      barsTotal=bars;
      double chvInd[];
      double maInd[];
      CopyBuffer(chv,0,0,3,chvInd);
      ArraySetAsSeries(chvInd,true);
      CopyBuffer(ma,0,0,3,maInd);
      ArraySetAsSeries(maInd,true);
      double chvVal = NormalizeDouble(chvInd[0], 1);
      double chvValPrev = NormalizeDouble(chvInd[1], 1);
      double maVal = NormalizeDouble(maInd[0], 5);
      double maValPrev = NormalizeDouble(maInd[1], 5);
      double lastClose=iClose(_Symbol,PERIOD_CURRENT,1);
      double prevLastClose=iClose(_Symbol,PERIOD_CURRENT,2);

      if(prevLastClose<maValPrev && lastClose>maVal && chvVal>0)
        {
         double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
         double slVal = ask - slPips*_Point;
         double tpVal = ask + tpPips*_Point;
         trade.Buy(lotSize,_Symbol,ask,slVal,tpVal);
        }
      if(prevLastClose>maValPrev && lastClose<maVal && chvVal<0)
        {
         double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
         double slVal = bid + slPips*_Point;
         double tpVal = bid - tpPips*_Point;
         trade.Sell(lotSize,_Symbol,bid,slVal,tpVal);
        }
     }
  }
//+------------------------------------------------------------------+

As diferenças neste código são as seguintes:

Declarar uma variável inteira para a média móvel (ma).

int ma;

Na parte OnInit(), definiremos a ma usando a palavra-chave iMA para retornar o identificador da média móvel. Seus parâmetros são:

  • symbol: para especificar o nome do símbolo, será _Symbol para ser aplicado ao atual. 
  • period: para especificar o período de tempo, será PERIOD_CURRENT para ser aplicado ao período atual.
  • ma_period: para especificar o período da média móvel, será a entrada MAperiod.
  • ma_shift: para especificar se precisamos de um deslocamento horizontal para a linha da média.
  • ma_method: para especificar o modo de suavização da média móvel, será a entrada do modo de MA. 
  • applied_price: para especificar o tipo de preço a ser utilizado para o cálculo, usaremos o preço de fechamento.
ma=iMA(_Symbol,PERIOD_CURRENT, InpMAPeriod, 0, InpMAMode, PRICE_CLOSE);

Adicionando o seguinte após verificar se há um novo candle:

Declarar o array maInd[].

double maInd[];

Obtendo dados do buffer especificado do indicador de média móvel usando a palavra-chave CopyBuffer e definindo a flag AS_SERIES para o array selecionado usando a palavra-chave ArraySetAsSeries.

      CopyBuffer(ma,0,0,3,maInd);
      ArraySetAsSeries(maInd,true);

Definindo os seguintes valores:

a média móvel atual, a média móvel anterior, o último preço de fechamento e o penúltimo preço de fechamento.

      double maVal = NormalizeDouble(maInd[0], 5);
      double maValPrev = NormalizeDouble(maInd[1], 5);
      double lastClose=iClose(_Symbol,PERIOD_CURRENT,1);
      double prevLastClose=iClose(_Symbol,PERIOD_CURRENT,2);

Definindo as condições da posição de compra, se o penúltimo preço de fechamento for menor que o valor da média móvel anterior e, ao mesmo tempo, o último preço de fechamento for maior que a média móvel atual e o valor atual do Chaikin for maior que zero, o EA deverá colocar uma posição de compra.

      if(prevLastClose<maValPrev && lastClose>maVal && chvVal>0)
        {
         double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
         double slVal = ask - slPips*_Point;
         double tpVal = ask + tpPips*_Point;
         trade.Buy(lotSize,_Symbol,ask,slVal,tpVal);
        }

Definindo as condições da posição de venda, se o penúltimo preço de fechamento for maior que o valor da média móvel anterior e, ao mesmo tempo, o último preço de fechamento for menor que a média móvel atual e o valor atual do Chaikin for menor que zero, o EA deverá colocar uma posição de venda.

      if(prevLastClose>maValPrev && lastClose<maVal && chvVal<0)
        {
         double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
         double slVal = bid + slPips*_Point;
         double tpVal = bid - tpPips*_Point;
         trade.Sell(lotSize,_Symbol,bid,slVal,tpVal);
        }

Após compilar este código, podemos ver que a colocação da posição de compra pode ser a mesma que a seguinte:

chvMACrossover_buySignal

Podemos verificar que a posição de venda também pode ser colocada da mesma maneira que a seguinte:

chvMACrossover_sellSignal

Após testar essa estratégia por um ano (1/1/2023 a 31/12/2023) no EURUSD e em um período de 1 hora, nossos resultados são os seguintes.

chvMACrossover_result

chvMACrossover_result2

chvMACrossover_result1

De acordo com os resultados dos testes, podemos encontrar os seguintes valores importantes:

  • Lucro Líquido: 20817.39 USD.
  • DD relativo do saldo: 9.62%.
  • Fator de Lucro: 1.15.
  • Payoff Esperado: 29.28.
  • Fator de Recuperação: 1.69
  • Índice de Sharpe: 1.71.

Com base nos resultados dos testes anteriores e após adicionar outra ferramenta técnica, que é a média móvel, podemos encontrar os melhores números que correspondem à estratégia testada de Crossover do CHV e da MA e ao período de 1 hora, conforme o seguinte:

  • Lucro líquido: O melhor valor (20817.39 USD).
  • DD relativo do saldo: O melhor valor mais baixo (9.62%).
  • Fator de Lucro: O melhor valor mais alto (1.15).
  • Payoff Esperado: O valor mais alto (29.28).
  • Fator de Recuperação: O valor mais alto (1.69).
  • Índice de Sharpe: O valor mais alto (1.71).


Conclusão

Devemos entender a importância do conceito de volatilidade no mercado financeiro aprendendo sobre o indicador técnico Chaikin Volatility, que pode ser útil para ler ou prever potenciais movimentos de mercado. Assumimos que entenderíamos como o indicador CHV funciona, como ele pode ser calculado e como podemos usá-lo a nosso favor nos mercados financeiros.

Assumimos que entendemos duas estratégias simples e como otimizar nossa estratégia para obter melhores resultados ao acompanhá-la de outra ferramenta técnica, como a média móvel. Aprendemos a criar nosso próprio indicador CHV usando o MQL5 para poder adicionar nossas preferências a ele e aprendemos a usar esse indicador CHV personalizado em um sistema de negociação baseado nas estratégias mencionadas.

  • Crossover do CHV:
  • Crossover do CHV e da MA:

Também aprendemos a criar um sistema de negociação para trabalhar e colocar posições automaticamente com base nas estratégias mencionadas, criando EAs, testando-os e vendo como podemos obter melhores insights e resultados ao acompanhar outra ferramenta técnica, como a Média Móvel, como uma otimização por meio do Strategy Tester.

Eu encorajo você a experimentar e testar outras ferramentas possíveis para obter melhores insights, pois a melhoria nunca termina e é uma função infinita, não apenas na negociação, mas também em nossas vidas. Espero que você tenha gostado de ler este artigo e o tenha achado útil em sua jornada de negociação. Se quiser ler mais artigos sobre como construir sistemas de negociação e entender o conceito principal por trás deles, você pode ler meus artigos anteriores sobre esses tópicos e outros relacionados à programação MQL5.


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

Arquivos anexados |
Custom_CHV.mq5 (3.24 KB)
chvVal.mq5 (0.97 KB)
chvCrossover.mq5 (1.8 KB)
O Método de Agrupamento de Manipulação de Dados: Implementando o Algoritmo Combinatório em MQL5 O Método de Agrupamento de Manipulação de Dados: Implementando o Algoritmo Combinatório em MQL5
Neste artigo, continuamos nossa exploração da família de algoritmos do Método de Agrupamento de Manipulação de Dados, com a implementação do Algoritmo Combinatório, juntamente com sua versão refinada, o Algoritmo Combinatório Seletivo em MQL5.
Redes neurais de maneira fácil (Parte 88): Codificador denso de séries temporais (TiDE) Redes neurais de maneira fácil (Parte 88): Codificador denso de séries temporais (TiDE)
O desejo de obter previsões mais precisas leva os pesquisadores a complicar os modelos de previsão. Isso, por sua vez, aumenta os custos de treinamento e manutenção do modelo. Mas será que isso sempre é justificado? Neste artigo, proponho que você conheça um algoritmo que utiliza a simplicidade e a velocidade dos modelos lineares, e demonstra resultados no nível dos melhores com uma arquitetura mais complexa.
Técnicas do MQL5 Wizard que você deve conhecer (Parte 17): Negociação Multimoedas Técnicas do MQL5 Wizard que você deve conhecer (Parte 17): Negociação Multimoedas
Negociar com múltiplas moedas não está disponível por padrão quando um expert advisor é montado através do assistente. Examinamos dois hacks possíveis que os traders podem fazer ao tentar testar suas ideias com mais de um símbolo ao mesmo tempo.
Superando Desafios de Integração com ONNX Superando Desafios de Integração com ONNX
ONNX é uma ótima ferramenta para integrar códigos complexos de IA entre diferentes plataformas, sendo uma ferramenta excelente, mas que vem com alguns desafios que devem ser superados para aproveitar ao máximo suas capacidades. Neste artigo, discutimos os problemas mais comuns que você pode enfrentar e como mitigá-los.