English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
Guia prático do MQL5: O Histórico de transações e a biblioteca de função para obter propriedades de posição

Guia prático do MQL5: O Histórico de transações e a biblioteca de função para obter propriedades de posição

MetaTrader 5Exemplos | 21 março 2014, 10:06
6 073 0
Anatoli Kazharski
Anatoli Kazharski

Introdução

É hora de brevemente resumir a informação fornecida nos artigos anteriores sobre as propriedades de posição. Neste artigo, criaremos algumas funções adicionais para obter propriedades que podem apenas serem obtidas após acessar o histórico de transações. Também nos familiarizaremos com estruturas de dados que nos permitirá acessar propriedades de posição e símbolo de forma mais conveniente.

Sistemas de negociação onde volumes de posição permanecem o mesmo durante sua existência não requerem realmente o uso de funções que serão fornecidas neste artigo. Mas se você planeja implementar um sistema de administração de dinheiro e controlar um tamanho da posição de um lote em sua estratégia de negociação em um momento mais tarde, estas funções serão indispensáveis.

Antes de começarmos, eu gostaria de fazer uma sugestão para aqueles leitores que seguiram um link para este artigo, enquanto visitantes de primeira viagem ao website, ou apenas começaram a aprender a linguagem MQL5, para começar com os primeiros artigos da série "Guia prático do MQL5".


Desenvolvimento do Consultor Especializado

Para ser possível visualizar a operação de novas funções no Consultor Especializado modificado no artigo anterior chamado "Guia prático do MQL5: Como Evitar Erros Quando Configurando/Modificando Níveis de Negociação", adicionaremos a possibilidade de aumentar o volume da posição se um sinal para abertura ocorrer novamente, enquanto a posição já estiver lá.

Podem haver várias transações no histórico de posição, e se houve mudanças no volume da posição no curso das negociações, devem ter ocorrido mudanças no preço atual da posição. Para descobrir o preço do primeiro ponto de entrada, precisamos acessar o histórico de transações com respeito aquela posição específica. A figura abaixo é uma demonstração do caso onde a posição tem apenas uma transação (um ponto de entrada):

Fig. 1. Primeira transação na posição

Fig. 1. Primeira transação na posição.

A próxima figura mostra uma mudança no preço da posição seguida da segunda transação:

Fig. 2. Segunda transação na posição

Fig. 2. Segunda transação na posição.

Como demonstrando em artigos anteriores, identificadores padrão permitem a você obter apenas o preço da posição atual (POSITION_PRICE_OPEN) e o preço atual de um símbolo (POSITION_PRICE_CURRENT) para os quais uma posição é aberta.

Entretanto, em alguns sistemas de negócios precisamos saber a distância coberta pelo preço desde o primeiro ponto de entrada, assim como o preço da última transação. Toda esta informação está disponível no histórico de transações/ordens da conta. Abaixo está a lista de transações associadas com a figura anterior:

Fig. 3. O histórico de transações na conta

Fig. 3. O histórico de transações na conta.

Acredito que a situação agora seja clara e todos os objetivos estão definidos. Vamos continuar a modificar o Consultor Especialista apresentado nos artigos anteriores. Primeiro, adicionaremos novos identificadores numerados 0, 6, 9, 12 e 16 para a enumeração de propriedades de posição:

//--- Enumeration of position properties
enum ENUM_POSITION_PROPERTIES
  {
   P_TOTAL_DEALS     = 0,
   P_SYMBOL          = 1,
   P_MAGIC           = 2,
   P_COMMENT         = 3,
   P_SWAP            = 4,
   P_COMMISSION      = 5,
   P_PRICE_FIRST_DEAL= 6,
   P_PRICE_OPEN      = 7,
   P_PRICE_CURRENT   = 8,
   P_PRICE_LAST_DEAL = 9,
   P_PROFIT          = 10,
   P_VOLUME          = 11,
   P_INITIAL_VOLUME  = 12,
   P_SL              = 13,
   P_TP              = 14,
   P_TIME            = 15,
   P_DURATION        = 16,
   P_ID              = 17,
   P_TYPE            = 18,
   P_ALL             = 19
  };

Comentários para cada das propriedades serão dados em uma estrutura que será revisada logo abaixo.

