English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
Assistente MQL5: Colocando Ordens, Stop Loss e Take Profits sobre os Preços Calculados. Extensão da Biblioteca Padrão

Assistente MQL5: Colocando Ordens, Stop Loss e Take Profits sobre os Preços Calculados. Extensão da Biblioteca Padrão

MetaTrader 5Exemplos | 14 janeiro 2015, 08:47
8 689 0
Andrey Shpilev
Andrey Shpilev

Introdução

A Biblioteca Padrão MQL5 constitui uma ajuda excelente no desenvolvimento de grandes projetos que requerem uma arquitetura rigorosa. O Assistente MQL5 permite utilizar o modo de diálogo para montar um grande projeto em questão de minutos, algo que, certamente é inestimável. O Assistente MQL5 agrupa de forma automatizada todas as partes do Expert e declara automaticamente os parâmetros dos módulos do Expert de acordo com seus manipuladores. Quando há um grande número de múltiplos módulos envolvidos, tal automação economiza muito o tempo e as operações de rotina.

Isso parece uma boa idéia, no entanto, há uma desvantagem óbvia - a capacidade do sistemas de negociação criados através do Assistente, baseado nas classes padrão são limitadas. Este artigo considera um método universal que permite prolongar significativamente a funcionalidade dos Experts criados. Quando este método for implementado, a compatibilidade com o Assistente e os módulos padrão continuará o mesmo.

A idéia do método é usar mecanismos de herança e polimorfismo em Programação Orientada a Objetos ou a criação de classes para substituir classes padrão no código dos Experts gerados. Desta forma, todas as vantagens do Assistente e da Biblioteca padrão são utilizados, o que resulta no desenvolvimento de um Expert com as capacidades desejadas. Para chegar lá, porém, o código tem de ser reduzido um pouco, apenas por quatro strings.

O objetivo prático deste artigo é a adicionar aos Experts gerados a capacidade de abrir ordens, Stop Loss e Take Profits nos níveis de preços desejados, não apenas na distância especificada a partir do preço atual.

Uma idéia semelhante foi discutida no artigo "Assistente MQL5: Como ensinar um EA a abrir ordens pendentes a qualquer preço". A desvantagem significativa da solução sugerida é a alteração "forçada" de um parâmetro do módulo do sinal de negociação do filtro subordinado. Esta abordagem não possibilita trabalhar adequadamente com vários módulos. Usar o Assistente para otimização do processo não faz sentido.

A implementação da colocação das ordens, bem como os Stop Loss e Take Profits a qualquer preço, as classes herdadas das padrão será considerado em detalhe mais abaixo. Dito isso, os conflitos entre os módulos são impossíveis. Espero que este artigo sirva de exemplo e inspire os leitores a escrever seus próprios melhoramentos na estrutura padrão e também que permita aos usuários executar a extensão da biblioteca desenvolvida.


1. Algoritmo padrão de Tomada de Decisões

Os Experts gerados no Assistente MQL5 são baseadas na instância de classe CExpert. O ponteiro para o objeto da classe CExpertSignal é declarada nesta classe. Em breve, este objeto será chamado de sinal principal por razões de concisão. O sinal principal contém ponteiros para os filtros subordinados (os módulos de sinal são os herdeiros da classe CExpertSignal).

Se não houver posições abertas e ordens, o Expert refere-se ao sinal principal para verificar se há alguma oportunidade para abrir uma posição sobre um novo tick. O sinal principal investiga os filtros subordinadas um por um e calcula a previsão média ponderada (direção) com base na previsão obtida. Se o valor exceder o limite (valor do parâmetro m_threshold_open no sinal principal), o Expert irá transferir os parâmetros da ordem e os resultados da verificação das condições do tipo bool. Se estas condições forem cumpridas, ou uma posição é aberta a preço de mercado ou a ordem fica pendente a uma certa distância dela (ver Fig. 1). Stop Loss podem ser colocados apenas a uma distância fixa. A diferença dos preços de abertura, Stop Loss e Take Profit sobre o preço de mercado são especificados nas configurações do Expert e armazenadaa no sinal principal, nas variáveis m_price_level, m_stop_level e m_take_level ​​respectivamente.

Assim, atualmente duas condições têm de ser cumpridas para a ordem ser colocada:

  1. Não deve haver posições em aberto para o símbolo atual;
  2. Valores absolutos da previsão média ponderada excede o valor limite, o que significa que a tendência é bastante forte).

Fig. 1. Padrão de tomada de decisão sobre a entrada no mercado

Fig. 1. Padrão de tomada de decisão sobre a entrada no mercado

O padrão atual de tomada de decisões na Fig. 1 limita significativamente a área de aplicação do Assistente MQL5. Estratégias com valores fixos de Stop Loss raramente são eficientes em negociações a longo prazo, devido à mudança na volatilidade. Sistemas que empregam de ordens pendentes geralmente exigem colocá-los em níveis calculados de forma dinâmica.


2. Algoritmo Modificado de Tomada de Decisões

Do ponto de vista de calcular os níveis e colocar ordens, esta é uma situação sem saída já que os módulos de sinal não podem gerar outra coisa senão um valor de previsão e o sinal principal não foi projetado para trabalhar com os níveis. A este respeito, é sugerido:

  • Introduzir um novo tipo de módulo de sinal (vamos chamá-los de módulos de preços) capaz de gerar os parâmetros de ordem;
  • Treinar o sinal principal para lidar com esses parâmetros, ou seja, selecionar os melhores e passá-los para o Expert.

Algoritmo modificado (Fig. 2) permite trabalhar com outros pedidos, além de ordens pendentes. A essência deste algoritmo é que ele separe o ponto de entrada (preço) da definição de uma tendência (previsão média ponderada). Isso significa que, para tomar uma decisão, a direção preferencial de negociação com filtros é definida e um conjunto de parâmetros de ordem com direção adequada obtida a partir de módulos de preços é selecionado. Se existirem vários conjuntos semelhantes disponíveis, o conjunto do módulo recebido com o maior peso (valor do parâmetro m_weight) sera escolhido. Se a direção foi determinada, mas não há pontos de entrada atualmente disponíveis, o Expert fica inativo.

Fig. 2. Padrão modificado de tomada de decisões sobre a entrada no mercado

Fig. 2. Padrão modificado de tomada de decisões sobre a entrada no mercado

Para colocar uma nova ordem, os seguintes requisitos devem ser atendidos:

  1. Não deve haver posições em aberto e ordens para o símbolo atual;
  2. O valor absoluto da previsão média ponderada deve exceder o valor limite;
  3. Foi encontrado pelo menos o preço de abertura da ordem.

O algoritmo da fig. 2 permite a manipulação de muitos pontos de entrada possíveis, filtrando-os por direção e escolhendo o melhor em um Expert.


3. Desenvolvimento de Classes Modificadas do Expert e do Módulo de Sinal

A extensão da Biblioteca é baseada em duas classes: CExpertSignalAdvanced e CExpertAdvanced, herdadas de CExpertSignal e CExpert respectivamente.

