English Русский 中文 Español Deutsch 日本語
preview
Construindo e testando sistemas de negociação com o Canal Keltner

Construindo e testando sistemas de negociação com o Canal Keltner

MetaTrader 5Negociação | 15 julho 2024, 16:13
475 0
Mohamed Abdelmaaboud
Mohamed Abdelmaaboud

Introdução

O conceito de volatilidade no mercado financeiro é muito importante para entender e fazer funcionar a seu favor quando você está negociando no mercado. O principal objetivo deste artigo é ajudar você a economizar tempo fornecendo muitos resultados de testes para sistemas de negociação baseados no conceito de volatilidade usando o indicador técnico Canal Keltner para descobrir como ele pode funcionar como parte de seu sistema completo para medir volatilidade ou tomar medidas sob certas condições em relação a este importante conceito.

A coisa mais importante a entender é que você pode descobrir que precisa otimizar seu sistema de acordo com suas preferências para obter melhores resultados, então você precisa fazer seu trabalho e testar muitos aspectos diferentes de acordo com seus objetivos de negociação para encontrar a melhor configuração final para seu sistema.

A abordagem deste artigo será aprender como podemos criar nosso indicador personalizado Canal Keltner e sistemas de negociação para negociar estratégias simples de negociação e, em seguida, testá-los em diferentes ativos financeiros e compará-los para descobrir qual pode fornecer melhores resultados de acordo com nossos testes e otimização e tentaremos fornecer a melhor configuração possível. Cobriremos este artigo através dos seguintes tópicos:

Após os tópicos anteriores, seremos capazes de usar o Indicador Canal Keltner baseado em seu conceito principal. Após entender o indicador em detalhes, seremos capazes de criar sistemas de negociação baseados em estratégias simples. Depois disso, seremos capazes de testá-los e ver qual estratégia é melhor do que as outras com base em seus resultados. Espero que você ache este artigo útil para ajudá-lo a melhorar sua negociação e obter melhores resultados após aprender algo novo ou obter mais insights sobre qualquer ideia relacionada que melhore seus resultados de negociaçã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.


Definição de volatilidade

Nesta parte, entenderemos o que é volatilidade em geral e como ela é importante no mercado financeiro e de negociação. A volatilidade é um conceito estatístico que pode ser usado para medir a dispersão dos retornos dos ativos financeiros e quando a volatilidade aumenta, o risco também aumenta. Podemos dizer que a volatilidade é um conceito que também se refere a grandes oscilações nos mercados em ambas as direções e esse movimento de oscilação é medido pela oscilação em torno do preço médio.

Há muitas razões que resultam na volatilidade do mercado, como as seguintes:

  • Sentimento do mercado: a volatilidade do mercado pode ser afetada pelas emoções dos negociadores.
  • Lucros: relatórios de lucros podem afetar a volatilidade do mercado com base em seus resultados.
  • Eventos econômicos e indicadores: eventos econômicos importantes e indicadores também podem levar à volatilidade no mercado, como inflação, PIB e notícias de emprego.
  • Liquidez: há uma relação entre liquidez e volatilidade no mercado; quando a liquidez é baixa, a volatilidade aumenta.

Quando se trata de medir a volatilidade, podemos ver que há muitas maneiras ou métodos que podem ser usados nesse contexto, como coeficiente beta e desvios padrão. Há também muitos indicadores técnicos que podem ser usados para medir a volatilidade no mercado, como Bandas de Bollinger, Faixa Verdadeiramente Média (ATR), Índice de Volatilidade (VIX) e o Canal Keltner, que é o nosso tópico neste artigo. Medir a volatilidade pode ser muito útil para avaliar a flutuação do ativo financeiro.

Há também muitos tipos de volatilidade, como volatilidade implícita e volatilidade histórica.


Definição do Canal Keltner

Nesta parte, aprenderemos mais sobre o indicador Canal Keltner em detalhes, como usá-lo e como podemos calcular este indicador para entender como podemos usá-lo a nosso favor. O indicador Canal Keltner é um indicador de volatilidade que contém duas bandas acima e abaixo dos preços e uma média móvel entre elas.

O indicador Canal Keltner foi introduzido pela primeira vez por Chester Keltner na década de 1960 em seu livro Como Ganhar Dinheiro em Commodities. Ele usava a média móvel simples e a faixa de alta/baixa em seu cálculo, mas evoluiu para a forma que é comumente usada hoje, utilizando a Faixa Verdadeiramente Média (ATR) em seu cálculo. A configuração típica para a média móvel é de 20 períodos; as bandas superior e inferior são calculadas como duas vezes o ATR acima e abaixo da EMA, e essas configurações podem ser ajustadas de acordo com as preferências do usuário e objetivos de negociação.

O Canal Keltner refere-se a tendência de alta quando o preço atinge a banda superior e tendência de baixa quando o preço atinge a banda inferior porque pode ser usado para identificar a direção da tendência. As bandas também podem ser usadas como suporte e resistência quando os preços se movem entre elas sem uma tendência clara de alta ou baixa. Em resumo, o Canal Keltner é um indicador técnico que mede a volatilidade dos ativos financeiros usando a média móvel exponencial e a faixa verdadeira média. 