Vamos aumentar o número de parâmetros externos. Agora, seremos capazes de especificar:

  • MagicNumber - uma ID única do Consultor Especialista (número mágico);
  • Deviation - desvio;
  • VolumeIncrease - um valor pelo qual o volume da posição será aumentado;
  • InfoPanel - um parâmetro que lhe permite ativar/desativar a exibição do painel de informação.

Assim é como é implementado:

//--- External parameters of the Expert Advisor
sinput   long        MagicNumber=777;     // Magic number
sinput   int         Deviation=10;        // Slippage
input    int         NumberOfBars=2;      // Number of Bullish/Bearish bars for a Buy/Sell
input    double      Lot=0.1;             // Lot
input    double      VolumeIncrease=0.1;  // Position volume increase
input    double      StopLoss=50;         // Stop Loss
input    double      TakeProfit=100;      // Take Profit
input    double      TrailingStop=10;     // Trailing Stop
input    bool        Reverse=true;        // Position reversal
sinput   bool        ShowInfoPanel=true;  // Display of the info panel

Por favor note os parâmetros cujo modificador sinput é definido. Este modificador lhe permite desabilitar a otimização no Testador de Estratégia. De fato, quando desenvolvemos um programa para uso próprio, você tem uma perfeita compreensão de quais parâmetros afetarão o resultado final, então você simplesmente os desmarca da otimização. Mas quando se trata de um grande número de parâmetros, este método te permite os separar visualmente de outros enquanto eles ficam esmaecidos:

Fig. 4. Parâmetros desativados para otimização estão esmaecidos

Fig. 4. Parâmetros desativados para otimização estão esmaecidos.

Vamos agora substituir as variáveis globais que armazenaram valores de propriedade de função e símbolo com estruturas de dados (struct):

//--- Position properties
struct position_properties
  {
   uint              total_deals;      // Number of deals
   bool              exists;           // Flag of presence/absence of an open position
   string            symbol;           // Symbol
   long              magic;            // Magic number
   string            comment;          // Comment
   double            swap;             // Swap
   double            commission;       // Commission   
   double            first_deal_price; // Price of the first deal in the position
   double            price;            // Current position price
   double            current_price;    // Current price of the position symbol      
   double            last_deal_price;  // Price of the last deal in the position
   double            profit;           // Profit/Loss of the position
   double            volume;           // Current position volume
   double            initial_volume;   // Initial position volume
   double            sl;               // Stop Loss of the position
   double            tp;               // Take Profit of the position
   datetime          time;             // Position opening time
   ulong             duration;         // Position duration in seconds
   long              id;               // Position identifier
   ENUM_POSITION_TYPE type;            // Position type
  };
//--- Symbol properties
struct symbol_properties
  {
   int               digits;        // Number of decimal places in the price
   int               spread;        // Spread in points
   int               stops_level;   // Stops level
   double            point;         // Point value
   double            ask;           // Ask price
   double            bid;           // Bid price
   double            volume_min;    // Minimum volume for a deal
   double            volume_max;    // Maximum volume for a deal
   double            volume_limit;  // Maximum permissible volume for a position and orders in one direction
   double            volume_step;   // Minimum volume change step for a deal
   double            offset;        // Offset from the maximum possible price for a transaction
   double            up_level;      // Upper Stop level price
   double            down_level;    // Lower Stop level price
  }

Agora, para acessar um certo elemento da estrutura, precisamos criar uma variável deste tipo de estrutura. O procedimento é similar a criar um objeto para uma classe de negócios que foi considerada no artigo chamado "Guia prático do MQL5: Analisando propriedades de posição no testador de estratégia do MetaTrader 5".

//--- variables for position and symbol properties
position_properties  pos;
symbol_properties    symb;

Você pode acessar os elementos da mesma maneira quando lidando com métodos de classe. Em outras palavras, é suficiente colocar um ponto após o nome da variável da estrutura para exibir a lista de elementos contidos naquela estrutura específica. Isto é muito conveniente. No caso de comentários de uma linha são fornecidos para os campos da estrutura (assim como em nosso exemplo), eles serão mostrados em uma dica na direita.

Fig. 5a. Lista de campos de estrutura para propriedades de posição Fig. 5b. Lista de campos de estrutura para propriedades de símbolo

