Estudo dos padrões de Merrill

3 outubro 2019, 16:20
Alexander Fedosov
0
3 705

Conteúdo

Introdução

A primeira tentativa de criar um sistema de padrões de preços foi feita por Robert Levy em 1971. Ele aplicou os padrões de flutuação de preço de cinco pontos e depois verificou se eles tinham algum significado. Ele não obteve resultados notáveis, mas Arthur Merrill continuou com o seu trabalho 10 anos depois. 

Ele dividiu os padrões em duas categorias que se assemelham às letras M e W. Cada categoria contém 16 padrões e suas próprias subcategorias. Merrill destacou 6 subcategorias:

  • Tendência de alta
  • Tendência de baixa
  • Triângulo
  • Expansão
  • Ombro, cabeça e ombro
  • Ombro, cabeça e ombro invertidos

Nós vamos definir a relevância atual dos padrões de Merrill usando um aplicativo para testá-los. Além disso, seria interessante aplicar esse modelo a vários tipos de dados — como os preços de fechamento, máxima e mínima, além dos osciladores.

Definição e aplicação

Para esclarecer como e para quais dados nós vamos aplicar os padrões de Merrill, nós precisamos entender o que eles realmente são. As duas principais categorias são os padrões que se assemelham às letras M e W. Eles são chamados de padrões M e W. Cada uma das categorias contém 16 padrões.

Fig. 1 Representação visual dos 16 padrões M. Como nós podemos ver, a diferença está no arranjo mútuo dos cinco pontos que compõem o padrão.  


Fig. 1. Representação visual dos padrões М

Fig. 2 Representação visual dos 16 padrões W. Nós vamos buscar esses dois grupos nos gráficos de preço e indicadores, além de estudar, avaliar e buscar possíveis regularidades.

Fig. 2. Representação visual dos padrões W

A ideia por trás de qualquer padrão se resume ao fato de que, quando uma formação específica aparece, nós podemos esperar que o preço se mova em uma determinada direção e obter lucro com isso.

Para deixar o mais claro possível em que área e como os padrões de Merrill devem ser estudados, aqui estão alguns exemplos. Fig. 3 Gráfico de preços linear de USDCAD, em H1. Esse tipo de representação é usado com menos frequência, pois as velas e barras se tornaram mais populares.

Fig. 3. Gráfico linear com base nos preços de fechamento de USDCAD, em H1

Aqui nós já podemos ver alguns padrões descritos acima. Essa deve ser a primeira área de estudo — aplicando ao gráfico linear com base nos preços de fechamento. Além disso, nós vamos verificar gráficos lineares com base nos preços de abertura (Open), máxima (High) e mínima (Low). 

A segunda área de estudo deve ser composta por osciladores, como:

O método que eu sugeri no artigo Estudo das técnicas de análise de velas (Parte I): Verificação de padrões existentes deve ser usado como um método de avaliação de padrões a serem aplicados ao preço e aos osciladores mencionados acima. A ideia por trás disso é simples:

  • Identificação do padrão analisado em uma parte específica da amostra.
  • Análise do movimento dos preços após a sua identificação.
  • Coleta dos dados e o cálculo da eficiência do padrão.


Desenvolvimento da ferramenta de teste

Antes de iniciar o desenvolvimento, nós precisamos definir quais configurações ele deve conter. A ferramenta consiste no painel com as guias Analysis e Settings. Os parâmetros da janela de configurações do EA também devem ser usados. Em seguida, nós teremos três seções com as ferramentas para trabalhar com os padrões. Agora, vamos descrever as configurações em cada uma das seções.