A seguir, como podemos calcular o indicador Canal Keltner:

  • Calcular a média móvel exponencial que será a linha do meio do indicador.
  • Calcular a faixa verdadeira média para usá-la no cálculo das bandas.
  • Calcular a banda superior igual à EMA e adicionar o resultado da multiplicação de 2 e ATR.
  • Calcular a banda inferior igual à EMA e subtrair o resultado da multiplicação de 2 e ATR.

Portanto,

Linha do Meio do Canal Keltner = Média Móvel Exponencial (EMA)

Banda Superior do Canal Keltner = Média Móvel Exponencial (EMA) + 2 * Faixa Verdadeiramente Média (ATR)

Banda Inferior do Canal Keltner = Média Móvel Exponencial (EMA) - 2 * Faixa Verdadeiramente Média (ATR)


Estratégias do Canal Keltner

De acordo com o que entendemos sobre como podemos usar o indicador Canal Keltner, usando as bandas como suporte ou resistência ou considerando tendência de alta ao se aproximar da banda superior e tendência de baixa ao se aproximar da banda inferior, usaremos duas estratégias simples:

  • Rebote nas bandas: colocaremos uma ordem de compra ao rebater acima da banda inferior e uma ordem de venda ao rebater abaixo da banda superior.
  • Rompimento das bandas: colocaremos uma ordem de compra ao romper a banda superior e uma ordem de venda ao romper abaixo da banda inferior.

Estratégia um: Rebote nas bandas

De acordo com o que entendemos sobre o indicador Canal Keltner, podemos usá-lo detectando sinais de compra e venda com base na posição do preço de fechamento e nas bandas dos indicadores. Abriremos uma ordem de compra quando o fechamento anterior ao último preço de fechamento fechar abaixo da banda inferior anterior e, ao mesmo tempo, o último preço de fechamento fechar acima da banda inferior. A ordem de venda será aberta quando o fechamento anterior ao último preço de fechamento fechar acima da banda superior e, ao mesmo tempo, o último preço de fechamento fechar abaixo da banda superior.

Simplificando,

O fechamento anterior ao último < a banda inferior e o último preço de fechamento > valor da banda inferior ==> sinal de compra

O fechamento anterior ao último > a banda superior e o último preço de fechamento < valor da banda superior ==> sinal de vendas

Estratégia dois: Rompimento das bandas
De acordo com esta estratégia, colocaremos uma ordem enquanto ocorre o rompimento; colocaremos uma ordem de compra quando o fechamento anterior ao último preço de fechamento estiver abaixo da banda superior anterior ao último e, ao mesmo tempo, o último preço de fechamento fechar acima da última banda superior e vice-versa, colocaremos uma ordem de venda quando o fechamento anterior ao último preço estiver acima da banda inferior anterior ao último e, ao mesmo tempo, o último preço de fechamento fechar abaixo da última banda inferior.

Simplificando,

O fechamento anterior ao último < a banda superior e o último preço de fechamento > valor da banda superior ==> sinal de compra

O fechamento anterior ao último > a banda inferior e o último preço de fechamento < valor da banda inferior ==> sinal de vendas


Sistema de negociação com o Canal Keltner

Nesta parte, criaremos um sistema de negociação para colocar ordens automaticamente com base na estratégia mencionada anteriormente. Primeiro, criaremos o indicador personalizado para calcular o indicador Canal Keltner para ser usado posteriormente para criar nosso sistema de negociação; o seguinte é sobre um método para codificar o indicador:

Usando o pré-processador #property para determinar o local do indicador e usaremos indicator_chart_window para mostrar o indicador no gráfico.

#property indicator_chart_window

Determinando os buffers do indicador usando o valor do identificador de indicator_buffers, definiremos o número 3 e, para determinar o número de gráficos, também definiremos com 3.

#property indicator_buffers 3
#property indicator_plots 3

Definindo as propriedades dos indicadores em termos de tipo, estilo, largura, cor e rótulo para as linhas superior, média e inferior.

#property indicator_type1 DRAW_LINE
#property indicator_style1 STYLE_SOLID
#property indicator_width1 2
#property indicator_color1 clrRed
#property indicator_label1 "Keltner Upper Band"


#property indicator_type2 DRAW_LINE
#property indicator_style2 STYLE_SOLID
#property indicator_width2 1
#property indicator_color2 clrBlue
#property indicator_label2 "Keltner Middle Line"


#property indicator_type3 DRAW_LINE
#property indicator_style3 STYLE_SOLID
#property indicator_width3 2
#property indicator_color3 clrGreen
#property indicator_label3 "Keltner Lower Band"

Definindo a entrada para o indicador em termos de período da média móvel, multiplicador do canal, uso do ATR no cálculo das bandas, método ou modo da média móvel e tipo de preço.