Fig. 5. Lista de campos de estrutura.

Outro ponto importante. Ao modificar o Consultor Especialista, mudamos virtualmente todas as suas variáveis globais usadas em muitas funções, então, agora precisamos substituí-las com campos de estrutura correspondentes para propriedades de símbolo e posição. Por exemplo, a variável global pos_open que foi usada para armazenar a sinalização de presença/ausência de uma posição aberta foi substituída com o campo exists do tipo de estrutura position_properties. Portanto, sempre que a variável pos_open for usada, ela precisa ser substituída por pos.exists.

Será um longo e exaustivo processo se você fazê-lo manualmente. Então será melhor automatizar a solução para esta tarefa usando os recursos do MetaEditor: Encontrar e Substituir -> Substituir no menu Editar ou na combinação de teclas Ctrl+H:


Fig. 6. Encontrando e substituindo o texto

Fig. 6. Encontrando e substituindo o texto.

Precisamos encontrar e substituir todas as variáveis globais para as propriedades de posição e símbolo para executar um teste mais profundo, tendo compilado o arquivo. Se nenhum erro é detectado, significará que fizemos tudo corretamente. Não fornecerei o código aqui para não fazer este artigo desnecessariamente longo. Além disso, um código fonte pronto para uso está disponível no final deste artigo para download.

Agora que resolvemos as coisas com as variáveis, vamos proceder para modificar as funções existentes e criar novas.

Nos parâmetros externos, você pode agora definir o número mágico e desvio em pontos. Nós, portanto, também precisaremos fazer mudanças relevantes no código do Consultor Especialista. Criaremos uma função auxiliar definida pelo usuário OpenPosition(), onde estas propriedades será definidas usando as funções da classe CTrade antes de enviar uma ordem para abertura de posição.

//+------------------------------------------------------------------+
//| Opening a position                                               |
//+------------------------------------------------------------------+
void OpenPosition(double lot,
                  ENUM_ORDER_TYPE order_type,
                  double price,
                  double sl,
                  double tp,
                  string comment)
  {
   trade.SetExpertMagicNumber(MagicNumber); // Set the magic number in the trading structure
   trade.SetDeviationInPoints(CorrectValueBySymbolDigits(Deviation)); // Set the slippage in points
//--- If the position failed to open, print the relevant message
   if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment))
     { Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError())); }
  }

Precisamos apenas fazer algumas pequenas mudanças no código da função de negociação principal do Consultor Especialista - TradingBlock(). Abaixo está a parte do código da função que sofreu mudanças:

//--- If there is no position
   if(!pos.exists)
     {
      //--- Adjust the volume
      lot=CalculateLot(Lot);
      //--- Open a position
      OpenPosition(lot,order_type,position_open_price,sl,tp,comment);
     }