A guia Analysis contém:

  1. Dois conjuntos de botões para selecionar os tipos de padrões testados. Existem também os botões All M e All W para a seleção/desmarcação rápida dos padrões М e W.
  2. O conjunto de botões para a seleção dos períodos gráficos testados e o botão ALL para selecionar/desmarcar todo o grupo de botões.
  3. O campo de entrada "Trend threshold (points)". É o lucro em pontos que o preço deve atingir dentro de no máximo três velas após a identificação do padrão de Merrill analisado.
  4. O botão que abre a janela de diálogo para a seleção das datas de início e término, além do horário de teste. 
  5. O campo de entrada com a caixa de seleção e o botão é um filtro para encontrar os símbolos de negociação necessários. Ele possui uma predefinição — Major. Ele exibe os principais pares de moedas. A caixa de seleção desativa o filtro e mostra todos os símbolos de negociação disponíveis.
  6. Símbolos de negociação selecionados na tabela com o filtro. Após a seleção deles da lista, a análise de padrões é realizada.
  7. A tabela de resultados consiste em sete colunas: 
    • Nome da figura. A coluna exibe o nome do padrão de Merrill analisado, por exemplo, M10 ou W12.
    • Encontrado. Número de padrões detectados de um tipo especificado em uma amostra selecionada.
    • Período gráfico. O período gráfico em que foi analisado um padrão especificado.
    • P, Uptrend. A probabilidade do preço subir para o valor do "Limiar de tendência (pontos)" após o padrão ser exibido.
    • P, Dntrend. A probabilidade do preço cair para o valor do "Limiar de tendência (pontos)" após o padrão ser exibido.
    • K, UpTrend/K, DnTrend. Esta é uma taxa descrita no meu artigo Estudo das técnicas de análise de velas (Parte I): Verificação dos padrões existentes. Ele avalia o quão rápido o preço atinge um lucro especificado após o padrão analisado aparecer na direção ascendente ou descendente de uma tendência.

A Fig. 4 forence a implementação visual de todos os símbolos e parâmetros descritos acima.


Fig. 4. Guia Analysis

Agora vamos considerar a guia Settings:

  1. Indicador usado. Permite selecionar um indicador que a busca e a análise dos padrões de Merrill devem ser aplicadas.
  2. Os coeficientes de ponderação são usados no cálculo das taxas de K, UpTrend/DnTrend descritas acima. 
  3. Idioma da interface. A lista suspensa da seleção do idioma da interface: inglês ou russo.

A aparência da guia com as configurações é exibida na Fig. 5 abaixo:


Fig. 5. Guia Settings

A última seção aplica a janela "EA Settings" (tecla de atalho F7) e apresenta as configurações dos indicadores aplicados que foram listados em "Indicador usado". A Fig. 6 mostra a janela da última seção de configurações.


Fig. 6. Janela de configuração dos indicadores usados

Nós devemos considerar as seguintes nuances ao definir as configurações na janela:

  • O primeiro ("Preço aplicado") aplica à variável de enumeração ENUM_APPLIED_PRICE com sete valores: preço de abertura, preço de fechamento, máxima e mínima, além dos preços médio, típico e médio ponderado. Ao executar uma análise com base no preço do gráfico, os quatro primeiros valores devem ser usados pois os três últimos são projetados para o cálculo dos indicadores.
  • Se você deseja usar os indicadores na análise de padrões, a configuração "Preço aplicado" afeta os indicadores usando a variável do tipo ENUM_APPLIED_PRICE em seus cálculos, a saber: ATR, CCI e RSI.

Agora, vamos considerar a implementação da interface do aplicativo, além dos métodos de busca e análise dos padrões de Merrill.

Para desenvolver a GUI, nós usamos o método CreateGUI() que consiste nos métodos CreateWindow() para a criação da janela principal da interface e a janela de diálogo CreateWindowSetting1() para a seleção do intervalo de tempo para o estudo.

//+------------------------------------------------------------------+
//| Create the program GUI                                           |
//+------------------------------------------------------------------+
bool CProgram::CreateGUI(void)
  {
//--- Create the panel
   if(!CreateWindow("Merrill Patterns"))
      return(false);
//--- Create the dialog window
   if(!CreateWindowSetting1("Setting dates"))
      return(false);
//--- Complete GUI creation
   CWndEvents::CompletedGUI();
   return(true);
  }

Agora, vamos ver no que cada método consiste. Primeiro, nós vamos focar nossa atenção na janela principal da interface. Ele consiste na implementação da guia Analysis feita dos elementos descritos na Fig. 4.

//+------------------------------------------------------------------+
//| Analyze tab                                                      |
//+------------------------------------------------------------------+
//--- Create the pattern set buttons
   if(!CreatePatternSet(m_patterns,10,10))
      return(false);
//--- Timeframe header
   if(!CreateTFLabel(m_text_labels[1],10,105,0))
      return(false);
//--- Create the timeframe set buttons
   if(!CreateTimeframeSet(m_timeframes,10,125,0))
      return(false);
//--- Field for searching the symbol filter 
   if(!CreateSymbolsFilter(m_symb_filter1,m_request1,10,180,0))
      return(false);
//--- Create the button for selecting a date range
   if(!CreateDateRange(m_request3,280,180,0))
      return(false);
//--- Create the field for entering the profit threshold value
   if(!CreateThresholdValue(m_threshold1,400,180,100,0))
      return(false);
//--- Create the symbol table
   if(!CreateSymbTable(m_symb_table1,10,225,0))
      return(false);