input int      maPeriod            = 10;           // Moving Average Period
input double   multiInp             = 2.0;          // Channel multiplier
input bool     isAtr                 = false;        // ATR
input ENUM_MA_METHOD     maMode       = MODE_EMA;     // Moving Average Mode
input ENUM_APPLIED_PRICE priceType = PRICE_TYPICAL;// Price Type

Declarando variáveis globais, três arrays (superior, média e inferior), dois handles de média móvel e ATR, e minBars.

double upper[], middle[], lower[];
int maHandle, atrHandle;
static int minBars = maPeriod + 1;

Na função OnInit(), vincularemos o buffer do indicador com arrays usando a função SetIndexBuffer e seus parâmetros são:

  • index: para determinar o índice do buffer e será 0 para o superior, 1 para o médio e 2 para o inferior.
  • buffer[]: para determinar o array, será superior, médio e inferior.]
  • data_type: para determinar o que precisamos armazenar no indicador e pode ser um dos ENUM_INDEXBUFFER_TYPE, é INDICATOR_DATA por padrão e isso é o que usaremos.
   SetIndexBuffer(0,upper,     INDICATOR_DATA);
   SetIndexBuffer(1,middle,  INDICATOR_DATA);
   SetIndexBuffer(2,lower,  INDICATOR_DATA);

Definindo a flag AS_Series para arrays usando a função ArraySetAsSeries e seus parâmetros são:

  • array[]: para determinar o array por sua referência, usaremos os arrays superior, médio e inferior.
  • flag: para determinar a direção da indexação do array e retornará true em caso de sucesso ou false em caso de falha.
   ArraySetAsSeries(upper, true);
   ArraySetAsSeries(middle, true);
   ArraySetAsSeries(lower, true);

Definindo o nome do indicador usando a função IndicatorSetString e seus parâmetros são:

  • prop_id: para determinar o identificador, pode ser um dos ENUM_CUSTOMIND_PROPERTY_STRING, usaremos o INDICATOR_SHORTNAME para definir o nome do indicador.
  • prop_value: para determinar o nome desejado do indicador.
IndicatorSetString(INDICATOR_SHORTNAME,"Custom Keltner Channel " + IntegerToString(maPeriod));

Definindo os dígitos dos valores do indicador usando a função IndicatorSetInteger e seus parâmetros são os mesmos do IndicatorSetString, exceto que o tipo de dado do prop_value será em vez de string.

IndicatorSetInteger(INDICATOR_DIGITS,_Digits);

Definindo o handle da média móvel usando a função iMA e seus parâmetros são:

  • symbol: para especificar o nome do símbolo, usaremos NULL para ser aplicado ao símbolo atual.
  • period: para especificar o período e usaremos 0 para ser aplicado ao período atual.
  • ma_period: para especificar o período da média móvel, usaremos a entrada do usuário maPeriod.
  • ma_shift: para especificar o deslocamento horizontal, se necessário.
  • ma_method: para especificar o método da média móvel e usaremos a entrada do usuário maMode.
  • applied_price: para especificar o tipo de preço e usaremos a entrada do usuário priceType.
maHandle = iMA(NULL, <s4>0</s5>, maPeriod, <s6>0</s7>, maMode, priceType);

Definindo o ATR de acordo com a entrada do ATR, se for verdadeiro ou falso, para ser usado no cálculo das bandas ou não.

   if(isAtr)
     {
      atrHandle = iATR(NULL, 0, maPeriod);
      if(atrHandle == INVALID_HANDLE)
        {
         Print("Handle Error");
         return(INIT_FAILED);
        }
     }
   else
      atrHandle = INVALID_HANDLE;

Declarando a função indValue para especificar os buffers do indicador, média móvel, valores do meio, superior e inferior.

void indValue(const double& h[], const double& l[], int shift)
  {
   double ma[1];
   if(CopyBuffer(maHandle, 0, shift, 1, ma) <= 0)
      return;
   middle[shift] = ma[0];
   double average = AVG(h, l, shift);
   upper[shift]    = middle[shift] + average * multiInp;
   lower[shift] = middle[shift] - average * multiInp;
  }

Declarando a função AVG para calcular posições dos limites com base no multiplicador calculado.

double AVG(const double& High[],const double& Low[], int shift)
  {
   double sum = 0.0;
   if(atrHandle == INVALID_HANDLE)
     {
      for(int i = shift; i < shift + maPeriod; i++)
         sum += High[i] - Low[i];
     }
   else
     {
      double t[];
      ArrayResize(t, maPeriod);
      ArrayInitialize(t, 0);
      if(CopyBuffer(atrHandle, 0, shift, maPeriod, t) <= 0)
         return sum;
      for(int i = 0; i < maPeriod; i++)
         sum += t[i];
     }
   return sum / maPeriod;
  }