Todas as medidas sobre a adição de novas capacidades tem o objetvo de mudar as interfaces utilizadas para troca de dados entre diferentes blocos do Expert. Por exemplo, para implementar o algoritmo pelo padrão na Fig. 2 é necessária organizar a interação do sinal principal (classe CExpertSignalAdvanced) com módulos de preços (descendentes dessa classe). A atualização já coloca as ordens quando os dados mudam, implicando na interação do Expert (classe CExpertAdvanced) com o sinal principal.

Assim, nesta fase, vamos implementar o padrão da Fig. 2 para as posições de abertura e organizar atualização das ordens já colocadas quando os parâmetros mudam (por exemplo, quando um ponto de entrada mais favorável aparece). Vamos considerar a classe CExpertSignalAdvanced.

3.1. CExpertSignalAdvanced

Essa classe vai substituir seu antecessor no papel do sinal principal e tornar-se o base para os módulos de preços da mesma maneira que seu antecessor foi para os módulos de sinal.

class CExpertSignalAdvanced : public CExpertSignal
  {
protected:
   //---data members for storing parameters of the orders being placed
   double            m_order_open_long;         //opening price of the order to buy
   double            m_order_stop_long;         //Stop Loss of the order to buy
   double            m_order_take_long;         //Take Profit of the order to buy
   datetime          m_order_expiration_long;   //expiry time of the order to buy
   double            m_order_open_short;        //opening price of the order to sell
   double            m_order_stop_short;        //Stop Loss of the order to sell
   double            m_order_take_short;        //Take Profit of the order to sell
   datetime          m_order_expiration_short;  //expiry time of the order to sell
   //---             
   int               m_price_module;            //index of the first price module in the m_filters array
public:
                     CExpertSignalAdvanced();
                    ~CExpertSignalAdvanced();
   virtual void      CalcPriceModuleIndex() {m_price_module=m_filters.Total();}
   virtual bool      CheckOpenLong(double &price,double &sl,double &tp,datetime &expiration);
   virtual bool      CheckOpenShort(double &price,double &sl,double &tp,datetime &expiration);
   virtual double    Direction(void);		//calculating weighted average forecast based on the data received from signal modules
   virtual double    Prices(void);		//updating of parameters of the orders being placed according to the data received from price modules
   virtual bool      OpenLongParams(double &price,double &sl,double &tp,datetime &expiration);
   virtual bool      OpenShortParams(double &price,double &sl,double &tp,datetime &expiration);
   virtual bool      CheckUpdateOrderLong(COrderInfo *order_ptr,double &open,double &sl,double &tp,datetime &ex);
   virtual bool      CheckUpdateOrderShort(COrderInfo *order_ptr,double &open,double &sl,double &tp,datetime &ex);
   double            getOpenLong()              { return m_order_open_long;         }
   double            getOpenShort()             { return m_order_open_short;        }
   double            getStopLong()              { return m_order_stop_long;         }
   double            getStopShort()             { return m_order_stop_short;        }
   double            getTakeLong()              { return m_order_take_long;         }
   double            getTakeShort()             { return m_order_take_short;        }
   datetime          getExpLong()               { return m_order_expiration_long;   }
   datetime          getExpShort()              { return m_order_expiration_short;  }
   double            getWeight()                { return m_weight;                  }
  };

Os membros de dados para armazenamento de parâmetros de ordem foram declarados na classe CExpertSignalAdvanced. Os valores dessas variáveis ​​são atualizados no método Prices(). Estas variáveis ​​atuam como um buffer.

Em seguida, o parâmetro m_price_module fica declarado. Ele armazena o índice do primeiro módulo de preço no array m_filters declarado em CExpertSignal. Este array contém os ponteiros para os módulos de sinal incluído. A principio, se guardam os módulos padrão (filtros) no início do array. Em seguida, a partir do índice m_price_module, os módulos de preços chegam. Para evitar a necessidade de mudança dos métodos de inicialização de indicadores e das séries temporais, foi decidido armazenar tudo em um array. Além disso, existe a possibilidade de incluir 64 módulos através de uma matriz e isso geralmente é suficiente.

Além disso, os métodos auxiliares foram declarados na classe CExpertSignalAdvanced para a obtenção de valores de membros de dados protegidos. Seus nomes começam com get (Ver declaração de classe).

3.1.1. Construtor

O construtor CExpertSignalAdvanced inicializa as variáveis ​​declaradas dentro da classe:

CExpertSignalAdvanced::CExpertSignalAdvanced()
  {
   m_order_open_long=EMPTY_VALUE;
   m_order_stop_long=EMPTY_VALUE;
   m_order_take_long=EMPTY_VALUE;
   m_order_expiration_long=0;
   m_order_open_short=EMPTY_VALUE;
   m_order_stop_short=EMPTY_VALUE;
   m_order_take_short=EMPTY_VALUE;
   m_order_expiration_short=0;
   m_price_module=-1;
  }

3.1.2. CalcPriceModuleIndex()

O método CalcPriceModuleIndex() atribui em m_price_module o número atual de elementos do array, que é igual ao índice do seguinte módulo adicionado. Este método é chamado antes de adicionar o primeiro módulo de preço. O corpo da função fica na declaração da classe.

virtual void      CalcPriceModuleIndex() {m_price_module=m_filters.Total();}

3.1.3. CheckOpenLong(...) e CheckOpenShort(...)

O método CheckOpenLong(...) é chamado a partir da instância de classe CExpert e funciona como descrito abaixo:

  1. Verifica se há módulos de preços incluídos. Se não houver nenhum, em seguida, chama o método epônimo da classe pai;
  2. Recebe a previsão média ponderada (direção) do método Direction();
  3. Verifica se as condições de entrada são atendidas através da comparação da direção com EMPTY_VALUE e o valor da limiar de m_threshold_open;
  4. Renova valores dos parâmetros de ordem pelo método Prices(), e passa eles para o Expert com a função OpenLongParams(...). Salva o resultado desta função;
  5. Retorna o resultado guardado.
bool CExpertSignalAdvanced::CheckOpenLong(double &price,double &sl,double &tp,datetime &expiration)
  {
//--- if price modules were not found, call the method of the basic class CExpertSignal
   if(m_price_module<0)
      return(CExpertSignal::CheckOpenLong(price,sl,tp,expiration));

   bool   result   =false;
   double direction=Direction();
//--- prohibitive signal
   if(direction==EMPTY_VALUE)
      return(false);
//--- check for exceeding the threshold
   if(direction>=m_threshold_open)
     {
      Prices();
      result=OpenLongParams(price,sl,tp,expiration);//there's a signal if m_order_open_long!=EMPTY_VALUE
     }
//--- return the result
   return(result);
  }

CheckOpenShort(...) tem o mesmo princípio de funcionamento e é usado da mesma forma, por isso não vamos considerá-lo.

3.1.4 Direction()