//--- Create the result table
   if(!CreateTable1(m_table1,120,225,0))
      return(false);

E da guia Settings descrita na Fig. 5.

//+------------------------------------------------------------------+
//| Settings tab                                                     |
//+------------------------------------------------------------------+
//---
   if(!CreateButtonsGroup1(10,50))
      return(false);
//--- Text labels
   if(!CreateTextLabel(m_text_labels[0],10,100))
      return(false);
   if(!CreateTextLabel(m_text_labels[3],10,10))
      return(false);
//--- Input fields
   if(!CreateCoef(m_coef1,10,140,"K1",1))
      return(false);
   if(!CreateCoef(m_coef2,100,140,"K2",0.5))
      return(false);
   if(!CreateCoef(m_coef3,200,140,"K3",0.25))
      return(false);
   if(!CreateLanguageSetting(m_lang_setting,10,180,1))
      return(false);
//--- Status bar
   if(!CreateStatusBar(1,26))
      return(false);
//---
   return(true);
  }

Uma implementação mais detalhada de cada um dos métodos aplicados que adicionam elementos de interface, pode ser encontrada nos códigos-fonte anexados.

O método que implementa a janela de diálogo para definir uma amostra temporária é o seguinte:

//+---------------------------------------------------------------------------------+
//| Create the dialog window for selecting the range of dates in the Analysis tab   |
//+---------------------------------------------------------------------------------+
bool CProgram::CreateWindowSetting1(const string caption_text)
  {
//--- Add the window pointer to the window array
   CWndContainer::AddWindow(m_window[2]);
//--- Coordinates
   int x=m_request3.X();
   int y=m_request3.Y()+m_request3.YSize();
//--- Properties
   m_window[2].XSize(372);
   m_window[2].YSize(230);
   m_window[2].WindowType(W_DIALOG);

//--- Create the form
   if(!m_window[2].CreateWindow(m_chart_id,m_subwin,caption_text,x,y))
      return(false);
//---
   if(!CreateCalendar(m_calendar1,m_window[2],10,25,D'01.01.2019',1))
      return(false);
   if(!CreateCalendar(m_calendar2,m_window[2],201,25,m_calendar2.Today(),1))
      return(false);
//---
   if(!CreateTimeEdit(m_time_edit1,m_window[2],10,200,"Time",1))
      return(false);
   if(!CreateTimeEdit(m_time_edit2,m_window[2],200,200,"Time",1))
      return(false);
//---
   return(true);
  }

Agora, nós vamos voltar nossa atenção para os métodos de busca, estudo e avaliação dos padrões. Para conseguir isso, nós precisamos monitorar toda a sequência de ações do algoritmo. Primeiro, vamos examinar o arquivo MerrillPatterns.mq5 onde esse algoritmo é iniciado.

//--- Include the application class
#include "Program.mqh"
CProgram program;
//+------------------------------------------------------------------+
//| EA inputs                                                        |
//+------------------------------------------------------------------+
input ENUM_APPLIED_PRICE   Inp_Price1              =  PRICE_CLOSE;   // Applied price
input int                  Inp_ATR_Peroid          =  5;             // ATR Period
input int                  Inp_CCI_Peroid          =  5;             // CCI Period
input int                  Inp_DeM_Peroid          =  5;             // DeMarker Period
input int                  Inp_ForcePeriod         =  13;            // ForceIndex Period
input ENUM_MA_METHOD       Inp_ForceMAMethod       =  MODE_SMA;      // ForceIndex MA method
input ENUM_APPLIED_PRICE   Inp_ForceAppliedPrice   =  PRICE_CLOSE;   // ForceIndex Applied price
input ENUM_APPLIED_VOLUME  Inp_ForceAppliedVolume  =  VOLUME_TICK;   // ForceIndex Volumes
input int                  Inp_WPR_Period          =  5;             // WPR Period
input int                  Inp_RSI_Period          =  5;             // RSI Period
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(void)
  {
//---
   program.OnInitEvent();
//--- Set the trading panel
   if(!program.CreateGUI())
     {
      ::Print(__FUNCTION__," > Failed to create GUI!");
      return(INIT_FAILED);
     }
//---
   program.InitializePrice(Inp_Price1);
   program.InitializeATR(Inp_ATR_Peroid);
   program.InitializeCCI(Inp_CCI_Peroid);
   program.InitializeDeM(Inp_DeM_Peroid);
   program.InitializeForce(Inp_ForcePeriod,Inp_ForceMAMethod,Inp_ForceAppliedPrice,Inp_ForceAppliedVolume);
   program.InitializeWPR(Inp_WPR_Period);
   program.InitializeRSI(Inp_RSI_Period);
   return(INIT_SUCCEEDED);
  }