//--- If there is a position
   else
     {
      //--- Get the position type
      GetPositionProperties(P_TYPE);
      //--- If the position is opposite to the signal and the position reversal is enabled
      if(pos.type==opposite_position_type && Reverse)
        {
         //--- Get the position volume
         GetPositionProperties(P_VOLUME);
         //--- Adjust the volume
         lot=pos.volume+CalculateLot(Lot);
         //--- Reverse the position
         OpenPosition(lot,order_type,position_open_price,sl,tp,comment);
         return;
        }
      //--- If the signal is in the direction of the position and the volume increase is enabled, increase the position volume
      if(!(pos.type==opposite_position_type) && VolumeIncrease>0)
        {
         //--- Get the Stop Loss of the current position
         GetPositionProperties(P_SL);
         //--- Get the Take Profit of the current position
         GetPositionProperties(P_TP);
         //--- Adjust the volume
         lot=CalculateLot(Increase);
         //--- Increase the position volume
         OpenPosition(lot,order_type,position_open_price,pos.sl,pos.tp,comment);
         return;
        }

O código acima foi melhorado com o bloco onde a direção da posição atual é verificada contra a direção do sinal. Se as direções coincidem e o aumento do volume da posição é ativado nos parâmetros externos (o valor do parâmetro VolumeIncrease é maior do que zero), nós verificamos/ajustamos um dado lote e enviados a ordem relevante. Agora, tudo que você precisa fazer para enviar uma ordem para abrir ou reverter uma posição ou para aumentar o volume da posição é escrever uma linha de código.

Vamos criar funções para obter propriedades de posição do histórico de transações. Começaremos com a função CurrentPositionTotalDeals() que retorna o número de transações na posição atual:

//+------------------------------------------------------------------+
//| Returning the number of deals in the current position            |
//+------------------------------------------------------------------+
uint CurrentPositionTotalDeals()
  {
   int    total       =0;  // Total deals in the selected history list
   int    count       =0;  // Counter of deals by the position symbol
   string deal_symbol =""; // symbol of the deal
//--- If the position history is obtained
   if(HistorySelect(pos.time,TimeCurrent()))
     {
      //--- Get the number of deals in the obtained list
      total=HistoryDealsTotal();
      //--- Iterate over all the deals in the obtained list
      for(int i=0; i<total; i++)
        {
            //--- Get the symbol of the deal
            deal_symbol=HistoryDealGetString(HistoryDealGetTicket(i),DEAL_SYMBOL);
            //--- If the symbol of the deal and the current symbol are the same, increase the counter
            if(deal_symbol==_Symbol)
               count++;
        }
     }
//---
   return(count);
  }

O código acima é dado com comentários bastante detalhados. Mas devemos dizer algumas palavras sobre como o histórico é selecionado. Em nosso caso, obtemos a lista do ponto de abertura da posição atual determinado pelo horário de abertura para o ponto atual do tempo usando a função HistorySelect(). Após o histórico ser selecionado, podemos descobrir o número de transações na lista usando a função HistoryDealsTotal(). O resto deve estar claro pelos comentários.

O histórico de uma posição particular também pode ser selecionado pelo seu identificador usando a função HistorySelectByPosition(). Aqui, você precisa considerar que o identificador da posição permanece o mesmo quando a posição é revertida, como acontece as vezes em nosso Consultor Especialista. Entretanto, o horário de abertura de posição realmente muda com a reversão, portanto esta variante é mais fácil de implementar. Mas se você tem que lidar com o histórico de transações que não se aplica apenas a posição aberta atualmente, você precisa utilizar identificadores. Retornaremos ao histórico de transações em artigos futuros.

Vamos continuar criando uma função CurrentPositionFirstDealPrice() que retorna o preço da primeira transação na posição, ou seja, o preço da transação no qual a posição foi aberta.

//+------------------------------------------------------------------+
//| Returning the price of the first deal in the current position    |
//+------------------------------------------------------------------+
double CurrentPositionFirstDealPrice()
  {
   int      total       =0;    // Total deals in the selected history list
   string   deal_symbol ="";   // symbol of the deal
   double   deal_price  =0.0;  // Price of the deal
   datetime deal_time   =NULL; // Time of the deal
//--- If the position history is obtained
   if(HistorySelect(pos.time,TimeCurrent()))
     {
      //--- Get the number of deals in the obtained list
      total=HistoryDealsTotal();
      //--- Iterate over all the deals in the obtained list
      for(int i=0; i<total; i++)
        {
         //--- Get the price of the deal
         deal_price=HistoryDealGetDouble(HistoryDealGetTicket(i),DEAL_PRICE);
         //--- Get the symbol of the deal
         deal_symbol=HistoryDealGetString(HistoryDealGetTicket(i),DEAL_SYMBOL);
         //--- Get the time of the deal
         deal_time=(datetime)HistoryDealGetInteger(HistoryDealGetTicket(i),DEAL_TIME);
         //--- If the time of the deal equals the position opening time, 
         //    and if the symbol of the deal and the current symbol are the same, exit the loop
         if(deal_time==pos.time && deal_symbol==_Symbol)
            break;
        }
     }
//---
   return(deal_price);
  }

O princípio aqui é o mesmo que na função anterior. Obtemos o histórico do ponto da abertura da posição e então verificamos o horário da transação e horário da abertura de posição a cada iteração. Junto com o preço da transação, obtemos o nome do símbolo e o horário da transação. A primeira transação é identificada quando o horário da transação coincide com o horário de abertura da posição. Como seu preço já foi atribuído para a variável relevante, apenas precisamos retornar o valor.

Vamos continuar. Às vezes, você pode precisar obter o preço da última transação na posição atual. Para este propósito, criaremos a função CurrentPositionLastDealPrice():

//+------------------------------------------------------------------+
//| Returning the price of the last deal in the current position     |
//+------------------------------------------------------------------+
double CurrentPositionLastDealPrice()
  {
   int    total       =0;   // Total deals in the selected history list
   string deal_symbol ="";  // Symbol of the deal 
   double deal_price  =0.0; // Price
//--- If the position history is obtained
   if(HistorySelect(pos.time,TimeCurrent()))
     {
      //--- Get the number of deals in the obtained list
      total=HistoryDealsTotal();
      //--- Iterate over all the deals in the obtained list from the last deal in the list to the first deal
      for(int i=total-1; i>=0; i--)
        {
         //--- Get the price of the deal
         deal_price=HistoryDealGetDouble(HistoryDealGetTicket(i),DEAL_PRICE);
         //--- Get the symbol of the deal
         deal_symbol=HistoryDealGetString(HistoryDealGetTicket(i),DEAL_SYMBOL);
         //--- If the symbol of the deal and the current symbol are the same, exit the loop
         if(deal_symbol==_Symbol)
            break;
        }
     }
//---
   return(deal_price);
  }

Desta vez o ciclo (loop) começou com a última transação na lista e é, frequentemente, o caso em que a transação requerida é identificada na primeira iteração do ciclo. Mas se você negociar em vários símbolos, o ciclo continuará até o símbolo da transação coincidir ao símbolo atual.

O volume atual de posição pode ser obtido usando o identificador padrão POSITION_VOLUME. Para encontrar o volume da posição inicial (o volume da primeira transação), criaremos a função CurrentPositionInitialVolume():

//+------------------------------------------------------------------+
//| Returning the initial volume of the current position             |
//+------------------------------------------------------------------+
double CurrentPositionInitialVolume()
  {
   int             total       =0;           // Total deals in the selected history list
   ulong           ticket      =0;           // Ticket of the deal
   ENUM_DEAL_ENTRY deal_entry  =WRONG_VALUE; // Position modification method
   bool            inout       =false;       // Flag of position reversal
   double          sum_volume  =0.0;         // Counter of the aggregate volume of all deals, except for the first one
   double          deal_volume =0.0;         // Volume of the deal
   string          deal_symbol ="";          // Symbol of the deal 
   datetime        deal_time   =NULL;        // Deal execution time
//--- If the position history is obtained
   if(HistorySelect(pos.time,TimeCurrent()))
     {
      //--- Get the number of deals in the obtained list
      total=HistoryDealsTotal();
      //--- Iterate over all the deals in the obtained list from the last deal in the list to the first deal
      for(int i=total-1; i>=0; i--)
        {
         //--- If the order ticket by its position is obtained, then...
         if((ticket=HistoryDealGetTicket(i))>0)
           {
            //--- Get the volume of the deal
            deal_volume=HistoryDealGetDouble(ticket,DEAL_VOLUME);
            //--- Get the position modification method
            deal_entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket,DEAL_ENTRY);
            //--- Get the deal execution time
            deal_time=(datetime)HistoryDealGetInteger(ticket,DEAL_TIME);
            //--- Get the symbol of the deal
            deal_symbol=HistoryDealGetString(ticket,DEAL_SYMBOL);
            //--- When the deal execution time is less than or equal to the position opening time, exit the loop
            if(deal_time<=pos.time)
               break;
            //--- otherwise calculate the aggregate volume of deals by the position symbol, except for the first one
            if(deal_symbol==_Symbol)
               sum_volume+=deal_volume;
           }
        }
     }
//--- If the position modification method is a reversal
   if(deal_entry==DEAL_ENTRY_INOUT)
     {
      //--- If the position volume has been increased/decreased
      //    I.e. the number of deals is more than one
      if(fabs(sum_volume)>0)
        {
         //--- Current volume minus the volume of all deals except for the first one
         double result=pos.volume-sum_volume;
         //--- If the resulting value is greater than zero, return the result, otherwise return the current position volume         
         deal_volume=result>0 ? result : pos.volume;
        }
      //--- If there are no more deals, other than the entry,
      if(sum_volume==0)
         deal_volume=pos.volume; // return the current position volume
     }
//--- Return the initial position volume
   return(NormalizeDouble(deal_volume,2));
  }