O método Direction() consulta os filtros e calcula a previsão média ponderada. Este método é muito similar a um método epônimo da classe pai CExpertSignal com excepção de que no loop nós não referimos a todos os elementos do array m_filters, mas apenas para aqueles que possuem um índice que varia de 0 para m_price_module menor. Todo o resto é semelhante ao CExpertSignal::Direction().

double CExpertSignalAdvanced::Direction(void)
  {
   long   mask;
   double direction;
   double result=m_weight*(LongCondition()-ShortCondition());
   int    number=(result==0.0)? 0 : 1;      // number of queried modules
//--- loop by filters
   for(int i=0;i<m_price_module;i++)
     {
      //--- mask for bitmaps (variables, containing flags)
      mask=((long)1)<<i;
      //--- checking for a flag of ignoring a filter signal
      if((m_ignore&mask)!=0)
         continue;
      CExpertSignal *filter=m_filters.At(i);
      //--- checking for a pointer
      if(filter==NULL)
         continue;
      direction=filter.Direction();
      //--- prohibitive signal
      if(direction==EMPTY_VALUE)
         return(EMPTY_VALUE);
      if((m_invert&mask)!=0)
         result-=direction;
      else
         result+=direction;
      number++;
     }
//--- averaging the sum of weighted forecasts
   if(number!=0)
      result/=number;
//--- return the result
   return(result);
  }

3.1.5. Prices()

O método Prices() itera sobre a segunda parte do array m_filters começando do índice m_price_module até o fim. Isto consulta os módulos de preços e renova os valores das variáveis ​​de classe com as funções OpenLongParams(...) e OpenShortParams(...). Antes do ciclo, os valores dos parâmetros são eliminadas.

Durante o ciclo, os valores dos parâmetros são sobrescritos caso o peso do módulo de preço atual (m_weight) for maior do que a dos módulos previamente consultados, o que proporciona os valores. Como resultado, ambos os parâmetros vazios são deixados (se nada foi encontrado) ou os parâmetros com o melhor peso que está disponível no momento da chamada de um método.

double CExpertSignalAdvanced::Prices(void)
  {
   m_order_open_long=EMPTY_VALUE;
   m_order_stop_long=EMPTY_VALUE;
   m_order_take_long=EMPTY_VALUE;
   m_order_expiration_long=0;
   m_order_open_short=EMPTY_VALUE;
   m_order_stop_short=EMPTY_VALUE;
   m_order_take_short=EMPTY_VALUE;
   m_order_expiration_short=0;
   int    total=m_filters.Total();
   double last_weight_long=0;
   double last_weight_short=0;
//--- cycle for price modules
   for(int i=m_price_module;i<total;i++)
     {   
      CExpertSignalAdvanced *prm=m_filters.At(i);
      if(prm==NULL)
         continue;
//--- ignore the current module if it has returned EMPTY_VALUE
      if(prm.Prices()==EMPTY_VALUE)continue;
      double weight=prm.getWeight();
      if(weight==0.0)continue;
//--- select non-empty values from modules with the greatest weight
      if(weight>last_weight_long && prm.getExpLong()>TimeCurrent())
         if(prm.OpenLongParams(m_order_open_long,m_order_stop_long,m_order_take_long,m_order_expiration_long))
            last_weight_long=weight;
      if(weight>last_weight_short && prm.getExpShort()>TimeCurrent())
         if(prm.OpenShortParams(m_order_open_short,m_order_stop_short,m_order_take_short,m_order_expiration_short))
            last_weight_short=weight;
     }
   return(0);
  }

3.1.6. OpenLongParams(...) e OpenShortParams(...)

Dentro da classe CExpertSignalAdvanced , o método OpenLongParams(...) passa o valor do parâmetro da ordem de compra por referência das variáveis ​​de classe para os parâmetros de entrada.

O papel deste método na classe pai foi um pouco diferente. Este foi o cálculo dos parâmetros exigidos com base no preço de mercado e os recuos especificados no sinal principal. Agora isso só passa os parâmetros prontos. Se o preço de abertura está correto (não igual a EMPTY_VALUE), em seguida, o método retorna true, caso contrário false.

bool CExpertSignalAdvanced::OpenLongParams(double &price,double &sl,double &tp,datetime &expiration)
  {
   if(m_order_open_long!=EMPTY_VALUE)
     {
      price=m_order_open_long;
      sl=m_order_stop_long;
      tp=m_order_take_long;
      expiration=m_order_expiration_long;
      return(true);
     }
   return(false);
  }

Nós não vamos considerar o OpenShortParams(...) já que seu princípio de funcionamento é o mesmo e ele é utilizado de forma semelhante.

3.1.7. CheckUpdateOrderLong(...) e CheckUpdateOrderShort(...)

Os métodos CheckUpdateOrderLong(...) e CheckUpdateOrderShort(...) são chamados com a classe CExpertAdvanced. Eles são usados ​​para atualizar uma ordem pendente já aberta de acordo com os últimos níveis de preços.

Vamos examinar o método CheckUpdateOrderLong(...) mais de perto. Os primeiros níveis do preço são atualizados ao chamar o método Prices(...), em seguida, ele verifica se as atualizações de dados foi realizada para eliminar eventuais erros de modificação. Finalmente, o método OpenLongParams(...) é chamado para a passar os dados atualizados e retornar o resultado.

bool CExpertSignalAdvanced::CheckUpdateOrderLong(COrderInfo *order_ptr,double &open,double &sl,double &tp,datetime &ex)
  {
   Prices();   //update prices
//--- check for changes
   double point=m_symbol.Point();
   if(   MathAbs(order_ptr.PriceOpen() - m_order_open_long)>point
      || MathAbs(order_ptr.StopLoss()  - m_order_stop_long)>point
      || MathAbs(order_ptr.TakeProfit()- m_order_take_long)>point
      || order_ptr.TimeExpiration()!=m_order_expiration_long)
      return(OpenLongParams(open,sl,tp,ex));
//--- update is not required   
   return (false);
  }

CheckUpdateOrderShort(...) não será considerado, uma vez que ele opera de forma semelhante e é aplicado da mesma maneira.

3.2. CExpertAdvanced

Mudanças na classe de Expert diz respeito somente a modificação das ordens em aberto de acordo com os dados atualizados nos preços do sinal principal. A declaração da classe CExpertAdvanced é apresentada abaixo.

class CExpertAdvanced : public CExpert
  {
protected:
   virtual bool      CheckTrailingOrderLong();
   virtual bool      CheckTrailingOrderShort();
   virtual bool      UpdateOrder(double price,double sl,double tp,datetime ex);
public:
                     CExpertAdvanced();
                    ~CExpertAdvanced();
  };

Como podemos ver, os métodos são poucos, o construtor e o destrutor estão vazios.

3.2.1. CheckTrailingOrderLong() e CheckTrailingOrderShort()