Além das entradas do indicador, a busca de uma interface gráfica é realizada na seção OnInit() seguido pela inicialização do conjunto de dados definido na janela de Propriedades. Todos os métodos passam as configurações externas para as variáveis internas.

//---
   void              InitializePrice(ENUM_APPLIED_PRICE price)    { m_applied_price=price;        }
   void              InitializeATR(int period)                    { m_atr_period=period;          }
   void              InitializeCCI(int period)                    { m_cci_period=period;          }
   void              InitializeDeM(int period)                    { m_dem_period=period;          }
   void              InitializeWPR(int period)                    { m_wpr_period=period;          }
   void              InitializeRSI(int period)                    { m_rsi_period=period;          }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CProgram::InitializeForce(int period,ENUM_MA_METHOD ma_method,ENUM_APPLIED_PRICE price,ENUM_APPLIED_VOLUME volume)
  {
   m_force_period=period;
   m_force_ma_method=ma_method;
   m_force_applied_price=price;
   m_force_applied_volume=volume;
  }
//+-----------------------------------------------------------------

Após isso, o aplicativo está pronto para ser usado, enquanto as configurações restantes são passadas para a GUI criada. Eu já mencionei que a execução do cálculo é realizada escolhendo um símbolo de moeda na tabela de símbolos (pos. 6 na Fig. 4). Ele é realizado também após a definição do "Limiar de tendência" (pos. 3 na Fig. 4). Ambos os eventos iniciam o método ChangeSymbol1() para começar a coleta de dados detectados para prepará-los para a análise.

//+------------------------------------------------------------------+
//| Select a symbol in the Analysis tab                              |
//+------------------------------------------------------------------+
bool CProgram::ChangeSymbol1(const long id)
  {
//--- Check the element ID
   if(id!=m_symb_table1.Id())
      return(false);
//--- Exit if the string is not highlighted
   if(m_symb_table1.SelectedItem()==WRONG_VALUE)
     {
      //--- Show full description of a symbol in the status bar
      m_status_bar.SetValue(0,"Symbol for analysis not selected");
      m_status_bar.GetItemPointer(0).Update(true);
      return(false);
     }
//--- Get a selected symbol
   string symbol=m_symb_table1.GetValue(0,m_symb_table1.SelectedItem());
//--- Show the full symbol description in the status bar
   string val=(m_lang_index==0)?"Выбранный символ: ":"Selected symbol: ";
   m_status_bar.SetValue(0,val+::SymbolInfoString(symbol,SYMBOL_DESCRIPTION));
   m_status_bar.GetItemPointer(0).Update(true);
//---
   GetResult(symbol);
   return(true);
  }

A essência de seu trabalho foi definir um símbolo de negociação selecionado da tabela de símbolos e passar o seu valor para a barra de estado e o método GetResult(). Vamos considerar o método em mais detalhes, pois todo o trabalho principal ocorre nele.