Na função OnCalculate, calcularemos os valores do indicador conforme o código a seguir.

   if(rates_total <= minBars)
      return 0;
   ArraySetAsSeries(close,true);
   ArraySetAsSeries(high, true);
   ArraySetAsSeries(low,  true);
   int limit = rates_total - prev_calculated;
   if(limit == 0)             
     {
     }
   else
      if(limit == 1)      
        {
         indValue(high, low, 1);
         return(rates_total);
        }
      else
         if(limit > 1)       
           {
            ArrayInitialize(middle, EMPTY_VALUE);
            ArrayInitialize(upper,    EMPTY_VALUE);
            ArrayInitialize(lower, EMPTY_VALUE);
            limit = rates_total - minBars;
            for(int i = limit; i >= 1 && !IsStopped(); i--)
               indValue(high, low, i);
            return(rates_total);
           }
   indValue(high, low, 0);
   return(rates_total);

Portanto, podemos encontrar o código completo em um bloco do indicador personalizado Canal Keltner da seguinte forma:

//+------------------------------------------------------------------+
//|                                       Custom_Keltner_Channel.mq5 |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots 3
#property indicator_type1 DRAW_LINE
#property indicator_style1 STYLE_SOLID
#property indicator_width1 2
#property indicator_color1 clrRed
#property indicator_label1 "Keltner Upper Band"
#property indicator_type2 DRAW_LINE
#property indicator_style2 STYLE_SOLID
#property indicator_width2 1
#property indicator_color2 clrBlue
#property indicator_label2 "Keltner Middle Line"
#property indicator_type3 DRAW_LINE
#property indicator_style3 STYLE_SOLID
#property indicator_width3 2
#property indicator_color3 clrGreen
#property indicator_label3 "Keltner Lower Band"
input int      maPeriod            = 10;           // Moving Average Period
input double   multiInp             = 2.0;          // Channel multiplier
input bool     isAtr                 = false;        // ATR
input ENUM_MA_METHOD     maMode       = MODE_EMA;     // Moving Average Mode
input ENUM_APPLIED_PRICE priceType = PRICE_TYPICAL;// Price Type
double upper[], middle[], lower[];
int maHandle, atrHandle;
static int minBars = maPeriod + 1;
//+------------------------------------------------------------------+
int OnInit()
  {
   SetIndexBuffer(0,upper, INDICATOR_DATA);
   SetIndexBuffer(1,middle, INDICATOR_DATA);
   SetIndexBuffer(2,lower, INDICATOR_DATA);
   ArraySetAsSeries(upper, true);
   ArraySetAsSeries(middle, true);
   ArraySetAsSeries(lower, true);
   IndicatorSetString(INDICATOR_SHORTNAME,"Custom Keltner Channel " + IntegerToString(maPeriod));
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
   maHandle = iMA(NULL, 0, maPeriod, 0, maMode, priceType);
   if(isAtr)
     {
      atrHandle = iATR(NULL, 0, maPeriod);
      if(atrHandle == INVALID_HANDLE)
        {
         Print("Handle Error");
         return(INIT_FAILED);
        }
     }
   else
      atrHandle = INVALID_HANDLE;
   return INIT_SUCCEEDED;
  }
void indValue(const double& h[], const double& l[], int shift)
  {
   double ma[1];
   if(CopyBuffer(maHandle, 0, shift, 1, ma) <= 0)
      return;
   middle[shift] = ma[0];
   double average = AVG(h, l, shift);
   upper[shift]    = middle[shift] + average * multiInp;
   lower[shift] = middle[shift] - average * multiInp;
  }
double AVG(const double& High[],const double& Low[], int shift)
  {
   double sum = 0.0;
   if(atrHandle == INVALID_HANDLE)
     {
      for(int i = shift; i < shift + maPeriod; i++)
         sum += High[i] - Low[i];
     }
   else
     {
      double t[];
      ArrayResize(t, maPeriod);
      ArrayInitialize(t, 0);
      if(CopyBuffer(atrHandle, 0, shift, maPeriod, t) <= 0)
         return sum;
      for(int i = 0; i < maPeriod; i++)
         sum += t[i];
     }
   return sum / maPeriod;
  }
//+------------------------------------------------------------------+
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[])
  {
   if(rates_total <= minBars)
      return 0;
   ArraySetAsSeries(close,true);
   ArraySetAsSeries(high, true);
   ArraySetAsSeries(low,  true);
   int limit = rates_total - prev_calculated;
   if(limit == 0)             
     {
     }
   else
      if(limit == 1)      
        {
         indValue(high, low, 1);
         return(rates_total);
        }
      else
         if(limit > 1)       
           {
            ArrayInitialize(middle, EMPTY_VALUE);
            ArrayInitialize(upper,    EMPTY_VALUE);
            ArrayInitialize(lower, EMPTY_VALUE);
            limit = rates_total - minBars;
            for(int i = limit; i >= 1 && !IsStopped(); i--)
               indValue(high, low, i);
            return(rates_total);
           }
   indValue(high, low, 0);
   return(rates_total);
  }
//+------------------------------------------------------------------+

Depois de compilar este código, podemos encontrá-lo na pasta do indicador; após inseri-lo no gráfico, podemos encontrá-lo como o exemplo a seguir:

KCH_insert

Como podemos ver no gráfico anterior, temos um canal ao redor do preço que representa o indicador Canal Keltner. Agora precisamos criar nosso sistema de negociação usando este indicador com base nas estratégias mencionadas e podemos fazer isso da seguinte forma.