O método CheckTrailingOrderLong() sobrescreve um método epônimo da classe base e chama o método CheckUpdateOrderLong(...) do sinal principal para descobrir a necessidade de modificar a ordem. Se a modificação é necessária, o método UpdateOrder (...) é chamado e o resultado é retornado.

bool CExpertAdvanced::CheckTrailingOrderLong(void)
  {
   CExpertSignalAdvanced *signal_ptr=m_signal;
//--- check for the opportunity to modify the order to buy
   double price,sl,tp;
   datetime ex;
   if(signal_ptr.CheckUpdateOrderLong(GetPointer(m_order),price,sl,tp,ex))
      return(UpdateOrder(price,sl,tp,ex));
//--- return with no actions taken
   return(false);
  }

O método CheckTrailingOrderShort() é semelhante e é usado da mesma maneira.

3.2.2. UpdateOrder()

A função UpdateOrder() começa com a verificação por um preço relevante (sem ser EMPTY_VALUE). Se não houver nenhum, a ordem é excluída, caso contrário a ordem é modificada de acordo com os parâmetros recebidos.

bool CExpertAdvanced::UpdateOrder(double price,double sl,double tp,datetime ex)
  {
   ulong  ticket=m_order.Ticket();
   if(price==EMPTY_VALUE)
      return(m_trade.OrderDelete(ticket));
//--- modify the order, return the result
   return(m_trade.OrderModify(ticket,price,sl,tp,m_order.TypeTime(),ex));
  }

O desenvolvimento de herdeiros das classes padrão está completo.


4. Desenvolvimento dos Módulos do Preço

Nós já temos a base para a criação de Experts que colocam ordens e Stop Loss nos níveis calculados. Para ser preciso, temos classes prontas para trabalhar com os níveis de preços. Agora apenas os módulos para gerar esses níveis são deixados para ser escrito.

O processo de desenvolvimento dos módulos de preços são semelhantes aos módulos de escrita dos sinais de negociação. A única diferença entre elas é que é o método Prices() responsável pela atualização dos preços dentro do módulo tem de ser sobrescrito e não LongCondition(), ShortCondition() ou Direction() como módulos de sinal. O ideal é que o leitor tenha uma ideia clara sobre o desenvolvimento dos módulos de sinal. Os artigos "Crie o seu próprio robô de negociação em 6 passos!" e "Gerador de sinal de negócios baseado em um indicador personalizado" podem ser úteis nisso.

O código de vários módulos de preços irá servir de exemplo.

4.1. Módulo de Preço baseado no indicador "Delta ZigZag"

O indicador Delta ZigZag desenha os níveis pelo número especificado dos vários últimos picos. Se o preço cruzae esses níveis, significa uma provável inversão de tendência.

O objetivo do módulo de preço é pegar o nível de entrada do buffer do indicador, encontrar o extremo local mais próximo para colocar Stop Loss, calcular o Take Profit multiplicando o Stop Loss pelo coeficiente especificado nas configurações.

Fig. 3. Ilustração da operação do módulo de preço no indicador Delta ZigZag usando a ordem de compra como um exemplo

Fig. 3. Ilustração da operação do módulo de preço no indicador Delta ZigZag usando a ordem de compra como um exemplo

Fig 3. representa os níveis gerados pelo módulo de preço. Antes da ordem ser acionada, o Stop Loss e Take Profit se altera seguindo as atualizações da mínima.

4.1.1. Módulo Descriptor

// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=DeltaZZ Price Module                                       |
//| Type=SignalAdvanced                                              |
//| Name=DeltaZZ Price Module                                        |
//| ShortName=DeltaZZ_PM                                             |
//| Class=CPriceDeltaZZ                                              |
//| Page=not used                                                    |
//| Parameter=setAppPrice,int,1, Applied price: 0 - Close, 1 - H/L   |
//| Parameter=setRevMode,int,0, Reversal mode: 0 - Pips, 1 - Percent |
//| Parameter=setPips,int,300,Reverse in pips                        |
//| Parameter=setPercent,double,0.5,Reverse in percent               |
//| Parameter=setLevels,int,2,Peaks number                           |
//| Parameter=setTpRatio,double,1.6,TP:SL ratio                      |
//| Parameter=setExpBars,int,10,Expiration after bars number         |
//+------------------------------------------------------------------+
// wizard description end

Os primeiros cinco parâmetros no descriptor são necessários para a criação do indicador em uso. Em seguida, vêm o coeficiente para o cálculo de Take Profit baseado no Stop Loss e no tempo de expiração das barras para as ordens a partir do módulo do preço atual.

4.1.2. Declaração da Classe

class CPriceDeltaZZ : public CExpertSignalAdvanced
  {
protected:
   CiCustom          m_deltazz;           //object of the DeltaZZ indicator
   //--- module settings
   int               m_app_price;
   int               m_rev_mode;
   int               m_pips;
   double            m_percent;
   int               m_levels;
   double            m_tp_ratio;          //tp:sl ratio
   int               m_exp_bars;          //lifetime of the orders in bars
   //--- method of indicator initialization
   bool              InitDeltaZZ(CIndicators *indicators);
   //--- helper methods
   datetime          calcExpiration() { return(TimeCurrent()+m_exp_bars*PeriodSeconds(m_period)); }
   double            getBuySL();          //function for searching latest minimum of ZZ for buy SL
   double            getSellSL();         //function for searching latest maximum of ZZ for sell SL
public:
                     CPriceDeltaZZ();
                    ~CPriceDeltaZZ();
   //--- methods of changing module settings
   void              setAppPrice(int ap)           { m_app_price=ap; }
   void              setRevMode(int rm)            { m_rev_mode=rm;  }
   void              setPips(int pips)             { m_pips=pips;    }
   void              setPercent(double perc)       { m_percent=perc; }
   void              setLevels(int rnum)           { m_levels=rnum;  }
   void              setTpRatio(double tpr)        { m_tp_ratio=tpr; }
   void              setExpBars(int bars)          { m_exp_bars=bars;}
   //--- method of checking correctness of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating indicators
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- main method of price module updating the output data
   virtual double    Prices();
  }; 

Dados protegidos - objeto do indicador do tipo CiCustom e parâmetros de acordo com os tipos especificados no descriptor são declarados no módulo.

4.1.3. Construtor

O construtor inicializa os parâmetros da classe com os valores padrão. Mais tarde, esses valores são inicializados mais uma vez quando o módulo é incluído no sinal principal de acordo com os parâmetros de entrada do Expert.

CPriceDeltaZZ::CPriceDeltaZZ() : m_app_price(1),
                                 m_rev_mode(0),
                                 m_pips(300),
                                 m_percent(0.5),
                                 m_levels(2),
                                 m_tp_ratio(1),
                                 m_exp_bars(10)
  {
  }

4.1.4. ValidationSettings()

ValidationSettings() é um método importante para verificar os parâmetros de entrada. Se os valores dos parâmetros do módulo são inválidos, o resultado false é retornado e uma mensagem de erro é impressa no diário.

