Teste de padrões que surgem ao negociar cestas de pares de moedas. Parte I

Andrei Novichkov | 30 agosto, 2017


Introdução

Nos artigos anteriores sobre a aplicação de cestas de pares de moedas na negociação, nós examinamos o princípio de negociação, as maneiras de análise técnica e os padrões que podem ser detectados por essas maneiras. Claro, é impossível seguir esses métodos sem confirmar determinados parâmetros de padrão. Por exemplo, nós precisamos esclarecer valores específicos sobre os níveis de sobrevenda/sobrecompra. Aqui, nós analisaremos os parâmetros dos padrões detectados e tentaremos elaborar recomendações para os traders.

Ferramentas de pesquisa

Para o nosso trabalho, nós usaremos o "WPR combinado" que desenvolvemos anteriormente. Nós chegamos a aplicar ele várias vezes na série de artigos anteriores, e ele provou-se útil na detecção da maioria dos padrões.

Aumente o período do WPR de 14 a 20 para suavizar ligeiramente o gráfico do indicador. Isso permitirá que você "endireite" o gráfico sem perder a qualidade de exibição.

Nós realizaremos estudos em três tempos gráficos: D1, H4 e H1. Você pode obter os resultados para outros períodos usando os métodos descritos aqui. 

A terminologia básica e os princípios podem ser encontrados aqui.

Padrão de pesquisa

Vamos começar nossos estudos com o padrão #3 descrito aqui. O padrão é bem simples. Seu equivalente para um par de moeda separado é bem conhecido durante muito tempo. Ele é aplicado da seguinte maneira para negociar pares de moedas:

Um trader recebe um sinal de entrada em todos os pares de moedas de uma cesta se um nível de sobrecompra cruzou para baixo ou para sobrecompra se cruzou para cima pelo WPR combinado após o fechamento da vela (sinal com confirmação).

Onde nós podemos encontrar estes níveis de sobrevenda/sobrecompra? Nós podemos responder facilmente a esta pergunta para o WPR padrão em um par moeda separado:

  • Nível de sobrecompra: - 20%
  • Nível de sobreposição: - 80%

Isso nos dá um ponto de partida em nossa pesquisa. Nós vamos usar esses dados para esclarecer a localização dos níveis para o WPR combinado. Os resultados serão úteis não só para verificar o padrão em questão, mas também em outros casos similares. O método aplicado também será útil.

A linha indicadora deve estar acima do nível de sobrecompra ou abaixo da sobrevenda para romper uma delas. Vamos analisar o histórico para definir o número de potenciais entradas no mercado. Nós não vamos usar os indicadores nesta fase. Em vez disso, nós vamos aplicar os indicadores testIndexZig-Zag1.mq5 e testWPReur.mq5 desenvolvidos anteriormente. No testWPReur.mq5, nós simplesmente substituímos os dados de acordo com os componentes da cesta. Nós simplificaremos ligeiramente o código fonte do indicador testIndexZig-Zag1.mq5, já que nós já conhecemos a Máxima e o Mínima do indicador (de 100% a -100%):

#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_separate_window
#property indicator_buffers 6
#property indicator_plots   3
//--- desenha a Máxima
#property indicator_label1  "High"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrGreen
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- desenha a Mínima
#property indicator_label2  "Low"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrGreen
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- desenha o ZigZag
#property indicator_label3  "ZigZag"
#property indicator_type3   DRAW_SECTION
#property indicator_color3  clrRed
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1
//--- desenha a Direção
#property indicator_label4  "Direction"
#property indicator_type4   DRAW_LINE
#property indicator_style4  STYLE_SOLID
#property indicator_width4  1
//--- desenha LastHighBar
#property indicator_label5  "LastHighBar"
#property indicator_type5   DRAW_LINE
#property indicator_style5  STYLE_SOLID
#property indicator_width5  1
//--- desenha LastLowBar
#property indicator_label6  "LastLowBar"
#property indicator_type6   DRAW_LINE
#property indicator_style6  STYLE_SOLID
#property indicator_width6  1

#include <ZigZag\CSorceData.mqh>
#include <ZigZag\CZZDirection.mqh>
#include <ZigZag\CZZDraw.mqh>
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum EDirection
  {
   Dir_NBars=0,
   Dir_CCI=1
  };
//--- parâmetros de entrada
input EDirection  DirSelect=Dir_NBars;
input int                  CCIPeriod   =  14;
input ENUM_APPLIED_PRICE   CCIPrice    =  PRICE_TYPICAL;
input int                  ZZPeriod=14;

string               name;

CZZDirection*dir;
CZZDraw*zz;

//--- buffers dos indicador
double         HighBuffer[];
double         LowBuffer[];
double         ZigZagBuffer[];
double         DirectionBuffer[];
double         LastHighBarBuffer[];
double         LastLowBarBuffer[];
//+------------------------------------------------------------------+
//| Função de inicialização do indicador personalizado               |
//+------------------------------------------------------------------+
int h;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
   switch(DirSelect)
     {
      case Dir_NBars:
         dir=new CNBars(ZZPeriod);
         break;
      case Dir_CCI:
         dir=new CCCIDir(CCIPeriod,CCIPrice);
         break;
     }
   if(!dir.CheckHandle())
     {
      Alert("Erro ao baixar o indicator 2");
      return(INIT_FAILED);
     }
   zz=new CSimpleDraw();