Agora precisamos criar um sistema de negociação para cada estratégia mencionada para automatizar a colocação de ordens de compra e venda com base no conceito delas.


Estratégia um: sistema de negociação de rebote nas bandas:

A primeira estratégia, como mencionamos, é considerar a abertura de negociações com base no rebote ao redor das bandas criando um EA para colocar ordens automaticamente. A seguir, como podemos codificar este sistema de negociação:

Incluiremos o arquivo de negociação usando o pré-processador include

#include <trade/trade.mqh>

Declarando entradas para período da média móvel, multiplicador do canal, ATR para cálculo das bandas ou não, modo da média móvel, tipo de preço, tamanho do lote, pips de stop loss e pips de take profit.

input int      maPeriod            = 10;           // Moving Average Period
input double   multiInp             = 2.0;          // Channel multiplier
input bool     isAtr                 = false;        // ATR
input ENUM_MA_METHOD     maMode       = MODE_EMA;     // Moving Average Mode
input ENUM_APPLIED_PRICE priceType = PRICE_TYPICAL;// Price Type
input double      lotSize=1;
input double slPips = 150;
input double tpPips = 300;

Declarando variáveis globais para Keltner, barTotal e objeto de negociação

int keltner;
int barsTotal;
CTrade trade;

Na função OnInit(), definiremos a variável barsTotal para ser usada posteriormente na avaliação se há um novo bar ou não usando a função iBars e seus parâmetros são:

  • symbol: para determinar o símbolo a ser aplicado e usaremos _Symbol para ser aplicado ao símbolo atual.
  • timeframe: para determinar o período e usaremos PERIOD_CURRENT para ser aplicado ao período atual.
barsTotal=iBars(_Symbol,PERIOD_CURRENT);

Definindo a variável Keltner para ser usada como o handle do indicador usando a função iCustom e seus parâmetros são:

  • symbol: para determinar o nome do símbolo e _Symbl será usado para ser aplicado ao símbolo atual.
  • period: para definir o período, usaremos PERIOD_CURRENT.
  • name: para especificar o nome do indicador.
  • ...: lista de entradas do indicador.
keltner = iCustom(_Symbol,PERIOD_CURRENT,"Custom_Keltner_Channel",maPeriod,multiInp, isAtr, maMode, priceType);

Na função OnDeinit, imprimiremos uma mensagem ao remover o EA

Print("EA is removed");

Na função OnTick(), declararemos e definiremos uma variável inteira chamada bars para ser comparada com barsTotal a fim de verificar se há um novo candle.

int bars=iBars(_Symbol,PERIOD_CURRENT);

Comparando barsTotal com bars para ver se barsTotal é menor que bars

if(barsTotal < bars)

Se barsTotal for menor que bars, precisamos atribuir o valor de bars a barsTotal

barsTotal=bars;

Em seguida, declare os três arrays para superior, médio e inferior

double upper[], middle[], lower[];

Obtendo dados dos buffers do indicador usando a função CopyBuffer e seus parâmetros são:

  • indicator_handle: para determinar o handle do indicador, usaremos Keltner para superior, médio e inferior.
  • buffer_num: para especificar o número do buffer do indicador e será 0 para superior, 1 para médio e 2 para inferior.
  • start_pos: para especificar a posição a partir da qual começar a contar e usaremos 0.
  • count: para especificar a quantidade que precisamos copiar e usaremos 3.
  • buffer[]: para especificar o array de destino para copiar e usaremos os arrays superior, médio e inferior.
      CopyBuffer(keltner,0,0,3,upper);
      CopyBuffer(keltner,1,0,3,middle);
      CopyBuffer(keltner,2,0,3,lower);

Definindo a flag AS_SERIES usando a função ArraySetAsSeries

      ArraySetAsSeries(upper,true);
      ArraySetAsSeries(middle,true);
      ArraySetAsSeries(lower,true);

Declarando e definindo prevUpper, middle e lower values para o valor anterior ao último dos valores do indicador.

      double prevUpperValue = NormalizeDouble(upper[2], 5);
      double prevMiddleValue = NormalizeDouble(middle[2], 5);
      double prevLowerValue = NormalizeDouble(lower[2], 5);

Declarando e definindo upper, middle e lower values para o valor final dos valores do indicador

      double upperValue = NormalizeDouble(upper[1], 5);
      double middleValue = NormalizeDouble(middle[1], 5);
      double lowerValue = NormalizeDouble(lower[1], 5);

Declarando e definindo o último e o anterior ao último dos preços de fechamento usando a função iClose e seus parâmetros são:

  • symbol: para especificar o nome do símbolo.
  • timeframe: para especificar o período a ser aplicado.
  • shift: para especificar se precisamos de um deslocamento para trás ou não, especificando o índice.
      double lastClose=iClose(_Symbol,PERIOD_CURRENT,1);
      double prevLastClose=iClose(_Symbol,PERIOD_CURRENT,2);