bool CPriceDeltaZZ::ValidationSettings(void)
  {
//--- checking for settings of additional filters
   if(!CExpertSignal::ValidationSettings())
      return(false);
//--- initial data check
   if(m_app_price<0 || m_app_price>1)
     {
      printf(__FUNCTION__+": Applied price must be 0 or 1");
      return(false);
     }
   if(m_rev_mode<0 || m_rev_mode>1)
     {
      printf(__FUNCTION__+": Reversal mode must be 0 or 1");
      return(false);
     }
   if(m_pips<10)
     {
      printf(__FUNCTION__+": Number of pips in a ray must be at least 10");
      return(false);
     }
   if(m_percent<=0)
     {
      printf(__FUNCTION__+": Percent must be greater than 0");
      return(false);
     }
   if(m_levels<1)
     {
      printf(__FUNCTION__+": Ray Number must be at least 1");
      return(false);
     }
   if(m_tp_ratio<=0)
     {
      printf(__FUNCTION__+": TP Ratio must be greater than zero");
      return(false);
     }
   if(m_exp_bars<0)
     {
      printf(__FUNCTION__+": Expiration must be zero or positive value");
      return(false);
     }
//--- parameter check passed
   return(true);
  } 

4.1.5. InitIndicators(...)

O método InitIndicators(...) chama um método epônimo da classe base e inicializa o indicador do módulo atual pelo método InitDeltaZZ(...).

bool CPriceDeltaZZ::InitIndicators(CIndicators *indicators)
  {
//--- initialization of indicator filters
   if(!CExpertSignal::InitIndicators(indicators))
      return(false);
//--- creating and initializing of custom indicator
   if(!InitDeltaZZ(indicators))
      return(false);
//--- success
   return(true);
  }

4.1.6. InitDeltaZZ(...)

O método InitDeltaZZ(...) adiciona o objeto do indicador personalizado para a coleção e cria o novo indicador "Delta ZigZag".

bool CPriceDeltaZZ::InitDeltaZZ(CIndicators *indicators)
  {
//--- adds to collection
   if(!indicators.Add(GetPointer(m_deltazz)))
     {
      printf(__FUNCTION__+": error adding object");
      return(false);
     }
//--- specifies indicator parameters
   MqlParam parameters[6];
//---
   parameters[0].type=TYPE_STRING;
   parameters[0].string_value="deltazigzag.ex5";
   parameters[1].type=TYPE_INT;
   parameters[1].integer_value=m_app_price;
   parameters[2].type=TYPE_INT;
   parameters[2].integer_value=m_rev_mode;
   parameters[3].type=TYPE_INT;
   parameters[3].integer_value=m_pips;
   parameters[4].type=TYPE_DOUBLE;
   parameters[4].double_value=m_percent;
   parameters[5].type=TYPE_INT;
   parameters[5].integer_value=m_levels;
//--- object initialization
   if(!m_deltazz.Create(m_symbol.Name(),m_period,IND_CUSTOM,6,parameters))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }
//--- number of the indicator buffers
   if(!m_deltazz.NumBuffers(5)) return(false);
//--- ок
   return(true);
  }

Após a conclusão bem sucedida dos métodos ValidationSettings(), InitDeltaZZ(...) e InitIndicators(...), O módulo é inicializado e está pronto para o trabalho.

4.1.7. Prices()

Este método é fundamental para o módulo de preço. Este é o lugar onde os parâmetros da ordem são atualizados. Seus valores são repassados ​​ao sinal principal. Este método retorna o resultado da operação do tipo double. Isso foi implementado principalmente para desenvolvimentos futuros. O resultado do método Prices() pode codificar algumas situações e acontecimentos peculiares de modo que o sinal principal poderia lidar com eles de acordo. Atualmente, apenas a manipulação do valor retornado EMPTY_VALUE é desejado. Ao receber esse resultado, o sinal principal vai ignorar os parâmetros sugeridos pelo módulo.

Algoritmo de operação do método Prices() deste módulo:

  1. Pega os preços de abertura das ordens dos buffers 3 e 4 do indicador para realizar compras e vendas, respectivamente;
  2. Zera os parâmetros finais das ordens;
  3. Verifica o preço para comprar. Se houver, identifica o nível para colocar o Stop Loss pelo método getBuySL(), calcula o nível de Take Profit pelo valor de Stop Loss e do preço de abertura e calcula o tempo de expiração da ordem;
  4. Verifica o preço para vender. Caso seja detectado, encontra o nível para colocar o Stop Loss pelo método getSellSL (), calcula o nível de Take Profit pelo valor de Stop Loss e e do preço de abertura e calcula o tempo de expiração da ordem;
  5. Saída.
Condições de presença dos preços de compra e venda são mutuamente exclusivos devido a alguns aspectos operacionais do indicador "Delta ZigZag". Os Buffers 3 e 4 são desenhados como pontos por padrão (ver Fig. 3).

double CPriceDeltaZZ::Prices(void)
  {
   double openbuy =m_deltazz.GetData(3,0);//receive the last value from buffer 3
   double opensell=m_deltazz.GetData(4,0);//receive the last value from buffer 4
//--- clear parameter values
   m_order_open_long=EMPTY_VALUE;
   m_order_stop_long=EMPTY_VALUE;
   m_order_take_long=EMPTY_VALUE;
   m_order_expiration_long=0;
   m_order_open_short=EMPTY_VALUE;
   m_order_stop_short=EMPTY_VALUE;
   m_order_take_short=EMPTY_VALUE;
   m_order_expiration_short=0;
   int digits=m_symbol.Digits();
//--- check for the prices to buy
   if(openbuy>0)//if buffer 3 is not empty
     {
      m_order_open_long=NormalizeDouble(openbuy,digits);
      m_order_stop_long=NormalizeDouble(getBuySL(),digits);
      m_order_take_long=NormalizeDouble(m_order_open_long + m_tp_ratio*(m_order_open_long - m_order_stop_long),digits);
      m_order_expiration_long=calcExpiration();
     }
//--- check for the prices to sell
   if(opensell>0)//if buffer 4 is not empty
     {
      m_order_open_short=NormalizeDouble(opensell,digits);
      m_order_stop_short=NormalizeDouble(getSellSL(),digits);
      m_order_take_short=NormalizeDouble(m_order_open_short - m_tp_ratio*(m_order_stop_short - m_order_open_short),digits);
      m_order_expiration_short=calcExpiration();
     }
   return(0);
  }

4.1.8. getBuySL() e getSellSL()

Os métodos getBuySL() e getSellSL() estão procurando os mínimos e máximo locais respectivamente para colocar os Stop Loss. O último valor diferente de zero em um buffer relevante  o nível de preços do último extremo local é procurado em cada método.

double CPriceDeltaZZ::getBuySL(void)
  {
   int i=0;
   double sl=0.0;
   while(sl==0.0)
     {
      sl=m_deltazz.GetData(0,i);
      i++;
     }
   return(sl);
  }