//--- mapeamento dos buffers dos indicadores
   SetIndexBuffer(0,HighBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,LowBuffer,INDICATOR_DATA);
   SetIndexBuffer(2,ZigZagBuffer,INDICATOR_DATA);
   SetIndexBuffer(3,DirectionBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(4,LastHighBarBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(5,LastLowBarBuffer,INDICATOR_CALCULATIONS);
   name = _Symbol + TimeFrameToShortString(Period()) + ".txt";
   h=FileOpen(name,FILE_CSV|FILE_WRITE|FILE_ANSI,',');
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {

   if(CheckPointer(dir)==POINTER_DYNAMIC)
     {
      delete(dir);
     }
   if(CheckPointer(zz)==POINTER_DYNAMIC)
     {
      delete(zz);
     }
  }
//+------------------------------------------------------------------+
//| Função de iteração do indicador personalizado                    |
//+------------------------------------------------------------------+
int ind=0;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[]
                )
  {
   int start;

   if(prev_calculated==0)
     {
      start=0;
     }
   else
     {
      start=prev_calculated-1;
     }

   for(int i=start;i<rates_total;i++)
     {
      HighBuffer[i]=price[i];
      LowBuffer[i]=price[i];
     }

   int rv;
   rv=dir.Calculate(rates_total,
                    prev_calculated,
                    HighBuffer,
                    LowBuffer,
                    DirectionBuffer);
   if(rv==0)return(0);
   zz.Calculate(rates_total,
                prev_calculated,
                HighBuffer,
                LowBuffer,
                DirectionBuffer,
                LastHighBarBuffer,
                LastLowBarBuffer,
                ZigZagBuffer);

   if(ind<= 10) ind++;
   if(ind == 10)
     {
      double mx=100,mn=-100;
      double lg;
      lg=mx-mn;
      lg/=100;
      double levels[100];
      int    count[100];
      ArrayInitialize(count,0);
      for(int i=1; i<101; i++) levels[i-1]=NormalizeDouble(lg*i + mn,_Digits);
      for(int i=0;i<rates_total;i++)
        {
         if(ZigZagBuffer[i]==0 || ZigZagBuffer[i]==EMPTY_VALUE) continue;
         else 
           {
            for(int j=0; j<100; j++) 
              {
               if(ZigZagBuffer[i]<levels[j]) 
                 {
                  count[j]++;
                  break;
                 }
              }
           }
        }
      for(int i=0; i<100; i++)
        {
         FileWrite(h,i,levels[i],count[i]);
        }
      FileClose(h);
      Print("Trabalho finalizado: ",name);
     }
   return(rates_total);
  }
//+------------------------------------------------------------------+


string TimeFrameToShortString(ENUM_TIMEFRAMES period)
{
   switch (period )
   {
      case PERIOD_M1:  return ("M1");
      case PERIOD_M2:  return ("M2");
      case PERIOD_M3:  return ("M3");
      case PERIOD_M4:  return ("M4");
      case PERIOD_M5:  return ("M5");
      case PERIOD_M6:  return ("M6");
      case PERIOD_M10: return ("M10");
      case PERIOD_M12: return ("M12");
      case PERIOD_M15: return ("M15");
      case PERIOD_M20: return ("M20");
      case PERIOD_M30: return ("M30");
      case PERIOD_H1:  return ("H1");
      case PERIOD_H2:  return ("H2");
      case PERIOD_H3:  return ("H3");
      case PERIOD_H4:  return ("H4");
      case PERIOD_H6:  return ("H6");
      case PERIOD_H8:  return ("H8");
      case PERIOD_H12: return ("H12");
      case PERIOD_D1:  return ("D1");
      case PERIOD_W1:  return ("W1");
      case PERIOD_MN1: return ("MN1");
   }
   return ("");
} 

Como mencionado anteriormente, o código principal deste indicador foi desenvolvido por um colega muito respeitado chamado Dmitry Fedoseev e gentilmente fornecido à comunidade neste artigo. Ambos os indicadores mencionados podem ser encontrados no arquivo Test.zip anexado abaixo. Nós temos as ferramentas necessárias, agora vamos descobrir quais os dados necessários.

Possível número de negociações

O intervalo do WPR combinado varia de -100% a +100%, então, por enquanto, nós assumiremos que o nível de sobrecompra é de +60%, enquanto o de sobrevenda é de -60%, o que corresponde ao valor padrão. Vamos descobrir quantas vezes o indicador ultrapassou os níveis de sobrecompra/sobrevenda. Para fazer isso, nós devemos usar o método descrito aqui:

  • Aplique o indicador testIndexZig-Zag1.mq5 ao gráfico WPR combinado (testWPReur.mq5). Nosso objetivo é determinar o número de valores extremos que excedem os níveis de +70% e +80% ou -70% e -80%, conforme a figura abaixo. Observe a área do problema marcada como um retângulo em azul. Por enquanto, esses valores extremos são incluídos no cálculo, embora nós classificaremos esses valores no futuro:

  • O indicador testIndexZig-Zag1.mq5 aplicado divide a faixa de indicadores testWPReur.mq5 nos intervalos de 1% e define o número de valores extremos que se enquadram em cada intervalo. Os resultados são enviados para o arquivo. O cálculo é repetido para todos os cronogramas selecionados. Depois disso, nós alteramos os dados no conteúdo da cesta em testWPReur.mq5 e continuamos nosso trabalho com a próxima cesta de moeda.

Para mais conveniência, os dados obtidos em todas as cestas e tempos gráficos selecionados foram organizados em uma tabela. A porção da tabela relativa a cesta do EUR é exibida abaixo. Vamos esclarecer o significado dos valores da linha e da coluna da tabela:

  • Num. — número do índice.
  • Indicador — valor do indicador em %. Por exemplo, a linha com o valor de -96 significa o intervalo de -96% a -98% do WPR combinado.
  • EUR — três colunas com o número dos valores extremos para cada período de tempo selecionado. Por exemplo, a linha Num.1 já mencionada com o indicador WPR combinado variando de 96% a 98% define que os seguintes números de valores extremos que se enquadram nesse intervalo foram encontrados no histórico: D1 - zero, H4 e H1 - um em cada um dos tempos gráficos.
  • Profundidade Histórica — profundidade histórica disponível para cálculos.
  • Contagem de negociação (80%) — número total de entradas possíveis para cada período de tempo. Por exemplo, a cesta do EUR no H4 oferece 83 entradas possíveis, o que significa que o indicador WPR combinado excedeu o valor de 80% ou foi inferior a -80% da quantidade especificada de vezes.
  • Contagem de negociação (70%) — mesmo parâmetro para o valor WPR combinado em 70%.
  • Total de negociação (80%) — número total de entradas potenciais para todas as cestas e tempos gráficos para o valor do WPR combinado em 80%.
  • Total de negociação (70%) — o mesmo para 70%.


EUR ----
Num. Indicador Período gráfico ----
D1 H4 H1 ----
0 -98 2 3 4 ----
1 -96 0 1 1 ----
2 -94 0 0 1 ----
3 -92 0 3 3 ----
4 -90 1 4 5 ----
5 -88 3 4 10 ----
6 -86 1 2 7 ----
7 -84 2 8 7 ----
8 -82 1 8 21 ----
9 -80 4 6 22 ----
---- ---- ---- ---- ---- ----
95 92 0 2 6 ----
96 94 0 1 4 ----
97 96 0 0 3 ----
98 98 0 3 0 ----
99 100 0 0 0 ----
Profundidade Histórica 09.11.2000 12.04.2005 17.01.2006 ----





----
Contagem de negociações (80%) 25 83 165 ----
Contagem de negociações (70%) 45 207 449 ----












Total de negociações (80%) 3793


Total de negociações (70%) 7885


A tabela pode ser encontrada no arquivo Pair.zip em anexo.

As duas últimas linhas da tabela contêm os valores de pesquisa. Este é um grande número de possíveis entradas no mercado, mesmo tendo em conta que parte dos sinais devem ser tratadas. Portanto, vamos deixar os níveis de sobrevenda/sobrecompra no mesmo lugar por enquanto. Tenha em mente que todos os valores encontrados (e já existentes) são de natureza probabilística e permitem correções.

Forma do padrão

Vamos definir a forma do padrão que precisamos identificar para entrar no mercado.

  • Um trader vende uma cesta de pares de moedas se o indicador WPR combinado romper o nível de sobrecompra +60% para baixo. No fechamento da vela, o valor do indicador não era inferior a +50%. A diminuição da linha indicadora deve ocorrer do valor não inferior a +70%. A segunda opção para este ponto é +80% e acima, enquanto que para o nível de sobrecompra, é +70%.
  • O caso de comprar uma cesta de pares de moedas é simétrico para o descrito.

Todos os três padrões destacados na imagem acima satisfazem essas condições. Nós recebemos um padrão "bonito" e esclarecedor com valores numéricos e condições que podem ser convertidos em um algoritmo.

Isso significa que nós precisamos de um Expert Advisor.

EA para testar o padrão

Primeiro, vamos lidar com a compra/venda da cesta. Nste artigo, você pode encontrar detalhes sobra negociação de cestas de moedas e estudar a tabela contendo conselhos práticos para cada cesta. Vamos usar essa tabela e implementar o mesmo princípio no código do EA.

Vamos mostrar mais uma vez os padrões que nós estamos procurando:

Padrão de destino
Sem padrão



Suponha que o nível de sobrevenda/sobrecompra possa mudar na faixa de 60-70%. Vamos verificá-lo para o número de negociações pelo padrão verificado, duração das negociações, rebaixamento e rentabilidade potencial. Nós não exigimos um lucro estável do EA por enquanto. Nosso objetivo é dar o primeiro passo para esclarecermos a forma do padrão. Portanto, nós não publicamos os relatórios de testes padrão, uma vez que não estamos interessados ​​na rentabilidade do EA, enquanto os dados que precisamos não estão incluídos nos relatórios padrão. Nos focaremos em exibir os resultados obtidos.

Nós vamos iniciar nossa análise da cesta de moedas pelo USD colocando o próximo EA no EURUSD nos tempos gráficos previamente escolhidos:

//+------------------------------------------------------------------+
//|                                                   testBasket.mq5 |
//|                        Copyright 2017, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//--- parâmetros de entrada

#include <Trade\\Trade.mqh>


#define LG 7

input int SELLPROFIT =   0;
input int SELL1LIMIT =  70;
input int SELL2FROM  =  60;
input int SELL2TO    =  50;

input int BUYPROFIT  =   0;
input int BUY1LIMIT  = -70;
input int BUY2FROM   = -60;
input int BUY2TO     = -50;

input int WPR=20;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum BSTATE 
  {
   BCLOSE = 0,
   BBUY   = 1,
   BSELL  = 2
  };

string pair[]={"EURUSD","GBPUSD","AUDUSD","NZDUSD","USDCAD","USDCHF","USDJPY"};
bool bDirect[]={false,false,false,false,true,true,true};
datetime TimeParam[3];

double dWpr[3];
ulong  Ticket[LG];
double TradeResult[LG];
double TradeCurrency;
double Drw;
string sLog;

double TradeTotalResult[LG];
double TradeTotalCurrency;
int    iTradeCount;
double mDrw;

int h1[LG];
BSTATE bstate;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double GetValue1(int shift)
  {
   double dBuf[1];
   double res=0.0;
   for(int i=0; i<LG; i++)
     {
      CopyBuffer(h1[i],0,shift,1,dBuf);
      if(bDirect[i]==true)
         res+=dBuf[0];
      else
         res+=-(dBuf[0]+100);
     }//end for (int i = 0; i < iCount; i++)      
   res=res/LG;
   return (NormalizeDouble((res + 50) * 2, _Digits) );
  }

//+------------------------------------------------------------------+
//| Função de inicialização do Expert                                |
//+------------------------------------------------------------------+
int lh;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
   EventSetTimer(1);

   for(int i=0; i<LG; i++)
     {
      h1[i]=iWPR(pair[i],0,WPR);
     }
   bstate=BCLOSE;

   ArrayInitialize(TradeTotalResult,0);
   ArrayInitialize(dWpr,EMPTY_VALUE);
   TradeTotalCurrency=0;
   iTradeCount=0;
   mDrw=1000000;

   lh=INVALID_HANDLE;
   string lname = _Symbol + "_" + TimeFrameToShortString(Period() );
   string t1, t = lname;
   int i=0;
   for(;;) 
     {
      t+=".html";
      long lg=FileFindFirst(t,t1);
      if(lg==INVALID_HANDLE) 
        {
         lh= FileOpen(t,FILE_WRITE | FILE_TXT | FILE_ANSI);
         Print("CREATE ",t);
         break;
        }
      FileFindClose(lg);
      t=lname+"_"+IntegerToString(i++);
     }

   FileWriteString(lh,"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n");
   FileWriteString(lh,"<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n");
   FileWriteString(lh,"<head>\r\n");
   FileWriteString(lh,"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\r\n");
   FileWriteString(lh,"<title>"+lname+"</title>\r\n");
   FileWriteString(lh,"</head>\r\n<body>\r\n");
   FileWriteString(lh,"<H2>"+_Symbol+" "+TimeFrameToShortString(Period())+"</H2>\r\n");
   FileWriteString(lh,"<H3>Parâmetros do padrão:</H3>\r\n");
   FileWriteString(lh,"<table width=\"100%\" cellspacing=\"0\" cellpadding=\"5\">\r\n");
   FileWriteString(lh,"<thead>\r\n<tr>\r\n<th>BUY</th>\r\n<th>SELL</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n<tr>\r\n");
   t=StringFormat("Ponto 1: %d Ponto 2 de: %d para: %d Fechamento em: %d",BUY1LIMIT,BUY2FROM,BUY2TO,BUYPROFIT);
   FileWriteString(lh,"<td style=\"text-align:center;\">\r\n<ul>\r\n<li>"+t+"</li>\r\n</ul>\r\n</td>\r\n");
   t=StringFormat("Ponto 1: %d Ponto 2 de: %d para: %d Fechamento em: %d",SELL1LIMIT,SELL2FROM,SELL2TO,SELLPROFIT);
   FileWriteString(lh,"<td style=\"text-align:center;\">\r\n<ul>\r\n<li>"+t+"</li>\r\n</ul>\r\n</td>\r\n");
   FileWriteString(lh,"</tr>\r\n</tbody>\r\n</table>\r\n");
   FileWriteString(lh,"<H2>"+"Resultado do Testador"+"</H2>\r\n");
   FileWriteString(lh,"<table border=\"1\" width=\"100%\" cellspacing=\"0\" cellpadding=\"5\">\r\n");
   FileWriteString(lh,"<thead>\r\n<th>Num.</th>\r\n<th>Type</th>\r\n<th>WPR(P1/P2)</th>\r\n<th>Time(Begin/End/Length)</th>\r\n<th>Drawdown/<br/>Profit</th>\r\n<th>Pair Profit</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n");

   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void PushWpr(double wpr) 
  {
   dWpr[2] = dWpr[1]; dWpr[1] = dWpr[0];
   dWpr[0] = wpr;
  }
//+------------------------------------------------------------------+
//| Função tick do Expert                                            |
//+------------------------------------------------------------------+
void OnTick()
  {

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Stat() 
  {

   double d=0;
   for(int i=0; i<LG; i++) 
     {
      PositionSelectByTicket(Ticket[i]);
      d+=PositionGetDouble(POSITION_PROFIT);
     }
   if(d<Drw) Drw=d;
   if(Drw<mDrw) 
     {
      mDrw=Drw;
      TimeParam[2]=TimeCurrent();
     }
  }
//+------------------------------------------------------------------+
//| Funçao timer                                                     |
//+------------------------------------------------------------------+
void OnTimer()
  {
   if(bstate!=BCLOSE) 
     {
      Stat();
     }
   if(IsNewCandle()) 
     {
      double res=GetValue1(0);
      PushWpr(res);
      if(dWpr[1]!=EMPTY_VALUE) 
        {
         if(bstate==BBUY && (dWpr[0]>=BUYPROFIT )) 
           {
            CloseAllPos();
            bstate=BCLOSE;
           }
         if(bstate==BSELL && (dWpr[0]<=SELLPROFIT )) 
           {
            CloseAllPos();
            bstate=BCLOSE;
           }
         if(bstate==BCLOSE && dWpr[0]<=SELL2FROM && dWpr[0]>=SELL2TO && dWpr[1]>=SELL1LIMIT) 
           {
            EnterSell(0.01);
            bstate=BSELL;
            TimeParam[0]=TimeCurrent();
            TradeCurrency=0;
            Drw=1000000;
            iTradeCount++;
            sLog=StringFormat("<tr>\r\n<td>%d</td>\r\n<td>SELL</td>\r\n<td>%.2f/<br/>%.2f</td>\r\n<td>%s/<br/>",iTradeCount,dWpr[1],dWpr[0],TimeToString(TimeCurrent()));
            return;
           }
         if(bstate==BCLOSE && dWpr[0]>=BUY2FROM && dWpr[0]<=BUY2TO && dWpr[1]<=BUY1LIMIT) 
           {
            EnterBuy(0.01);
            bstate=BBUY;
            TimeParam[0]=TimeCurrent();
            TradeCurrency=0;
            Drw=1000000;
            iTradeCount++;
            sLog=StringFormat("<tr>\r\n<td>%d</td>\r\n<td>BUY</td>\r\n<td>%.2f/<br/>%.2f</td>\r\n<td>%s/<br/>",iTradeCount,dWpr[1],dWpr[0],TimeToString(TimeCurrent()));
            return;
           }
        }//if (stc.Pick(1) != EMPTY_VALUE)
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CloseAllPos() 
  {

   CTrade Trade;
   Trade.LogLevel(LOG_LEVEL_NO);

   TimeParam[1]=TimeCurrent();
   string p="<td>";
   for(int i=0; i<LG; i++) 
     {
      TradeResult[i]=PositionGetDouble(POSITION_PROFIT)+PositionGetDouble(POSITION_SWAP);
      p+=StringFormat("%s = %.2f<br/>",pair[i],TradeResult[i]);
      TradeCurrency       += TradeResult[i];
      TradeTotalResult[i] += TradeResult[i];
      Trade.PositionClose(Ticket[i]);
     }
   p+="</td>\r\n";
   TradeTotalCurrency+=TradeCurrency;
   sLog += StringFormat("%s/<br/>%s</td>\r\n<td>%.2f/<br/>%.2f</td>\r\n",TimeToString(TimeParam[1]), TimeIntervalToStr(TimeParam[0], TimeParam[1]), Drw, TradeCurrency );
   sLog += p;
   FileWriteString(lh,sLog);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void EnterBuy(double lot) 
  {

   CTrade Trade;
   Trade.LogLevel(LOG_LEVEL_NO);

   for(int i=0; i<LG; i++) 
     {
      if(bDirect[i]) 
        { //envia a compra
         Trade.Buy(lot,pair[i]);
         Ticket[i]=Trade.ResultDeal();
        }
      else 
        { //envia a venda
         Trade.Sell(lot,pair[i]);
         Ticket[i]=Trade.ResultDeal();
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void EnterSell(double lot) 
  {

   CTrade Trade;
   Trade.LogLevel(LOG_LEVEL_NO);

   for(int i=0; i<LG; i++) 
     {
      if(bDirect[i]) 
        { //envia a venda
         Trade.Sell(lot,pair[i]);
         Ticket[i]=Trade.ResultDeal();
        }
      else 
        { //envia a compra
         Trade.Buy(lot,pair[i]);
         Ticket[i]=Trade.ResultDeal();
        }
     }
  }
//+------------------------------------------------------------------+
//| Função de desinicialização do Expert                             |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- destrói o timer
   EventKillTimer();

   FileWriteString(lh,"</tbody>\r\n</table>\r\n");
   FileWriteString(lh,"<H2>Resultado Total</H2>\r\n");
   FileWriteString(lh,"<table border=\"1\" width=\"100%\" cellspacing=\"0\" cellpadding=\"5\">\r\n");
   FileWriteString(lh,"<thead>\r\n<tr>\r\n<th>Operações<br/>Contagem</th>\r\n<th>Lucro</th>\r\n<th>Rebaixamento Máximo</th>\r\n<th>Lucro do Par</th>\r\n</tr>\r\n</thead>\r\n<tbody>\r\n");
   string p = StringFormat("<tr><td>%d</td>\r\n<td>%.2f</td>\r\n<td>%.2f at<br/>%s</td>\r\n<td>",iTradeCount,TradeTotalCurrency,mDrw,TimeToString(TimeParam[2]));
   for(int i=0; i<LG; i++)
     {
      if(h1[i]!=INVALID_HANDLE) IndicatorRelease(h1[i]);
      p+=StringFormat("%s = %.2f<br/>",pair[i],TradeTotalResult[i]);
     }
   p+="</td>\r\n</tr>\r\n";
   FileWriteString(lh,p);
   FileWriteString(lh,"</tbody>\r\n</table>\r\n");
   FileWrite(lh,"</body>\r\n</html>"); //End log
   FileClose(lh);
  }
//+------------------------------------------------------------------+

bool IsNewCandle() 
  {

   static int candle=-1;

   int t1=0;
   switch(_Period)
     {
      case PERIOD_H1:  t1 = Hour();   break;
      case PERIOD_H4:  t1 = Hour4();  break;
      case PERIOD_D1:  t1 = Day();    break;
     }
   if(t1!=candle) {candle=t1; return(true);}
   return (false);
  }
int Hour4(){return((int)Hour()/4);}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int Day()
  {
   MqlDateTime tm;
   TimeCurrent(tm);
   return(tm.day);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int Hour()
  {
   MqlDateTime tm;
   TimeCurrent(tm);
   return(tm.hour);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string TimeIntervalToStr(datetime dt1,datetime dt2) 
  {
   string tm;
   if(dt1 >= dt2)   tm = TimeToString(dt1 - dt2);
   else tm = TimeToString(dt2 - dt1,TIME_DATE|TIME_MINUTES|TIME_SECONDS);
   string ta[],ta1[];
   StringSplit(tm,StringGetCharacter(" ",0),ta);
   StringSplit(ta[0],StringGetCharacter(".",0),ta1);
   ta1[0] = IntegerToString( StringToInteger(ta1[0]) - 1970);
   ta1[1] = IntegerToString( StringToInteger(ta1[1]) - 1);
   ta1[2] = IntegerToString( StringToInteger(ta1[2]) - 1);
   return (ta1[0] + "." + ta1[1] + "." + ta1[2] + " " + ta[1]);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string TimeFrameToShortString(ENUM_TIMEFRAMES period)
  {
   switch(period)
     {
      case PERIOD_H1:  return ("H1");
      case PERIOD_H4:  return ("H4");
      case PERIOD_D1:  return ("D1");
     }
   return ("");
  }
//+------------------------------------------------------------------+

A primeira versão do EA para testes pode ser encontrada no arquivo testBasket.mq5 em anexo. O algoritmo não contém nada de especial, embora seja dada muita atenção aos formulários do relatório. Vamos esclarecer o significado das entradas do EA:

  • SELLPROFIT. Quando o indicador WPR combinado atinge esse valor, encerra todas as posições abertas para vender a cesta. O valor padrão é 0%.
  • SELL1LIMIT. Este é o valor mínimo do WPR combinado para o ponto 1 (veja a imagem acima) para começar a identificar o padrão de venda da cesto. O valor padrão é 70%.
  • SELL2FROM. Valor máximo do WPR combinado para o ponto 2 para identificar o padrão de venda da cesta. Por padrão, 60% é um nível de sobrecompra.
  • SELL2TO. Valor mínimo do WPR combinado para o ponto 2 para a identificação final do padrão de venda da cesta. O padrão é de 50%.
  • BUYPROFIT. Quando o indicador WPR combinado atinge esse valor, encerra todas as posições abertas para comprar a cesto. O padrão é 0%.
  • BUY1LIMIT. Este é o valor máximo do WPR combinado para o ponto 1 para identificar o padrão de compra da cesta. O padrão é -70%.
  • BUY2FROM. Valor mínimo do WPR combinado para o ponto 2 para identificar o padrão de compra da cesta. Por padrão, 60% é um nível de sobrevenda.
  • BUY2TO. Valor máximo do WPR combinado para o ponto 2 para a identificação final do padrão de compra da cesta. O padrão é -50%.
  • WPR. Período do indicador técnico padrão WPR. O padrão é 20.

Em seguida, teste o EA no testador a partir de janeiro de 2016. A data de teste selecionada depende da qualidade do histórico. Nós vamos analisar dois padrões de formas. O primeiro foi descrito acima e definido por padrão. O segundo é deslocado em relação ao primeiro da seguinte maneira:

  • SELLPROFIT. Quando o indicador WPR combinado atinge esse valor, encerra todas as posições abertas para vender a cesta. Este é o valor de 0%.
  • SELL1LIMIT. Este é o valor mínimo do WPR combinado para o ponto 1 (veja a imagem acima) para começar a identificar o padrão de venda da cesto. Este é o valor de 80%.
  • SELL2FROM. Valor máximo do WPR combinado para o ponto 2 para identificar o padrão de venda da cesta. Este é o valor de 70%, nível de sobrecompra.
  • SELL2TO. Valor mínimo do WPR combinado para o ponto 2 para a identificação final do padrão de venda da cesta. Este é o valor de 50%.
  • BUYPROFIT. Quando o indicador WPR combinado atinge esse valor, encerra todas as posições abertas para comprar a cesto. Este é o valor de 0%.
  • BUY1LIMIT. Este é o valor máximo do WPR combinado para o ponto 1 para identificar o padrão de compra da cesta. Este é o valor de -80%.
  • BUY2FROM. Valor mínimo do WPR combinado para o ponto 2 para identificar o padrão de compra da cesta. Este é o valor de -70%, nível de sobrevenda.
  • BUY2TO. Valor máximo do WPR combinado para o ponto 2 para a identificação final do padrão de compra da cesta. Este é o valor de -50%.

O resultado está nos relatórios em html.

Relatório do EA

Os relatórios do EA são de fácil compreensão. Vamos considerar a estrutura dos relatórios usando o relatório da cesta EUR como exemplo.

A primeira linha contém o cabeçalho com os nomes do gráfico e o período em que o EA foi lançado.

Seguem os parâmetros do padrão que o EA aplicou separadamente para comprar e vender as cestas: Localização ponto 1 — ponto 1: SELL1LIMIT (BUY1LIMIT). Ponto 2 de: ... para: ... —  localização do ponto 2: SELL2FROM (BUY2FROM) e SELL2TO (BUY2TO). Encerramento em — localização do ponto de encerramento do padrão SELLPROFIT (BUYPROFIT):

EURUSD H4

Parâmetros do padrão:

COMPRA VENDA
  • Ponto 1: -80 Ponto 2 de: -70 para: -50 Encerramento em: 0
  • Ponto 1: 80 Ponto 2 de: 70 para: 50 Encerramento em: 0

Os parâmetros do padrão são seguidos pela tabela de Resultados do Teste contendo os dados de cada negociação durante o período de teste na seguinte ordem:

  • Num. — número do índice
  • Tipo — tipo de negociação: venda ou compra da cesto
  • WPR(P1/P2) — dados do WPR combinado no formato do Ponto 1/Ponto 2 usado para entrar no mercado
  • Tempo(Início/Fim/Duração) — dados sobre o tempo da negociação: Horário de entrada no mercado/Horário de saída/Duração da negociação
  • Rebaixamento/Lucro — redução máxima por tempo de negociação / lucro final. Dados na moeda de depósito.
  • Lucro do par — lucro dos pares individuais em que a cesta de moedas é constituída. Dados na moeda de depósito.

Abaixo está a porção da tabela onde podemos ver que o primeiro negócio durou oito horas e trouxe uma perda de 16.34 USD. Em particular, a ordem no EURUSD foi encerrada com uma perda de 2.55 USD:

Num. Tipo WPR(P1/P2) Tempo(Início/Fim/Duração) Rebaixamento/
Lucro
Lucro do Par
1 VENDA 86.26/
67.15
23.03.2016 20:00/
24.03.2016 04:00/
0.0.0 08:00:00
-21.70/
-16.34
EURUSD = -2.55
GBPUSD = -1.58
AUDUSD = -2.02
NZDUSD = -3.66
USDCAD = -2.15
USDCHF = -2.97
USDJPY = -1.41


A tabela "Resultado Total" que contém resumo dos dados no período de teste na seguinte ordem vem em último lugar:

  • Contagem do negócio — número de negociações para todo o período de teste.
  • Lucro — lucro obtido durante todo o período de teste. Dados na moeda de depósito.
  • Rebaixamento Máximo — redução máxima e o momento em que ele foi detectado. Dados na moeda e data do depósito.
  • Lucro do Par — lucro total por cada par de moedas em que a cesta de moedas é constituída. Dados na moeda de depósito.

Aqui está a tabela diretamente do relatório:

Operações
Contagem
Lucro Rebaixamento Máximo Lucro do Par
22 189.06 -52.37 em
02.05.2016 19:53
EURUSD = 52.43
GBPUSD = 24.50
AUDUSD = 45.88
NZDUSD = 13.94
USDCAD = 15.73
USDCHF = 12.26
USDJPY = 24.32


Os relatórios obtidos estão anexados em DocUSD.zip.

Vale ressaltar que as transações em D1 são inesperadamente pequenas. No entanto, existem sinais encorajadores:

  • O EA mostrou um resultado positivo em H4 e H1 sem nenhum esforço da nossa parte.

Embora os dados sejam bastante limitados, nós ainda podemos fazer conclusões preliminares que possam ser esclarecidas no futuro.

  1. O padrão raramente é encontrado no tempo gráfico diário. Esta tendência é mais provável de continuar em tempos gráficos superiores a D1.
  2. O nível de sobrecompra/sobrevenda está dentro da faixa de 60% — 70% em caso de sobrecompra e -60% — -70% em caso de sobrevenda. Não há muitos negócios acima de 70% e abaixo de -70%. Neste caso, o ponto 1 deve estar acima de 90% ou abaixo de -90% para identificar o padrão, o que é uma ocorrência rara. Abaixo de 60% ou acima de -60%, o ponto 2 revela-se perto de 40% ou -40% e se aproxima da área de potencial lateralização. Esta área é caracterizada por uma volatilidade ainda maior das leituras do indicador e de múltiplos sinais falso positivos.

Vamos finalizar o EA e continuar com a próxima moeda da cesta — NZD. Primeiro, nós devemos fazer as alterações no formulário do relatório, deduzindo o valor do "rebaixamento positivo". Qual é a ideia por trás desse conceito? A cesta é encerrada de acordo com as leituras do indicador em vez de um determinado valor de lucro ou níveis de negociação especificados. Antes do fechamento, as ordens da cesta de pedidos podem estar sofrendo um rebaixamento, monitorado pelo EA. Essas mesmas ordens podem apresentar lucro significativo que não pode ser corrigido, já que o indicador ainda não atingiu os valores necessários para o fechamento. Nós chamamos isso de "rebaixamento positivo" e seus valores máximos são enviados para o relatório. Agora, nós sabemos o lucro potencial e a capacidade da cesta para se mover para o lado positivo.

Vamos adicionar esse valor à penúltima coluna da tabela Resultado do Testador. A coluna Rebaixamento/Lucro é chamada agora Rebaixamento/+Rebaixamento/Lucro. Os dados de cada célula da coluna são organizados na seguinte ordem: Rebaixamento/Rebaixamento positivo/Lucro. Todos os dados estão na moeda de depósito.

Além disso, a retirada positiva máxima é exibida na tabela de Resultado Total. Vamos apresentar a penúltima coluna adicional, o "+Rebaixamento Máximo" e mostrar a redução máxima positiva para todo o período de teste quando o rebaixamento é revertido.

O código fonte da próxima versão do EA pode ser encontrado no arquivo testBasket1.mq5 anexado abaixo.

Os relatórios obtidos de cesta NZD estão no arquivo DocNZD.zip. As conclusões são as seguintes:

  • Assim, a suposição sobre a localização dos níveis de sobrecompra/sobrevenda feita anteriormente é confirmada. O relatório NZDUSD_H1_1.html é adicionado ao arquivo com os níveis próximos do possível início do movimento lateralizado com uma grande quantidade de entradas falso positivas. As consequências são bem óbvias.
  • Um pequeno número de negociações por este padrão na D1 é confirmado.
  • O resultado no H1 é decepcionante. Nós podemos assumir que o "nível de ruído" do tempo gráfico é uma soma de todos os pares de moedas da cesta que causam sinais falsos.

Vamos concluir o nosso estudo usando as moedas da cesta restante: AUD, EUR, GBP, CAD, JPY e CHF. Encontre os relatórios dessas moedas no arquivo Doc.zip anexado. É hora de resumir os resultados.

Resultados

  • O nível de sobrecompra é, na verdade, dentro da faixa de 60-70%, enquanto o sobrevendido está de -60% e -70%. Esta suposição é confirmada pelos relatórios obtidos e a localização do nível correspondente no indicador WPR padrão.
  • A verificação foi realizada em três tempos gráficos e todas as oito cestas. Nós analisamos duas formas do padrão de rompimento das linhas de sobrecompra/sobrevenda:
    1. O Ponto 1 do padrão está acima de 80%. O nível de sobrevenda é de 70%. O ponto 2 situa-se dentro de 70% e 50%. A cesta é encerrada quando o indicador ≤ 0%. A forma do padrão para entrar no mercado para vender a cesta é exibida aqui. A forma da entrada de compra é simétrica com um sinal de menos.
    2. O ponto 1 do padrão está acima de 70%. O nível de sobrevenda é de 60%. O ponto 2 situa-se entre 60% e 50%. A cesta é encerrada quando o indicador ≤ 0%. A forma do padrão para entrar no mercado para vender a cesta é exibida aqui. A forma da compra da cesta é simétrica com um sinal de menos.
  • Devo notar mais uma vez que há muito poucos negócios no D1, e nós não vamos fazer referência neste artigo. Vamos usar os dados das tabelas Resultado Total de todos os relatórios para formar o resumo das tabelas para outros prazos. A tabela mostra os resultados da negociação do EA na moeda de depósito para cada cesta de moedas e os dois formulários padrão descritos no parágrafo anterior:

     

    Tempo gráfico H1
      AUD EUR USD GBP NZD CAD CHF JPY
    Padrão 1 -590 90 -37 -991 -141 -80 -118 -514
    Padrão 2 -259 -67 328 -714 -352 -446 -118 -272

     

    Tempo gráfico H4
      AUD EUR USD GBP NZD CAD CHF JPY
    Padrão 1 286 -72 189 -400 104 60 -209 120
    Padrão 2 -208 25 40 80 172 10 -69 -176

     

    Vamos prestar atenção aos resultados desencorajadores no H1. Provavelmente, isso deve-se ao alto nível de "ruído" dos pares de moedas neste período.
  • Os resultados no H4 são mais promissores. Prestaremos uma atenção especial a este tempo gráfico a partir de agora.

Os resultados obtidos não nos permitem escolher entre duas formas do padrão, então teremos que trabalhar com ambos. O potencial da segunda forma parece maior para mim, mas é minha opinião subjetiva. Nós tomaremos a decisão final sobre isso mais tarde.

Nós devemos completar nosso trabalho com H1? No mínimo! Como você pode se lembrar, nós introduzimos o parâmetro "rebaixamento positivo" no relatório. Comparando-o com a redução convencional, nós podemos ver o seguinte:

  • A ideia inicial de encerrar a cesta de acordo com as leituras do WPR combinado (quando seu valor atinge zero) não é suficiente. A questão das perdas limitantes também não foi resolvida. Uma vez que nós lidamos com uma cesta de ordens, seria lógico atribuir um stop loss na moeda de depósito e monitora o lucro na moeda de depósito também. Isso nos impedirá de sofrer perdas instantâneas enquanto estiver no lucro e, por outro lado, nos permitam limitar as perdas potenciais de forma razoável. Esse método pode levar a um resultado positivo no H1 e aumentar a lucratividade no H4. Isso não faz parte dos nossos planos por enquanto, mas a solução técnica proposta pode ser útil no futuro.

Conclusão

A primeira etapa do teste padrão está completa. Os resultados obtidos requerem uma séria consideração. No nosso próximo trabalho, nós iremos concentrar nossa atenção na classificação de sinais, bem como em analisar sinais adicionais de outros padrões conhecidos. Isso nos permitirá obter novas informações, bem como refinar gradualmente os dados já obtidos.

Programas usados ​​no artigo:

 # Nome
Tipo
 Descrição
1 Pair.zip Arquivo
Os resultados do cálculo do número de negociações possíveis para todas as moedas da cesta em três tempos gráficos selecionados.
2
testBasket.mq5 Expert Advisor
Expert Advisor para teste.
3
DocUSD.zip Arquivo Relatórios em Html relativos à operação do EA testBasket.mq5 com a cesta USD.
 4 DocNZD.zip Arquivo Relatórios em Html relativos à operação do EA testBasket1.mq5 com a cesta NZD.
5
testBasket1.mq5 Expert Advisor EA para testes - próxima versão.
 6  Doc.zip Arquivo
Relatórios em Html relativos à operação do EA testBasket1.mq5 com outras cestas.
7 test.zip
 Arquivo Arquivo com os indicadores testIndexZig-Zag1.mq5 e testWPReur.mq5.