//+------------------------------------------------------------------+
//| Handle pattern search results                                    |
//+------------------------------------------------------------------+
bool CProgram::GetResult(const string symbol)
  {
//--- Structure for evaluating pattern efficiency
   RATING_SET m_coef[];
//--- Figure types
   PATTERN_TYPE pattern_types[];
//---
   ArrayResize(pattern_types,33);
   for(int i=0;i<33;i++)
     {
      if(i==16)
         pattern_types[i]=-1;
      if(i<16)
         pattern_types[i]=PATTERN_TYPE(i);
      if(i>16)
         pattern_types[i]=PATTERN_TYPE(i-1);
     }
//--- Define selected timeframes
   GetTimeframes(m_timeframes,m_cur_timeframes);
   int total=ArraySize(m_cur_timeframes);
//--- Check for at least one selected timeframe
   if(total<1)
     {
      if(m_lang_index==0)
         MessageBox("Вы не выбрали рабочий таймфрейм!","Ошибка",MB_OK);
      else if(m_lang_index==1)
         MessageBox("You have not selected working timeframe!","Error",MB_OK);
      return(false);
     }
   int count=0;
   m_total_row=0;
//--- Remove all strings
   m_table1.DeleteAllRows();
//--- Get date range
   datetime start=StringToTime(TimeToString(m_calendar1.SelectedDate(),TIME_DATE)+" "+(string)m_time_edit1.GetHours()+":"+(string)m_time_edit1.GetMinutes()+":00");
   datetime end=StringToTime(TimeToString(m_calendar2.SelectedDate(),TIME_DATE)+" "+(string)m_time_edit2.GetHours()+":"+(string)m_time_edit2.GetMinutes()+":00");
//--- Check selected dates
   if(start>end || end>TimeCurrent())
     {
      if(m_lang_index==0)
         MessageBox("Неправильно выбран диапазон дат!","Ошибка",MB_OK);
      else if(m_lang_index==1)
         MessageBox("Incorrect date range selected!","Error",MB_OK);
      return(false);
     }
//--- 
   for(int k=0;k<33;k++)
     {
      if(k==16)
         continue;
      //--- Get selected patterns for analysis
      if(m_patterns[k].IsPressed())
        {
         ArrayResize(m_m_total,total);
         ArrayResize(m_coef,total);
         ZeroMemory(m_m_total);
         ZeroMemory(m_coef);
         count++;
         //--- Calculate by timeframes
         for(int j=0;j<total;j++)
           {
            double arr[];
            //--- Get data for analysis
            int copied=GetData(m_buttons_group1.SelectedButtonIndex(),symbol,m_cur_timeframes[j],start,end,arr);
            //---
            if(copied<9)
               MessageBox("Insufficient data for analysis","Error",MB_OK);
            for(int i=0;i<copied;i++)
              {
               if(i>copied-9)
                  continue;
               //--- Pattern search condition
               double A=arr[i];
               double B=arr[i+1];
               double C=arr[i+2];
               double D=arr[i+3];
               double E=arr[i+4];
               if(GetPatternType(A,B,C,D,E)==pattern_types[k])
                 {
                  m_m_total[j]++;
                  GetCategory(symbol,i+5,m_coef[j],m_cur_timeframes[j],m_threshold_value1);
                 }
              }
            //--- Add the result to the table
            AddRow(m_table1,m_patterns[k].LabelText(),m_coef[j],m_m_total[j],m_cur_timeframes[j]);
           }
        }
     }
//---
   if(count>0)
     {
      //---
      m_table1.DeleteRow(m_total_row);
      //--- Update the table
      m_table1.Update(true);
      m_table1.GetScrollVPointer().Update(true);
     }
   else
     {
      if(m_lang_index==0)
         MessageBox("Вы не выбрали паттерн!","Ошибка",MB_OK);
      else if(m_lang_index==1)
         MessageBox("You have not chosen a pattern!","Error",MB_OK);
     }
   return(true);
  }

Primeiro, eu preciso explicar os tipos de variáveis inseridas no início do método. O primeiro é a estrutura RATING_SET.

struct RATING_SET
  {
   int               a_uptrend;
   int               b_uptrend;
   int               c_uptrend;
   int               a_dntrend;
   int               b_dntrend;
   int               c_dntrend;
  };

Ele contém 6 variáveis do tipo int e ela é responsável para adicionar os dados sobre a frequência com que o preço se move em uma direção especificada após a identificação de um padrão e o quão rápido o preço atinge ela. Por exemplo, suponha que nós temos uma tendência de alta e o limiar de tendência está definido para 100 pontos em 5 dígitos, enquanto o preço estiver dentro desse valor em uma única vela. Nesse caso, a variável a_uptrend recebe o valor igual a um. Se o preço atingir 100 pontos em 2 velas, o valor será passado para a variável b_uptrend. Nós usaremos o array da estrutura m_coef[] em nosso método.

O segundo tipo de variável é a PATTERN_TYPE. Esta é uma enumeração que reúne todos os tipos de padrões de Merrill.

//+------------------------------------------------------------------+
//| Figure type                                                      |
//+------------------------------------------------------------------+
enum PATTERN_TYPE
  {
   M1,M2,M3,M4,M5,M6,M7,M8,
   M9,M10,M11,M12,M13,M14,M15,M16,
   W1,W2,W3,W4,W5,W6,W7,W8,
   W9,W10,W11,W12,W13,W14,W15,W16
  };

O array de enumeração pattern_types[] é aplicado ao método Em seguida, temos a verificação — quais períodos gráficos foram selecionados para trabalhar no aplicativo. Esses dados são manipulados pelo método GetTimeframes().