double CPriceDeltaZZ::getSellSL(void)
  {
   int i=0;
   double sl=0.0;
   while(sl==0.0)
     {
      sl=m_deltazz.GetData(1,i);
      i++;
     }
   return(sl);
  }

4.2. Módulo do Preço baseado na Barra Interna

A barra interna é um dos modelos (padrões) mais amplamente utilizados na negociação sem nenhum indicador chamado de Price action. Uma barra interna é um barra contendo sua máxima e mínima entre os extremos da barra anterior. Uma barra interna indica o início de consolidação ou uma possível reversão do movimento de preços.

Na Fig. 4 as barras internas estão dentro das elipses vermelhas. Quando um barra interna é detectada, o módulo de preço gera os preços de abertura das ordens buystop e sellstop no extremo da barra anterior da barra interna.

Os preços de abertura são os níveis de Stop Loss das ordens opostas. O Take Profit é calculado da mesma forma que no módulo discutido acima - multiplicando-se o nível de Stop Loss pelo coeficiente especificado nas configurações. Os preços de abertura e Stop Loss são marcados com linhas horizontais vermelhas e os Take Profits com as verdes.

Fig. 4. Ilustração das barras internas e os níveis do módulo de preço

Fig. 4. Ilustração das barras internas e os níveis do módulo de preço

Na Fig. 4 as ordens de venda não foram colocados já que a tendência está próxima. No entanto, o módulo de preço gera níveis de entrada em ambos os sentidos. Alguns níveis de Take Profit estão fora de ação.

Ao contrário do módulo anterior, este algoritmo é simples e não requer a inicialização de indicadores. Há pouca código no módulo, ele é apresentado abaixo na íntegra. Nós não vamos analisar cada função separadamente.