Definindo condições da estratégia para colocar uma ordem de compra se o fechamento anterior ao último preço de fechamento for menor que o valor da banda inferior anterior ao último e o último preço de fechamento for maior que o valor da banda inferior.

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

Definindo condições da estratégia para colocar uma ordem de venda se o fechamento anterior ao último preço de fechamento for maior que o valor da banda superior anterior ao último e o último preço de fechamento for menor que o valor da banda superior.

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

Portanto, o código completo em um bloco para criar um sistema de negociação baseado na estratégia de rebote nas bandas é o seguinte:

//+------------------------------------------------------------------+
//|                                       Keltner_Trading_System.mq5 |
//+------------------------------------------------------------------+
#include <trade/trade.mqh>
input int      maPeriod            = 10;           // Moving Average Period
input double   multiInp             = 2.0;          // Channel multiplier
input bool     isAtr                 = false;        // ATR
input ENUM_MA_METHOD     maMode       = MODE_EMA;     // Moving Average Mode
input ENUM_APPLIED_PRICE priceType = PRICE_TYPICAL;// Price Type
input double      lotSize=1;
input double slPips = 150;
input double tpPips = 300; 
int keltner;
int barsTotal;
CTrade trade;
int OnInit()
  {
   barsTotal=iBars(_Symbol,PERIOD_CURRENT);
   keltner = iCustom(_Symbol,PERIOD_CURRENT,"Custom_Keltner_Channel",maPeriod,multiInp, isAtr, maMode, priceType);
   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 upper[], middle[], lower[];
      CopyBuffer(keltner,0,0,3,upper);
      CopyBuffer(keltner,1,0,3,middle);
      CopyBuffer(keltner,2,0,3,lower);
      ArraySetAsSeries(upper,true);
      ArraySetAsSeries(middle,true);
      ArraySetAsSeries(lower,true);
      double prevUpperValue = NormalizeDouble(upper[2], 5);
      double prevMiddleValue = NormalizeDouble(middle[2], 5);
      double prevLowerValue = NormalizeDouble(lower[2], 5);
      double upperValue = NormalizeDouble(upper[1], 5);
      double middleValue = NormalizeDouble(middle[1], 5);
      double lowerValue = NormalizeDouble(lower[1], 5);
      double lastClose=iClose(_Symbol,PERIOD_CURRENT,1);
      double prevLastClose=iClose(_Symbol,PERIOD_CURRENT,2);
      if(prevLastClose<prevLowerValue && lastClose>lowerValue)
        {
         double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
         double slVal = lowerValue - slPips*_Point;
         double tpVal = middleValue + tpPips*_Point;
         trade.Buy(lotSize,_Symbol,ask,slVal,tpVal);
        }
      if(prevLastClose>prevUpperValue && lastClose<upperValue)
        {
         double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
         double slVal = upperValue + slPips*_Point;
         double tpVal = middleValue - tpPips*_Point;
         trade.Sell(lotSize,_Symbol,bid,upperValue,tpVal);
        }
     }
  }
//+------------------------------------------------------------------+


Estratégia dois: sistema de negociação de rompimento das bandas:

A primeira estratégia, como mencionamos, é considerar a abertura de negociações com base no rompimento acima ou abaixo das bandas criando um EA para colocar ordens automaticamente. A seguir, as diferenças ao codificar este sistema de negociação:

Condições para colocar uma ordem de compra apenas quando o EA encontrar primeiro o fechamento anterior ao último fechamento abaixo da banda superior anterior ao último, depois o último fechamento acima da banda superior.

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

Condições para colocar uma ordem de venda apenas quando o EA encontrar primeiro o fechamento anterior ao último fechamento acima da banda inferior anterior ao último, depois o último fechamento abaixo da banda inferior.

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

Portanto, o código completo para criar um sistema de negociação baseado na estratégia de rompimento das bandas é o seguinte:

//+------------------------------------------------------------------+
//|                                      Keltner_Trading_System2.mq5 |
//+------------------------------------------------------------------+
#include <trade/trade.mqh>
input int      maPeriod            = 10;           // Moving Average Period
input double   multiInp             = 2.0;          // Channel multiplier
input bool     isAtr                 = false;        // ATR
input ENUM_MA_METHOD     maMode       = MODE_EMA;     // Moving Average Mode
input ENUM_APPLIED_PRICE priceType = PRICE_TYPICAL;// Price Type
input double      lotSize=1;
input double slPips = 150;
input double tpPips = 500; 
int keltner;
int barsTotal;
CTrade trade;
int OnInit()
  {
   barsTotal=iBars(_Symbol,PERIOD_CURRENT);
   keltner = iCustom(_Symbol,PERIOD_CURRENT,"Custom_Keltner_Channel",maPeriod,multiInp, isAtr, maMode, priceType);
   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 upper[], middle[], lower[];
      CopyBuffer(keltner,0,0,3,upper);
      CopyBuffer(keltner,1,0,3,middle);
      CopyBuffer(keltner,2,0,3,lower);
      ArraySetAsSeries(upper,true);
      ArraySetAsSeries(middle,true);
      ArraySetAsSeries(lower,true);
      double prevUpperValue = NormalizeDouble(upper[2], 5);
      double prevMiddleValue = NormalizeDouble(middle[2], 5);
      double prevLowerValue = NormalizeDouble(lower[2], 5);
      double upperValue = NormalizeDouble(upper[1], 5);
      double middleValue = NormalizeDouble(middle[1], 5);
      double lowerValue = NormalizeDouble(lower[1], 5);
      double lastClose=iClose(_Symbol,PERIOD_CURRENT,1);
      double prevLastClose=iClose(_Symbol,PERIOD_CURRENT,2);
      if(prevLastClose<prevUpperValue && lastClose>upperValue)
        {
         double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
         double slVal = upperValue - slPips*_Point;
         double tpVal = upperValue + tpPips*_Point;
         trade.Buy(lotSize,_Symbol,ask,slVal,tpVal);
        }
      if(prevLastClose>prevLowerValue && lastClose<lowerValue)
        {
         double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
         double slVal = lowerValue + slPips*_Point;
         double tpVal = lowerValue - tpPips*_Point;
         trade.Sell(lotSize,_Symbol,bid,upperValue,tpVal);
        }
     }
  }