//+------------------------------------------------------------------+
//| Get the array of selected timeframes                             |
//+------------------------------------------------------------------+
void  CProgram::GetTimeframes(CButton &buttons[],ENUM_TIMEFRAMES &timeframe[])
  {
   string tf[22]=
     {
      "M1","M2","M3","M4","M5","M6","M10","M12","M15","M20","M30",
      "H1","H2","H3","H4","H6","H8","H12","D1","W1","MN"
     };
   int j=0;
   ArrayResize(timeframe,22);
   for(int i=0;i<22;i++)
     {
      if(buttons[i].IsPressed())
        {
         timeframe[j]=StringToTimeframe(tf[i]);
         j++;
        }
     }
   ArrayResize(timeframe,j);
  }

O método escreve isso no array de período gráfico preliminar m_cur_timeframes[]. Em seguida, obtemos o intervalo de tempo para o trabalho.

Na primeira iteração, nós começamos a verificar através do pressionamento do botão selecionado responsável pelos tipos de padrão e que definem um conjunto de padrões estudados. Na próxima iteração, cada um dos padrões é estudado nos períodos gráficos selecionados antes. Nesse estágio, surge a pergunta: em quais dados os padrões preliminares e as configurações do período gráfico devem ser aplicados. O método GetData() é responsável por isso, já que ele define as configurações definidas na janela de propriedades do EA, bem como o indicador aplicado (pos. 1 na Fig. 5) na guia de configurações do aplicativo.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CProgram::GetData(int index,string symb,ENUM_TIMEFRAMES tf,datetime start,datetime end,double &arr[])
  {
//---
   int Handle=INVALID_HANDLE,copied;
//--- Close price
   if(index==0)
     {
      MqlRates rt[];
      ZeroMemory(rt);
      copied=CopyRates(symb,tf,start,end,rt);
      ArrayResize(arr,copied);
      for(int i=0;i<copied;i++)
        {
         arr[i]=rt[i].close;
         if(m_applied_price==PRICE_OPEN)
            arr[i]=rt[i].open;
         else if(m_applied_price==PRICE_CLOSE)
            arr[i]=rt[i].close;
         else if(m_applied_price==PRICE_HIGH)
            arr[i]=rt[i].high;
         else if(m_applied_price==PRICE_LOW)
            arr[i]=rt[i].low;
        }
      return(copied);
     }
//--- ATR
   if(index==1)
      Handle=iATR(symb,tf,m_atr_period,m_applied_price);
//--- CCI
   if(index==2)
      Handle=iCCI(symb,tf,m_cci_period,m_applied_price);
//--- DeMarker
   if(index==3)
      Handle=iDeMarker(symb,tf,m_dem_period);
//--- Force Index
   if(index==4)
      Handle=iForce(symb,tf,m_force_period,m_force_ma_method,m_force_applied_volume);
//--- WPR
   if(index==5)
      Handle=iWPR(symb,tf,m_wpr_period);
//--- RSI
   if(index==6)
      Handle=iRSI(symb,tf,m_rsi_period,m_applied_price);
//---
   if(Handle==INVALID_HANDLE)
     {
      Print("Failed to get indicator handle");
      return(-1);
     }
   copied=CopyBuffer(Handle,0,start,end,arr);
   return(copied);
  }

Após receber os dados para análise, o algoritmo passa para o método GetPatternType(), ele é usado para buscar todos os padrões definidos anteriormente nos períodos gráficos selecionados. 