#include <Expert\ExpertSignalAdvanced.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Inside Bar Price Module                                    |
//| Type=SignalAdvanced                                              |
//| Name=Inside Bar Price Module                                     |
//| ShortName=IB_PM                                                  |
//| Class=CPriceInsideBar                                            |
//| Page=not used                                                    |
//| Parameter=setTpRatio,double,2,TP:SL ratio                        |
//| Parameter=setExpBars,int,10,Expiration after bars number         |
//| Parameter=setOrderOffset,int,5,Offset for open and stop loss     |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CPriceInsideBar                                            |
//| Purpose: Class of the generator of price levels for orders based |
//|          on the "inside bar" pattern.                            |
//| Is derived from the CExpertSignalAdvanced class.                 |
//+------------------------------------------------------------------+
class CPriceInsideBar : public CExpertSignalAdvanced
  {
protected:
   double            m_tp_ratio;          //tp:sl ratio
   int               m_exp_bars;          //lifetime of the orders in bars
   double            m_order_offset;      //shift of the opening and Stop Loss levels
   datetime          calcExpiration()  { return(TimeCurrent()+m_exp_bars*PeriodSeconds(m_period)); }
public:
                     CPriceInsideBar();
                    ~CPriceInsideBar();
   void              setTpRatio(double ratio){ m_tp_ratio=ratio; }
   void              setExpBars(int bars)    { m_exp_bars=bars;}
   void              setOrderOffset(int pips){ m_order_offset=m_symbol.Point()*pips;}
   bool              ValidationSettings();
   double            Prices();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CPriceInsideBar::CPriceInsideBar()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CPriceInsideBar::~CPriceInsideBar()
  {
  }
//+------------------------------------------------------------------+
//| Validation of protected settings                                 |
//+------------------------------------------------------------------+
bool CPriceInsideBar::ValidationSettings(void)
  {
//--- verification of the filter parameters
   if(!CExpertSignal::ValidationSettings())
      return(false);
//--- initial data check
  if(m_tp_ratio<=0)
     {
      printf(__FUNCTION__+": TP Ratio must be greater than zero");
      return(false);
     }
   if(m_exp_bars<0)
     {
      printf(__FUNCTION__+": Expiration must be zero or positive value");
      return(false);
     }
//--- check passed
   return(true);
  }
//+------------------------------------------------------------------+
//| Price levels refreshing                                          |
//+------------------------------------------------------------------+
double CPriceInsideBar::Prices(void)
  {
   double h[2],l[2];
   if(CopyHigh(m_symbol.Name(),m_period,1,2,h)!=2 || CopyLow(m_symbol.Name(),m_period,1,2,l)!=2)
      return(EMPTY_VALUE);
//--- check for inside bar      
   if(h[0] >= h[1] && l[0] <= l[1])
     {
      m_order_open_long=h[0]+m_order_offset;
      m_order_stop_long=l[0]-m_order_offset;
      m_order_take_long=m_order_open_long+(m_order_open_long-m_order_stop_long)*m_tp_ratio;
      m_order_expiration_long=calcExpiration();
      
      m_order_open_short=m_order_stop_long;
      m_order_stop_short=m_order_open_long;
      m_order_take_short=m_order_open_short-(m_order_stop_short-m_order_open_short)*m_tp_ratio;
      m_order_expiration_short=m_order_expiration_long;
      return(0);
     }
   return(EMPTY_VALUE);
  }  
//+------------------------------------------------------------------+

No método Prices() deste módulo, o retorno do resultado EMPTY_VALUE é usado para demonstrar ao sinal principal de que não existem níveis de preços disponíveis.

4.3. Módulo de Preço Baseado na Barra Externa

A barra externa é outro padrão popular de Price Action também chamada de "absorção". A barra exterma é chamado assim porque suas máximas e mínimas se sobrepõe as máximas e mínimas da barra anterior. O aparecimento de uma barra externa é uma indicação de aumento da volatilidade seguido por um movimento direcionado do preço.

Na Fig. 5 as barras externas foram marcadas pelas elipses vermelhas. Ao detectar uma barra externa, o módulo de preço gera os preços de abertura das ordens buystop e sellstop em seu extremo.

Os preços de abertura são os níveis de Stop Loss das ordens opostas. O Take Profit é calculado da mesma forma que no módulo discutido acima - multiplicando-se o nível de Stop Loss pelo coeficiente especificado nas configurações. Os preços de abertura e Stop Loss são marcados com linhas horizontais vermelhas e os Take Profits com as verdes.

Fig. 5. Ilustração das barras externas e os níveis do módulo de preço

Fig. 5. Ilustração das barras externas e os níveis do módulo de preço

Na Fig. 5 as barras foram marcadas com elipses vermelhas. As linhas horizontais refletem os preços de abertura das ordens pendentes geradas pelo módulo de preço.

Neste caso, somente ordens de venda são abertas, porque há uma tendência de baixa. O funcionamento deste módulo é essencialmente similar ao anterior. A única diferença entre o seu código é somente o método Prices(), outras partes são exatamente os mesmos e têm os mesmos nomes. Abaixo está o código de Prices().

double CPriceOutsideBar::Prices(void)
{
   double h[2],l[2];
   if(CopyHigh(m_symbol.Name(),m_period,1,2,h)!=2 || CopyLow(m_symbol.Name(),m_period,1,2,l)!=2)
      return(EMPTY_VALUE);
//--- check of outside bar
   if(h[0] <= h[1] && l[0] >= l[1])
   {
      m_order_open_long=h[1]+m_order_offset;
      m_order_stop_long=l[1]-m_order_offset;
      m_order_take_long=m_order_open_long+(m_order_open_long-m_order_stop_long)*m_tp_ratio;
      m_order_expiration_long=calcExpiration();
      
      m_order_open_short=m_order_stop_long;
      m_order_stop_short=m_order_open_long;
      m_order_take_short=m_order_open_short-(m_order_stop_short-m_order_open_short)*m_tp_ratio;
      m_order_expiration_short=m_order_expiration_long;
      return(0);
   }
   return(EMPTY_VALUE);
} 

4.4. Teste de Desempenho do Módulo

Na próxima seção três exemplos de módulos são testados para verificá-los individualmente e, em seguida, junta-se em um Expert e se certificam de que o sistema funcionará como foi projetado. Como resultado, quatro Experts são gerados. Módulo de sinal de negociação com base no indicador Awesome Oscillator trabalhando no tempo H12, ele é usado como um filtro em cada um dos Experts gerados. Os módulos do preço estão trabalhando em H6.

Gestão do dinheiro: lote fixo e stop móvel não são utilizados. Todos os testes são realizados nas cotações EURUSD a partir da conta de demonstração do servidor MetaQuotes-Demo para o período de 01/01/2013 até 01/06/2014. Versão do Terminal: 5.00, nuild 965 (junho, 27 de 2014).

Para manter isto simples, os resultados dos testes são representados apenas pelos gráficos do saldo. Eles são o suficiente para obter o comportamento dos Experts em cada caso particular.

4.4.1. Testando o Módulo com Base no Indicador Delta ZigZag

Fig. 6. Gráfico do saldo ao testar o módulo de preço com base no Delta ZigZag

Fig. 6. Gráfico do saldo ao testar o módulo de preço com base no indicador "Delta ZigZag"

4.4.2. Testando o Módulo com Base no Padrão "Barra interna"

Fig. 7. Gráfico do saldo ao testar o módulo de preço com base na barra interna

Fig. 7. Gráfico do saldo ao testar o módulo de preço com base na barra interna

Olhando para a Fig. 7., deve-se ter em mente que o objetivo dos testes nesta etapa é verificar o desempenho do código, não para obter uma estratégia vencedora.

4.4.3. Testando o Módulo com Base no Padrão "Barra Externa"

Fig. 8. Gráfico do saldo ao testar o módulo de preço com base na barra externa

Fig. 8. Gráfico do saldo ao testar o módulo de preço com base na barra externa

4.4.4. Teste Conjunto dos Módulos de Preço Desenvolvidos

Levando-se em consideração os resultados dos testes anteriores, os módulos de preços com base em DeltaZigZag, barra interna e externa receberam coeficientes de peso igual a 1, 0.5 e 0.7, respectivamente. Os coeficientes de peso definem as prioridades dos módulos de preços.

Fig. 9. Gráfico do saldo ao testar o Expert com base nos três módulos de preço.

Fig. 9. Gráfico do saldo ao testar o Expert com base nos três módulos de preço.

Em todas as fases de testes, todas as operações realizadas foram minuciosamente analisadas segundo o gráfico de preço. Erros de estratégia e desvios não foram elicitados. Todos os programas sugeridos estão anexados a este artigo sendo que você pode testá-los.


5. Instruções de Utilização

Nós vamos considerar as etapas de desenvolvimento do Expert usando a extensão desenvolvida no exemplo do Expert com três módulos de preços e o Awesome Oscillator como um filtro.

Antes que a geração começe, certifique-se de que os arquivos de cabeçalho "CExpertAdvanced.mqh" e "CExpertSignalAdvanced.mqh" estão no catálogo do terminal MetaTrader 5 na pasta MQL5/Include/Expert e os arquivos dos módulos de preços estão na pasta MQL5/Include/Expert/MySignal. Antes de lançar o Expert, garanta que os indicadores compilados estão na pasta MQL5/Indicators. Neste caso, é o arquivo "DeltaZigZag.ex5". Em anexo, todos os arquivos estão em seus lugares. Tudo o que precisamos é descomprimir estes arquivos em uma pasta com o terminal MetaTrader 5 e confirmar os catálogos combinados.

5.1. Geração do Expert

Para iniciar a geração do Expert, selecione "Arquivo"->"Novo" no MetaEditor.

Fig. 10. Criando um novo Expert usando o Assistente MQL5

Fig. 10. Criando um novo Expert usando o Assistente MQL5

Na nova janela, selecione "Expert Advisor (gerar)" e pressione "Avançar".


Fig. 11. Gerando um Expert usando o Assistente MQL5

Fig. 11. Gerando um Expert usando o Assistente MQL5

Ele vai abrir uma janela onde você pode especificar o nome. Neste exemplo em particular, o nome do Expert é "TEST_EA_AO_DZZ_IB_OB", os parâmetros do símbolo e do tempo possuem valores padrão. Em seguida, clique em "Avançar".

Fig. 12. Parâmetros comuns do Expert Advisor


Fig. 12. Propriedades gerais do Expert Advisor

Na janela que apareceu adicione os módulos de inclusão, um por um pressionando "Adicionar". Todo o processo é apresentado abaixo.

ATENÇÃO! Quando você for adicionar os módulos, primeiramente inclua todos os módulos de sinais (herdados de CExpertSignal) e depois os módulos de preço (herdados de CExpertSignalAdvanced). O resultado fora dessa ordem na inclusão dos módulos será imprevisível.

Assim, começamos incluindo os módulos de sinais do Awesome Oscillator. É o único filtro neste exemplo.

Fig. 13. Incluindo o módulo de sinais do Awesome Oscillator.

Fig. 13. Incluindo o módulo de sinais do Awesome Oscillator.

Inclua os módulos de preços exigidos em uma ordem aleatória após todos os módulos de sinal serem incluídos. Há três deles neste exemplo.

Fig. 14. Incluindo o módulo de sinais do módulo de preço DeltaZZ

Fig. 14. Incluindo o módulo de sinais do módulo de preço DeltaZZ


Fig. 15. Incluindo o módulo de sinais do módulo de preço barra interna

Fig. 15. Incluindo o módulo de sinais do módulo de preço barra interna


Fig. 16. Incluindo o módulo de sinais do módulo de preço barra externa

Fig. 16. Incluindo o módulo de sinais do módulo de preço barra externa

Depois de todos os módulos serem adicionados, a janela ficará da seguinte forma:

Fig. 17. Lista de módulos de sinais de negociação incluídos

Fig. 17. Lista de módulos de sinais de negociação incluídos

O valor do parâmetro "Weight" para o módulo de preço define sua prioridade.

Depois que o botão "Avançar" foi pressionado, o assistente sugere selecionar os módulos de gestão de dinheiro e de stop móvel. Escolha um desses ou deixae como está, pressionando "Avançar" ou "Pronto".

Pressionando "Pronto", nós devemos de receber o código gerado de Advisor.

5.2. Editando o código Gerado

Então, nós já obtemos o código.

1. Encontre a string no início

#include <Expert\Expert.mqh>

e edite ela dessa forma

#include <Expert\ExpertAdvanced.mqh>

É necessário incluir os arquivos das classes desenvolvidas.

2. Em seguida, encontre a string

CExpert ExtExpert;

e altere para

CExpertAdvanced ExtExpert;

Isso vai mudar a classe padrão do Expert para seus descendentes com as funções exigidas.

3. Agora, encontre a string

CExpertSignal *signal=new CExpertSignal;

e altere para

CExpertSignalAdvanced *signal=new CExpertSignalAdvanced;

Este é o caminho para alterar a classe padrão do sinal principal para seus descendentes com as funções exigidas.

4. Localize a string implementando a adição do primeiro módulo do preço para o array m_filters do sinal principal. Neste exemplo, ele se parece com:

signal.AddFilter(filter1);

Antes disso, nós inserimos a string

signal.CalcPriceModuleIndex();

Isto é necessário para o sinal principal reconhecer até qual valor do índice do array m_filters existem ponteiros do módulo de sinal e a partir do qual existem ponteiros do módulo de preço.

Encontrar a posição certa para inserir a string especificada pode causar dificuldade. Use o número após a palavra "filter" como ponto de referência. Ele irá simplificar a pesquisa e permitir que você não perca a posição correta. O Assistente MQL5 dá automaticamente e em ordem os nomes dos módulos inclusos. O primeiro módulo é chamado de filter0, o segundo - filter1, o terceiro - filter2 etc. Em nosso caso há apenas um módulo de sinal. Portanto, o primeiro módulo de preço incluído é o número dois e temos de procurar pela string "signal.AddFilter(filter1);" para adicionar o filtro como a numeração do código que começa com zero. A ilustração está na fig. 18:

Fig. 18. Os nomes dos módulos no código de acordo com a ordem de inclusão

Fig. 18. Os nomes dos módulos no código de acordo com a ordem de inclusão

5. Esta parte não é obrigatória. Através de alterações introduzidas, os parâmetros do Expert responsáveis ​​pela diferença da abertura de preços, Stop Loss, Take Profits e de expiração da ordem perdeu a sua utilização. Para tornar o código mais compacto, você pode excluir as seguintes linhas:

input double Signal_PriceLevel            =0.0;                    // Price level to execute a deal
input double Signal_StopLevel             =50.0;                   // Stop Loss level (in points)
input double Signal_TakeLevel             =50.0;                   // Take Profit level (in points)
input int    Signal_Expiration            =4;                      // Expiration of pending orders (in bars)

O erro de compilação encontrado após a exclusão das linhas acima nos leva ao próximo grupo de linhas a serem eliminados:

   signal.PriceLevel(Signal_PriceLevel);
   signal.StopLevel(Signal_StopLevel);
   signal.TakeLevel(Signal_TakeLevel);
   signal.Expiration(Signal_Expiration);

Após esta última ter sido excluída, a compilação será bem sucedida.

Comentários e explicações de edição podem ser encontradas no código anexado do Expert "TEST_EA_AO_DZZ_IB_OB". As linhas do código que poderiam ser excluídas possuem comentários de acompanhamento.


Conclusão

Neste artigo, nós expandimos significativamente a área de aplicação do Assistente MQL5. Agora ela pode ser usada para a otimização do desenvolvimento de sistemas de negociação automatizados que requerem o colocamento de ordens pendentes,de Stop Loss e Take Profits em diferentes níveis de preços, independentemente do preço atual.

Experts gerados podem incluir um conjunto de módulos de preços no cálculo dos parâmetros das ordens a serem enviadas. O conjunto de parâmetros mais adequado é selecionado dentre os que estão disponíveis. As preferências são especificadas nas configurações. Ele permite o uso de muitos diferentes pontos de entrada com a máxima eficiência. Esta abordagem torna os Experts seletivos. Se a direção é conhecida, mas o ponto de entrada é indefinido, então, o Expert esperará para que ele apareça.

Apresentando módulos compatíveis padrão responsáveis pela busca de níveis de preços é uma vantagem significativa e destina-se a simplificar o desenvolvimento dos Experts. Embora no momento existem apenas três módulos, o seu número, sem dúvida, aumentará no futuro. Se você encontrou este artigo útil, por favor, sugerir nos comentários alguns algoritmos de operação dos módulos de preços. Idéias interessantes serão implementadas no código.

Este artigo também apresenta um método para a nova extensão da capacidade do Expert desenvolvido no Assistente. A herança é a melhor maneira de introduzir mudanças.

Usuários com nenhuma habilidade de programação, embora sendo capazes de editar as instruções de código seguindo as instruções, terão uma oportunidade para criar Experts mais avançados com base nos modelos disponíveis.

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/987

Gráfico Líquido Gráfico Líquido
Você gostaria de ver um gráfico horário com barras que variam sua abertura de segundos até o quinto minuto da hora? Como que se parece um gráfico redesenhado quando o tempo de abertura das barras está mudando a cada minuto? Que vantagens temos em negociar em tais gráficos? Você irá encontrar as respostas para estas perguntas neste artigo.
Guia Prático MQL5: Processamento do Evento BookEvent Guia Prático MQL5: Processamento do Evento BookEvent
Este artigo estuda o BookEvent - o evento da Profundidade do Mercado, bem como o princípio de seu processamento. Um programa em MQL e o tratamento dos estados da Profundidade do Mercado servem de exemplo. Ele é escrito usando a abordagem orientada a objetos. Os resultados do tratamento são exibidos na tela como um painel com os níveis da Profundidade do Mercado.
Princípios da Precificação da Bolsa Tomando como Exemplo o Mercado de Derivativos da Bolsa de Moscou (MOEX) Princípios da Precificação da Bolsa Tomando como Exemplo o Mercado de Derivativos da Bolsa de Moscou (MOEX)
Este artigo descreve a teoria de precificação cambial e das especificidades da Câmara de Compensação (Clearing) do Mercado de Derivativos da Bolsa de Moscou (MOEX). Este é um artigo abrangente para iniciantes que querem obter uma primeira experiência na negociação de derivativos cambial, bem como para os traders experientes do mercado forex que estão considerando a negociação em plataforma centralizada da bolsa de valores.
Princípios de Programação em MQL5: Variáveis Globais do Terminal Princípios de Programação em MQL5: Variáveis Globais do Terminal
Este artigo destaca as capacidades orientada a objeto da linguagem MQL5 em criar objetos que facilitam o trabalho com as variáveis ​​globais do terminal. Como exemplo prático eu considero um caso em que as variáveis ​​globais são usados ​​como pontos de controle para a implementação das fases de um programa.