//+------------------------------------------------------------------+

Agora, testaremos esses EAs de duas estratégias de negociação no ouro (XAUUSD), (EURUSD), (GBPUSD) usando o período de 1 hora com as configurações padrão de entradas para o período de 1º de janeiro de 2023 a 31 de dezembro de 2023,

Focaremos nas seguintes medições-chave para fazer uma comparação entre os dois:

  • 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 quão bem a estratégia testada se recupera após experimentar perdas. O 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 sem risco. O Índice de Sharpe mais alto é o melhor.


Estratégia um: Teste de rebote nas bandas:

Teste de XAUUSD

Podemos encontrar os resultados do teste de (XAUUSD) da seguinte forma:

gráfico

backtest

backtest2

Como podemos ver nos resultados anteriores do teste de XAUUSD, temos figuras importantes no teste, conforme a seguir

  • Lucro Líquido: 11918.60 USD.
  • DD Relativo do Saldo: 3.67%.
  • Fator de Lucro: 1.36.
  • Payoff Esperado: 75.91.
  • Fator de Recuperação: 2.85.
  • Índice de Sharpe: 4.06.

Teste de EURUSD

Podemos encontrar os resultados do teste de (EURUSD) da seguinte forma:

gráfico

backtest

backtest2

Como podemos ver nos resultados anteriores do teste de EURUSD, temos figuras importantes no teste, conforme a seguir

  • Lucro Líquido: 2221.20 USD.
  • DD Relativo do Saldo: 2.86%.
  • Fator de Lucro: 1.11.
  • Payoff Esperado: 13.63.
  • Fator de Recuperação: 0.68
  • Índice de Sharpe: 1.09.

Teste de GBPUSD

Podemos encontrar os resultados do teste de (GBPUSD) da seguinte forma:

gráfico

backtest

backtest2

Como podemos ver nos resultados anteriores do teste de GBPUSD, temos figuras importantes no teste, conforme a seguir

  • Lucro Líquido: -1389.40 USD.
  • DD Relativo do Saldo: 4.56%.
  • Fator de Lucro: 0.94.
  • Payoff Esperado: -8.91.
  • Fator de Recuperação: -0.28.
  • Índice de Sharpe: -0.78.


Estratégia dois: Teste de rompimento das bandas:

Teste de XAUUSD

Podemos encontrar gráficos para os resultados do teste de (XAUUSD) da seguinte forma:

gráfico

backtest

backtest2

Como podemos ver nos resultados anteriores do teste de XAUUSD, temos figuras importantes no teste, conforme a seguir

  • Lucro Líquido: -11783 USD.
  • DD Relativo do Saldo: 12.89%.
  • Fator de Lucro: 0.56.
  • Payoff Esperado: -96.58.
  • Fator de recuperação: -0.83
  • Índice de Sharpe: -5.00.

Teste de EURUSD

Podemos encontrar gráficos para os resultados do teste de (EURUSD) da seguinte forma:

gráfico

backtest

backtest2

Como podemos ver nos resultados anteriores do teste de EURUSD, temos figuras importantes no teste, conforme a seguir

  • Lucro Líquido: -1358.30 USD.
  • DD Relativo do Saldo: 6.53%.
  • Fator de Lucro: 0.94.
  • Payoff Esperado: -8.54.
  • Fator de Recuperação: -0.20.
  • Índice de Sharpe: -0.59.

Teste de GBPUSD

Podemos encontrar gráficos para os resultados do teste de (GBPUSD) da seguinte forma:

gráfico

backtest

backtest2

Como podemos ver nos resultados anteriores do teste de GBPUSD, temos figuras importantes no teste, conforme a seguir

  • Lucro Líquido: -3930.60 USD.
  • DD Relativo do Saldo: 5.06%.
  • Fator de Lucro: 0.84.
  • Payoff Esperado: -25.69.
  • Fator de Recuperação: -0.75.
  • Índice de Sharpe: -2.05.