//+------------------------------------------------------------------+
//| Define the patterns                                              |
//+------------------------------------------------------------------+
PATTERN_TYPE CProgram::GetPatternType(double A,double B,double C,double D,double E)
  {
//--- M1
   if(B>A && A>D && D>C && C>E)
      return(M1);
//--- M2
   if(B>A && A>D && D>E && E>C)
      return(M2);
//--- M3
   if(B>D && D>A && A>C && C>E)
      return(M3);
//--- M4
   if(B>D && D>A && A>E && E>C)
      return(M4);
//--- M5
   if(D>B && B>A && A>C && C>E)
      return(M5);
//--- M6
   if(D>B && B>A && A>E && E>C)
      return(M6);
//--- M7
   if(B>D && D>C && C>A && A>E)
      return(M7);
//--- M8
   if(B>D && D>E && E>A && A>C)
      return(M8);
//--- M9
   if(D>B && B>C && C>A && A>E)
      return(M9);
//--- M10
   if(D>B && B>E && E>A && A>C)
      return(M10);
//--- M11
   if(D>E && E>B && B>A && A>C)
      return(M11);
//--- M12
   if(B>D && D>C && C>E && E>A)
      return(M12);
//--- M13
   if(B>D && D>E && E>C && C>A)
      return(M13);
//--- M14
   if(D>B && B>C && C>E && E>A)
      return(M14);
//--- M15
   if(D>B && B>E && E>C && C>A)
      return(M15);
//--- M16
   if(D>E && E>B && B>C && C>A)
      return(M16);
//--- W1
   if(A>C && C>B && B>E && E>D)
      return(W1);
//--- W2
   if(A>C && C>E && E>B && B>D)
      return(W2);
//--- W3
   if(A>E && E>C && C>B && B>D)
      return(W3);
//--- W4
   if(A>C && C>E && E>D && D>B)
      return(W4);
//--- W5
   if(A>E && E>C && C>D && D>B)
      return(W5);
//--- W6
   if(C>A && A>B && B>E && E>D)
      return(W6);
//--- W7
   if(C>A && A>E && E>B && B>D)
      return(W7);
//--- W8
   if(E>A && A>C && C>B && B>D)
      return(W8);
//--- W9
   if(C>A && A>E && E>D && D>B)
      return(W9);
//--- W10
   if(E>A && A>C && C>D && D>B)
      return(W10);
//--- W11
   if(C>E && E>A && A>B && B>D)
      return(W11);
//--- W12
   if(E>C && C>A && A>B && B>D)
      return(W12);
//--- W13
   if(C>E && E>A && A>D && D>B)
      return(W13);
//--- W14
   if(E>C && C>A && A>D && D>B)
      return(W14);
//--- W15
   if(C>E && E>D && D>A && A>B)
      return(W15);
//--- W16
   if(E>C && C>D && D>A && A>B)
      return(W16);
   return(-1);
  }

Ao detectar o padrão, ele é avaliado usando o método GetCategory(). O array de estrutura do tipo RATING_SET, que foi definido anteriormente, é utilizado aqui.

//+------------------------------------------------------------------+
//| Define the profit categories                                     |
//+------------------------------------------------------------------+
bool CProgram::GetCategory(const string symbol,const int shift,RATING_SET &rate,ENUM_TIMEFRAMES timeframe,int threshold)
  {
   MqlRates rt[];
   datetime start=StringToTime(TimeToString(m_calendar1.SelectedDate(),TIME_DATE)+" "+(string)m_time_edit1.GetHours()+":"+(string)m_time_edit1.GetMinutes()+":00");
   start+=PeriodSeconds(timeframe)*shift;
   int copied=CopyRates(symbol,timeframe,start,4,rt);
//--- Get the data of previous candles
   if(copied<4)
      return(false);
   double high1,high2,high3,low1,low2,low3,close0,point;
   close0=rt[0].close;
   high1=rt[1].high;
   high2=rt[2].high;
   high3=rt[3].high;
   low1=rt[1].low;
   low2=rt[2].low;
   low3=rt[3].low;
   if(!SymbolInfoDouble(symbol,SYMBOL_POINT,point))
      return(false);

//--- Check for Uptrend
   if((int)((high1-close0)/point)>=threshold)
     {
      rate.a_uptrend++;
     }
   else if((int)((high2-close0)/point)>=threshold)
     {
      rate.b_uptrend++;
     }
   else if((int)((high3-close0)/point)>=threshold)
     {
      rate.c_uptrend++;
     }

//--- Check for Downtrend
   if((int)((close0-low1)/point)>=threshold)
     {
      rate.a_dntrend++;
     }
   else if((int)((close0-low2)/point)>=threshold)
     {
      rate.b_dntrend++;
     }
   else if((int)((close0-low3)/point)>=threshold)
     {
      rate.c_dntrend++;
     }
   return(true);
  }

Os dados de avaliação tratados são passados para o método AddRow(), que calcula os valores da probabilidade e das taxas de eficiência, fazendo a adição deles à tabela de resultados.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CProgram::AddRow(CTable &table,string pattern_name,RATING_SET &rate,int found,ENUM_TIMEFRAMES timeframe)
  {
   int row=m_total_row;
   double p1,p2,k1,k2;
   int sum1=0,sum2=0;
   sum1=rate.a_uptrend+rate.b_uptrend+rate.c_uptrend;
   sum2=rate.a_dntrend+rate.b_dntrend+rate.c_dntrend;
//---
   p1=(found>0)?(double)sum1/found*100:0;
   p2=(found>0)?(double)sum2/found*100:0;
   k1=(found>0)?(m_k1*rate.a_uptrend+m_k2*rate.b_uptrend+m_k3*rate.c_uptrend)/found:0;
   k2=(found>0)?(m_k1*rate.a_dntrend+m_k2*rate.b_dntrend+m_k3*rate.c_dntrend)/found:0;
//---
   table.AddRow(row);
   table.SetValue(0,row,pattern_name);
   table.SetValue(1,row,(string)found);
   table.SetValue(2,row,TimeframeToString(timeframe));
   table.SetValue(3,row,DoubleToString(p1,2),2);
   table.SetValue(4,row,DoubleToString(p2,2),2);
   table.SetValue(5,row,DoubleToString(k1,2),2);
   table.SetValue(6,row,DoubleToString(k2,2),2);
   ZeroMemory(rate);
   m_total_row++;
  }