Esta função saiu mais complexa do que as anteriores. Tenho tentado levar em consideração todas as possíveis situações que pode resultar no valor errado. Um teste cuidadoso não revelou quaisquer problemas. Os comentários detalhados fornecidos no código deve ajudá-lo a entender a ideia.

Também será útil ter uma função que retorna a duração da posição. Organizaremos para permitir ao usuário selecionar o formato apropriado do valor retornado: segundos, minutos, horas ou dias. Para este propósito, vamos criar outra enumeração:

//--- Position duration
enum ENUM_POSITION_DURATION
  {
   DAYS     = 0, // Days
   HOURS    = 1, // Hours
   MINUTES  = 2, // Minutes
   SECONDS  = 3  // Seconds
  };

Abaixo está o código da função CurrentPositionDuration() responsável por todos os cálculos relevantes:

//+------------------------------------------------------------------+
//| Returning the duration of the current position                   |
//+------------------------------------------------------------------+
ulong CurrentPositionDuration(ENUM_POSITION_DURATION mode)
  {
   ulong     result=0;   // End result
   ulong     seconds=0;  // Number of seconds
//--- Calculate the position duration in seconds
   seconds=TimeCurrent()-pos.time;
//---
   switch(mode)
     {
      case DAYS      : result=seconds/(60*60*24);   break; // Calculate the number of days
      case HOURS     : result=seconds/(60*60);      break; // Calculate the number of hours
      case MINUTES   : result=seconds/60;           break; // Calculate the number of minutes
      case SECONDS   : result=seconds;              break; // No calculations (number of seconds)
      //---
      default        :
         Print(__FUNCTION__,"(): Unknown duration mode passed!");
         return(0);
     }
//--- Return result
   return(result);
  }