De acordo com o que vemos nos testes de estratégias anteriores para mais de um instrumento, podemos encontrar todos os resultados em uma tabela para compará-los facilmente conforme abaixo:

all_results2

Com base na tabela acima, podemos encontrar os melhores valores que correspondem à estratégia testada e ao período da seguinte forma:
  • Lucro Líquido: O melhor valor mais alto (11918.60 USD) é mostrado com a estratégia de rebote nas bandas quando testado no ativo XAUUSD.
  • DD Relativo do Saldo: O melhor valor mais baixo (2.86 %) é mostrado com a estratégia de rebote nas bandas quando testado no ativo EURUSD.
  • Fator de Lucro: O melhor valor mais alto (1.36) é mostrado com a estratégia de rebote nas bandas quando testado no ativo XAUUSD.
  • Payoff Esperado: O valor mais alto (75.91) é mostrado com a estratégia de rebote nas bandas quando testado no ativo XAUUSD
  • Fator de Recuperação: O valor mais alto (2.85) é mostrado com a estratégia de rebote nas bandas quando testado no ativo XAUUSD
  • Índice de Sharpe: O valor mais alto (4.06) é mostrado com a estratégia de rebote nas bandas quando testado no ativo XAUUSD.

Como podemos ver, a melhor estratégia é a estratégia de rebote nas bandas com XAUUSD ou otimizar estratégias e testá-las novamente de acordo com suas preferências para atender aos seus objetivos de negociação se você quiser ver melhores resultados e configurações.


Conclusão

Como traders, é muito importante ter um sistema de negociação confiável e, se esse sistema de negociação incluir e medir todos os aspectos importantes, como volatilidade e outros, isso aumenta sua confiabilidade.

Neste artigo, tentamos fornecer os resultados dos testes de estratégias simples baseadas no indicador Canal Keltner para dar uma ideia de como você pode incorporar ou usar o sistema de negociação com base neste conceito importante, após identificar o indicador em detalhes, como ele pode ser usado com base em seu conceito principal e como podemos calculá-lo.

Mencionamos as seguintes estratégias:

  • Rebote nas bandas: Colocaremos uma ordem de compra em um rebote acima da banda inferior e uma ordem de venda em um rebote abaixo da banda superior.
  • Rompimento das bandas: Colocamos uma ordem de compra quando a banda superior é rompida e uma ordem de venda quando a banda inferior é rompida.

Depois testamos essas estratégias e, com base nos resultados de cada uma, identificamos figuras importantes para muitos instrumentos financeiros (XAUUSD, EURUSD e GBPUSD) para saber qual é a melhor.

É crucial entender que essas estratégias mencionadas podem precisar de mais otimização e mais esforço para encontrar melhores resultados para nossos sistemas de negociação porque o objetivo principal deste artigo, como mencionamos anteriormente, é compartilhar o que podemos fazer compartilhando algumas ideias de negociação que podem abrir nossas mentes para construir ou desenvolver melhores sistemas de negociação.

Espero que tenha achado este artigo útil em sua jornada de aprendizado de negociação e codificação para obter resultados melhores, mais confiáveis e mais eficazes. Se achou este artigo útil e deseja ler mais sobre a construção de sistemas de negociação com base em diferentes estratégias e diferentes indicadores técnicos, especialmente os mais populares, você pode ler meus artigos anteriores verificando minha página de publicações para encontrar muitos artigos a esse respeito sobre os indicadores técnicos mais populares e espero que os ache úteis para você.

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

Usando algoritmos de otimização para configurar parâmetros de EA em tempo real Usando algoritmos de otimização para configurar parâmetros de EA em tempo real
O artigo discute os aspectos práticos do uso de algoritmos de otimização para encontrar os melhores parâmetros de EA em tempo real, bem como a virtualização das operações de negociação e da lógica do EA. O artigo pode ser usado como instrução para implementar algoritmos de otimização em um EA.
Balanceando riscos ao negociar múltiplos instrumentos simultaneamente Balanceando riscos ao negociar múltiplos instrumentos simultaneamente
Este artigo permitirá que um iniciante escreva uma implementação de um script do zero para balancear riscos ao negociar múltiplos instrumentos simultaneamente. Além disso, pode dar aos usuários experientes novas ideias para implementar suas soluções em relação às opções propostas neste artigo.
Operações baseadas em ângulos para traders Operações baseadas em ângulos para traders
Este artigo abordará operações baseadas em ângulos. Vamos examinar métodos para construir ângulos e utilizá-los no trading.
Desenvolvendo um sistema de Replay (Parte 56): Adequando os Módulos Desenvolvendo um sistema de Replay (Parte 56): Adequando os Módulos
Apesar dos módulos estarem se comunicando de maneira adequada, existe uma falha quando é tentado usar o indicador de mouse no serviço de replay. Precisamos corrigir isto agora, antes de dar o próximo passo. Além disto, havia uma falha que finalmente foi devidamente corrigida no código do indicador de mouse. Então esta versão finalmente se tornou estável, e devidamente finalizada.