Para eliminar as possíveis perguntas relacionadas ao uso do aplicativo, o vídeo abaixo exibe os exemplos de cálculos com diferentes configurações.


Recomendações para o teste dos padrões de Merrill:

  • Para permitir que o aplicativo funcione corretamente, nós precisamos dos dados históricos baixados para testar o símbolo de negociação selecionado.
  • Não é recomendável fazer o download de todos os padrões e períodos gráficos ao mesmo tempo, pois o tratamento dos resultados pode demorar muito tempo.
  • Os cenários mais comuns que podem causar dificuldades são acompanhados de dicas. Esses cenários incluem a não definição do período gráfico ou padrão, além de uma data inválida.
  • Tenha cuidado ao definir as propriedades do EA (Fig. 6). Se as configurações não estiverem claras, releia o artigo.
  • Neste artigo, o tema sobre o método de cálculo da eficiência de padrão foi discutido duas vezes Aqui, fornecemos o link para o artigo que aborda em detalhes o tópico. Lembre-se de que você precisa entender claramente como os coeficientes de ponderação na guia configurações afetam a avaliação dos padrões.

Conclusão

O arquivo anexado abaixo contém todos os arquivos descritos, que foram organizados em pastas correspondentes. Para uma execução correta do aplicativo, coloque a pasta MQL5 para o diretório raiz do terminal. Para abrir o diretório raiz do terminal, onde a pasta MQL5 está localizada, pressione a combinação de teclas Ctrl+Shift+D na plataforma MetaTrader 5 ou use o menu de contexto como é exibido na Fig. 7 abaixo.


Fig. 7. Abrindo a pasta MQL5 no diretório raiz da plataforma MetaTrader 5


Traduzido do russo pela MetaQuotes Software Corp.
Artigo original: https://www.mql5.com/ru/articles/7022

Arquivos anexados |
MQL5.zip (1736.93 KB)
Biblioteca para desenvolvimento fácil e rápido dos programas MetaTrader (parte XIV): O objeto Símbolo Biblioteca para desenvolvimento fácil e rápido dos programas MetaTrader (parte XIV): O objeto Símbolo

Neste artigo, nós criaremos a classe de objeto símbolo que deve ser o objeto base para a criação da coleção de símbolos. A classe nos permitirá os obter dados sobre os símbolos necessários para futuras análises e comparações.

Biblioteca para desenvolvimento fácil e rápido de programas para a MetaTrader (parte XIII): Eventos do objeto Conta Biblioteca para desenvolvimento fácil e rápido de programas para a MetaTrader (parte XIII): Eventos do objeto Conta

O artigo considera trabalhar com os eventos da conta para monitorar alterações importantes nas propriedades da conta que afetam a negociação automatizada. Nós já implementamos algumas funcionalidades para monitorar os eventos da conta no artigo anterior ao desenvolver a coleção de objetos da conta.

Biblioteca para criação simples e rápida de programas para MetaTrader (Parte XV): coleção de objetos-símbolo Biblioteca para criação simples e rápida de programas para MetaTrader (Parte XV): coleção de objetos-símbolo

No artigo, consideramos a criação de uma coleção de símbolos com base no objeto-símbolo abstrato básico criado no último artigo. Os descendentes de símbolos abstratos vão esclarecer os dados do símbolo e definir a disponibilidade das propriedades básicas do objeto-símbolo no programa. Esses objetos-símbolos vão ser distinguidos por sua afiliação a grupos (status do símbolo).

Biblioteca para criação simples e rápida de programas para MetaTrader (Parte XVI): eventos de coleção de símbolos Biblioteca para criação simples e rápida de programas para MetaTrader (Parte XVI): eventos de coleção de símbolos

No artigo, criaremos uma nova classe base - para todos os objetos da biblioteca - que adicionará funcionalidade de evento a todos os seus herdeiros, bem como uma classe para rastrear eventos de uma coleção de símbolos com base numa classe base nova. Além disso, alteraremos as classes e os eventos de conta para operarem sob a nova funcionalidade do objeto base.