Vamos criar a função CurrentPositionDurationToString() para o painel de informação onde as propriedades de função são exibidas. A função converterá a duração da posição em segundos para um formato facilmente compreendido pelo usuário. O número de segundos será passado para a função, e a função por sua vez retornará um string contendo a duração da posição em dias, horas, minutos e segundos:

//+------------------------------------------------------------------+
//| Converting the position duration to a string                     |
//+------------------------------------------------------------------+
string CurrentPositionDurationToString(ulong time)
  {
//--- A dash if there is no position
   string result="-";
//--- If the position exists
   if(pos.exists)
     {
      //--- Variables for calculation results
      ulong days=0;
      ulong hours=0;
      ulong minutes=0;
      ulong seconds=0;
      //--- 
      seconds=time%60;
      time/=60;
      //---
      minutes=time%60;
      time/=60;
      //---
      hours=time%24;
      time/=24;
      //---
      days=time;
      //--- Generate a string in the specified format DD:HH:MM:SS
      result=StringFormat("%02u d: %02u h : %02u m : %02u s",days,hours,minutes,seconds);
     }
//--- Return result
   return(result);
  }

Está tudo pronto agora. Não fornecerei os códigos das funções GetPositionProperties() e GetPropertyValue() que precisam ser modificados de acordo com todas as mudanças acima. Se você leu todos os artigos anteriores da série, você não deve encontrar qualquer dificuldade em fazer isso por conta própria. Qualquer que seja o caso, o arquivo do código-fonte está em anexo a este artigo.

Como resultado, o painel de informação deve parecer como mostrado abaixo:

Fig. 7. Demonstração de todas as propriedades de posição no painel de informação

Fig. 7. Demonstração de todas as propriedades de posição no painel de informação.

Deste modo, agora temos a biblioteca de função para obter propriedades de função e provavelmente continuaremos a trabalhar nela em artigos futuros, como e quando necessário.


Otimizando Parâmetros e Testando o Consultor Especialista

Como um experimento, vamos tentar otimizar os parâmetros do Consultor Especialista. Embora o que temos atualmente não pode ainda ser chamado um sistema de transações completo e cheio de recursos, o resultado que alcançaremos abrirá nossos olhos em relação a algumas coisas e melhorar nossa experiência como desenvolvedores de sistemas de transações.

Configuraremos o Testador de Estratégia como mostrado abaixo:

Fig. 8. Configurações do Testador de Estratégia para otimização de parâmetro

Fig. 8. Configurações do Testador de Estratégia para otimização de parâmetro.

Configurações dos parâmetros externos do Consultor Especialista devem ser como seguem:

Fig. 9. Configurações de parâmetro do Consultor Especialista para otimização

Fig. 9. Configurações de parâmetro do Consultor Especialista para otimização.

Seguindo a otimização, classificamos os resultados alcançados pelo fator máximo de recuperação:

Fig. 10. Resultados ordenados pelo fator máximo de recuperação

Fig. 10. Resultados ordenados pelo fator máximo de recuperação.

Vamos agora testar o grupo de parâmetros do topo com o valor do Fator de Recuperação sendo igual a 4.07. Mesmo dado o fato que a otimização foi feita para EURUSD, podemos ver os resultados positivos para muitos símbolos:

Resultados para EURUSD:

Fig. 11. Resultados para EURUSD

Fig. 11. Resultados para EURUSD.

Resultados para AUDUSD:

Fig. 12. Resultados para AUDUSD

Fig. 12. Resultados para AUDUSD.

Resultados para NZDUSD:

Fig. 13. Resultados para NZDUSD

Fig. 13. Resultados para NZDUSD.


Conclusão

Virtualmente qualquer ideia pode ser desenvolvida e melhorada. Todo sistema de transações deve ser cuidadosamente testado antes de ser rejeitado como defeituoso. Em artigos futuros, olharemos para vários mecanismos e esquemas que podem desempenhar um papel muito positivo na personalização e adaptação de quase qualquer sistema de negociações.

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

Arquivos anexados |
Guia prático do MQL5: Utilizando indicadores para ajustar condições de negócios no Consultor Especialista Guia prático do MQL5: Utilizando indicadores para ajustar condições de negócios no Consultor Especialista
Neste artigo, continuaremos a a modificar o Consultor Especialista que estamos trabalhando durante os artigos precedentes da série Guia prático do MQL5. Desta vez, o Consultor Especialista será melhorado com indicadores dos quais os valores serão usados para verificar as condições de abertura de posição. Para aprimorá-lo, criaremos uma lista de menu suspenso nos parâmetros externos para ser possível selecionar um de três indicadores de transações.
Guia prático do MQL5: Como Evitar Erros Quando Configurando/Modificando Níveis de Negociação Guia prático do MQL5: Como Evitar Erros Quando Configurando/Modificando Níveis de Negociação
Em continuação do nosso trabalho no Consultor Especialista do artigo anterior da série chamado "Guia prático: Analisando propriedades de posição no testador de estratégias do MetaTrader 5", o melhoraremos com um punhado de funções úteis, assim como aprimorar e otimizar as já existentes. O Consultor Especialista terá neste momento parâmetros externos que podem ser otimizados no Testador de Estratégias MetaTrader 5 e, em algumas formas, se parecerá com um simples sistema de transações.
O indicador ZigZag: nova abordagem e novas soluções O indicador ZigZag: nova abordagem e novas soluções
O artigo examina a possibilidade de criar um indicador ZigZag avançado. A ideia de identificar nós é baseada no uso de indicador Envelopes. Presumimos que podemos encontrar uma certa combinação de parâmetros de entrada para uma série de Envelopes, pelos quais a maioria dos nós dos ZigZags se encontram nos confins das faixas dos Envelopes. Consequentemente, podemos tentar prever as coordenadas do novo nó.
Guia prático do MQL5: Analisando propriedades de posição no testador de estratégias do MetaTrader 5 Guia prático do MQL5: Analisando propriedades de posição no testador de estratégias do MetaTrader 5
Apresentaremos uma versão modificada do Expert Advisor a partir fo artigo anterior "Guia prático do MQL5: Propriedades de posição no painel de informações personalizado". Alguns dos assuntos que abordaremos incluem a obtenção de dados das barras, verificação de eventos de uma nova barra no símbolo atual, inclusão de uma classe de negociação da Biblioteca padrão a um arquivo, criação de uma função para buscar por sinais de negociação e uma função para execução das operações de negócio, assim como determinar os eventos de negócio na função OnTrade().