English Русский 中文 Español Deutsch 日本語
preview
Quase-construtor para criar um Expert Advisor

Quase-construtor para criar um Expert Advisor

MetaTrader 5Exemplos | 10 janeiro 2022, 10:48
1 239 0
Vladimir Karputov
Vladimir Karputov

Sumário


Introdução

Desde o início, meu objetivo era usar a Biblioteca padrão. Lembro-me que minha primeira tarefa era implementar uma funcionalidade muito simples: anexar a classe de negociação CTrade e executar o método Buy ou Sell. Escolhi a biblioteca padrão porque o código resultante era breve e conciso. Esse pequeno código a seguir, na forma de script, abre uma posição BUY com um volume de 1,0 lotes:

//+------------------------------------------------------------------+
//|                                                     Open Buy.mq5 |
//|                         Copyright © 2018-2021, Vladimir Karputov |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2018-2021, Vladimir Karputov"
#property version   "1.001"
//---
#include <Trade\Trade.mqh>
CTrade         m_trade;                      // trading object
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   m_trade.Buy(1.0); // open Buy position, volume 1.0 lot
  }

Gradualmente as exigências foram aumentando, eu me deparava com erros de negociação quase toda vez que escrevia um novo EA. O que mais queria era poder elaborar um código correto e esquecer esses erros para sempre. E foi então que foi publicado um artigo muito marcante para mim - Que testes deve passar o robô de negociação antes da publicação no mercado. Nessa altura, eu já estava ciente da necessidade de funções de controle confiáveis para executar ordens de negociação. Desde então, tenho adquirido gradualmente funções testadas e comprovadas que, com o método 'copy->paste', podem ser facilmente inseridas e utilizadas em um EA.

Como os indicadores são quase sempre usados no trabalho do EA, comecei a acumular funções para criar corretamente o identificador do indicador

LEMBRA: o estilo MQL5 implica que o identificador do indicador é criado UMA VEZ e é feito, como regra, em OnInit.

bem como funções para receber dados do indicador. Em torno da versão 2.XXX comecei duas linhas de desenvolvimento para o construtor - código de procedimento normal e código como uma classe (a tarefa principal da classe é implementar EAs com múltiplas moedas).

E o construtor evoluiu, incorporando gradualmente as configurações mais populares:

  • stop loss e take profit,
  • trailing,
  • cálculo do lote como porcentagem de risco ou como lote constante ou mínimo,
  • controle do intervalo de tempo dentro do qual a negociação é realizada,
  • presença de apenas uma posição no mercado,
  • reversão de sinais de negociação,
  • fechamento forçado de posições no caso de um sinal contrário...

Cada parâmetro de entrada traz consigo a criação de blocos de código e novas funções.

Para uso diário, optou-se por reunir todas as funções mais populares e um conjunto completo de parâmetros de entrada no EA 'Trading engine 3.mq5' - é essencialmente um EA pronto que elimina muito trabalho de rotina. Resta para cada caso adicionar ou apagar funções ou alterar a interação entre blocos de código.


1. Funcionalidade do EA após o construtor

O EA criado pelo construtor tem muitas configurações que podem ser usadas para criar estratégias únicas. Na versão 4.XXX, aplicam-se as seguintes regras: 

  • é usado o símbolo atual (o símbolo do gráfico em que o EA está sendo executado)
  • Take Profit, Stop Loss e Trailing nos parâmetros de entrada são definidos em pontos (points). Points é o tamanho do ponto do instrumento atual na moeda da cotação, por exemplo, para o par 'EURSD' 1.00055-1.00045=10 points.

Sempre é possível ver quais são os 'points' no gráfico do símbolos arrastando a ferramenta Fio de Retículo:

points

Fig. 1. Points

Esses são so parâmetros de entrada do Expert Advisor que é obtido após usar o construtor:

  • "Trading settings" parâmetros de negociação
    • Working timeframe — período gráfico de trabalho. Pode ser diferente do período gráfico em que o EA está sendo executado. É o período gráfico em que o indicador é criado (a menos que outro período gráfico seja explicitamente especificado no indicador). Também é usado para rastrear o surgimento de uma nova barra (para situações em que é necessário: buscar um sinal de negociação ou iniciar um Trailing, apenas quando surge uma nova barra).
    • Stop Loss se definido como 0, significa desabilitar o parâmetro.
    • Take Profit  se definido como 0, significa desabilitar o parâmetro.
    • Trailing on ...  duas hipóteses de Trailing: 'bar #0 (at every tick)' - a cada tick ou 'bar #1 (on a new bar)' - apenas quando surgir uma nova barra.
    • Search signals on ...  duas hipóteses de busca de sinal de negociação: 'bar #0 (at every tick)' - a cada tick ou 'bar #1 (on a new bar)' - apenas quando surgir uma nova barra.
    • Trailing Stop (min distance from price to Stop Loss)  distância mínima entre o preço e o Stop Loss da posição. O trailing começa a funcionar apenas se a posição for lucrativa e o preço se afastar do preço de abertura pela distância 'Trailing Stop' + 'Trailing Step'. Como o trailing funciona é mostrado nas imagens do código TrailingStop.
    • Trailing Step  passo do trailing. 
  • "Position size management (lot calculation) cálculo do lote.
    • Money management lot: Lot OR Risk  seleção do sistema de cálculo do lote. O lote pode ser constante (' Money management' definido em 'Constant lot' e especificar o tamanho do lote em ' The value for "Money management"') e dinâmico - como uma porcentagem do risco por negócio (' Money management' definido em 'Risk in percent for a deal' e especificar a porcentagem do risco em ' The value for "Money management"'). Você também pode definir um lote constante igual ao lote mínimo, — ' Money management' definido em 'Lots Min'.
    • The value for "Money management"  valor para  ' Money management
  • "Trade mode"  modo de negociação
    • Trade mode:  seleção do modo de negociação. Pode ser 'Allowed only BUY positions' (permite abrir apenas posições BUY), 'Allowed only SELL positions' (permite abrir apenas posições SELL) e 'Allowed BUY and SELL positions' (permite abrir apenas posições BUY e posições SELL)
  • "DEMA" parâmetros de indicador personalizado. Aqui é onde você insere seu indicador e seus parâmetros
    • DEMA: averaging period
    • DEMA: horizontal shift
    • DEMA: type of price
  • "Time control" período de tempo de trabalho. Especifica o período de tempo no qual podemos procurar sinais de negociação
    • Use time control  sinalizador, ativar/desativar o Time control
    • Start Hour  horas de início do período
    • Start Minute  minutos do início do período
    • End Hour  horas finais do período
    • End Minute  minutos finais do período
  • "Pending Order Parameters parâmetros relacionados a ordens pendentes
    • Pending: Expiration, in minutes ('0' -> OFF)  tempo de vida da ordem pendente ('0' significa que o parâmetro está desabilitado). 
    • Pending: Indent deslocamento da ordem pendente em relação ao preço atual (usado quando o preço da ordem pendente não está explicitamente definido)
    • Pending: Maximum spread ('0' -> OFF)  spread máximo ('0' significa que o parâmetro está desabilitado). Se o spread atual for maior do que o especificado, a ordem pendente não será colocada (o EA esperará que o spread diminua)
    • Pending: Only one pending  sinalizador, ativar/desativar, apenas uma ordem pendente é permitida no mercado
    • Pending: Reverse pending type   sinalizador, ativar/desativar, reverso de ordem pendente
    • Pending: New pending -> delete previous ones  se houver uma solicitação de posicionamento de ordem pendente, todas as outras ordens pendentes são eliminadas de antemão
  • "Additional features parâmetros adicionais
    • Positions: Only one  sinalizador, ativar/desativar, apenas uma posição é permitida no mercado
    • Positions: Reverse  sinalizador, ativar/desativar, reversão de ordem de negociação
    • Positions: Close opposite  sinalizador, ativar/desativar, se houver uma ordem de negociação, todas as posições são fechadas preliminarmente e só então a ordem é executada
    • Print log  sinalizador, ativar/desativar, exibir informações ampliadas sobre operações e erros
    • Coefficient (if Freeze==0 Or StopsLevels==0)  coeficiente que leva em consideração o Stop 
    • Deviation  derrapagem especificada
    • Magic number  identificador exclusivo do Expert Advisor

2. Algoritmo geral do construtor

A nível global (no "cabeçalho" do Expert Advisor) é declarada uma matriz 'SPosition' ('SPosition' — nome da matriz), com estruturas 'STRUCT_POSITION'. Esta matriz tem tamanho zero quando é iniciada e, quando o sinal de negociação é acionado, volta ao tamanho zero.

Desde OnTick é chamada a função 'SearchTradingSignals' — se houver um sinal (recebemos um sinal se não houver posições abertas no mercado), esta função gera a ordem de negociação (cria uma estrutura 'STRUCT_POSITION' na matriz para cada ordem de negociação). Além disso, em OnTick é verificada a existência de uma ordem de negociação — é examinado o tamanho da matriz 'SPosition:  caso seja maior que zero, a ordem de negociação existe e é enviada a 'OpenBuy' ou a 'OpenSell' para ser executada. O controle sobre a execução da ordem de negociação é realizado em OnTradeTransaction:

general algorithm (simple)

Fig. 2. Algoritmo geral (simples)

Sempre é assumido que o Expert Advisor usa o símbolo atual, isto é, o símbolo do gráfico em que o EA está sendo executado. Por exemplo, se o Expert Advisor é colocado no gráfico 'USDPLN', significa que ele usa o símbolo 'USDPLN'.

2.1. Estrutura 'STRUCT_POSITION'

Esta estrutura é o coração do Expert Advisor e desempenha duas funções: ela tem um campo onde é preenchida a ordem de negociação (o registro é realizado em 'SearchTradingSignals') e, além disso, tem outro campo para controlar a ordem de negociação (o controle é realizado em OnTradeTransaction). 

//+------------------------------------------------------------------+
//| Structure Positions                                              |
//+------------------------------------------------------------------+
struct STRUCT_POSITION
  {
   ENUM_POSITION_TYPE pos_type;              // position type
   double            volume;                 // position volume (if "0.0" -> the lot is "Money management")
   double            lot_coefficient;        // lot coefficient
   bool              waiting_transaction;    // waiting transaction, "true" -> it's forbidden to trade, we expect a transaction
   ulong             waiting_order_ticket;   // waiting order ticket, ticket of the expected order
   bool              transaction_confirmed;  // transaction confirmed, "true" -> transaction confirmed
   //--- Constructor
                     STRUCT_POSITION()
     {
      pos_type                   = WRONG_VALUE;
      volume                     = 0.0;
      lot_coefficient            = 0.0;
      waiting_transaction        = false;
      waiting_order_ticket       = 0;
      transaction_confirmed      = false;
     }
  };

Determinados campos são responsáveis pela ordem de negociação, enquanto outros pelo controle da mesma. A estrutura contém um construtor  uma função especial 'STRUCT_POSITION()' que é chamada quando um objeto de estrutura é criado e inicializa os elementos da mesma.

Campos da ordem de negociação:

  • pos_type tipo de posição que deve ser aberta (pode ser 'POSITION_TYPE_BUY' ou 'POSITION_TYPE_SELL')
  • volume volume da posição. Se o volume for especificado como '0.0', o volume da posição será obtido a partir do grupo de parâmetros de entrada 'Position size management (lot calculation)'
  • lot_coefficient  se este coeficiente for maior que 0.0', o volume da posição será multiplicado por dado valor

Campos de controle sobre a execução de uma ordem de negociação

  • waiting_transaction  sinalizador que indica se a ordem de negociação foi executada com sucesso e é necessário aguardar confirmação
  • waiting_order_ticket número de ordem de negociação recebido no momento de sua execução
  • transaction_confirmed  sinalizador que indica se a execução da ordem de negociação foi confirmada 

Depois de desmarcar o sinalizador no campo 'transaction_confirmed', a ordem de negociação é removida da estrutura. Assim, se quando o EA estiver funcionando e não houver ordem de negociação, o tamanho da estrutura será zero. Para saber mais sobre os campos da estrutura e sobre o controle, consulte o capítulo 'Pegamos a transação - código simplificado We catch the transaction'.

Por que este algoritmo?

Aparentemente, basta verificar se o método Buy retorna 'true' ou 'false', e pensar que a ordem de negociação foi executada caso o valor seja 'true'. Em muitos casos esta abordagem irá funcionar, mas há situações em que a ocorrência do valor 'true' não garante um resultado - a documentação fala sobre isso nos métodos Buy e Sell:

Observação

A conclusão bem sucedida de um método nem sempre significa um negócio bem sucedido. É necessário verificar o resultado da solicitação de negociação (código de retorno do servidor de negociação) por meio do método ResultRetcode(), bem como o valor retornado pelo método  ResultDeal().

A confirmação definitiva e exata da transação pode ser encontrada no histórico de negociação. Por isso, escolhi o seguinte algoritmo: após a execução bem-sucedida do método, verificamos ResultDeal (ticket da transação), checamos ResultRetcode (código de resultado da solicitação) e lembramos ResultOrder (ticket da ordem). Obtemos o ticket da ordem em OnTradeTransaction.


3. Adicionamos o indicador padrão — trabalho usando o arquivo 'Indicators Code.mq5'

Para facilitar o uso, blocos de código previamente preparados são montados no EA 'Indicators Code.mq5', blocos esses que incluem declarações de variáveis para armazenar identificadores, parâmetros de entrada, criação de identificadores. Os parâmetros de entrada de indicadores e as variáveis para armazenamento de identificadores estão localizados no 'cabeçalho' da EA, a criação de identificadores, como esperado, é especificada em OnInit. Nota: os nomes das variáveis para os identificadores de armazenamento são obtidos de acordo com o seguinte padrão: 'handle_' + 'indicador', por exemplo 'handle_iStdDev'. Todo o trabalho por meio de 'Indicators Code.mq5' é reduzido a operações 'copy-paste'. 

ATENÇÃO: o estilo MQL5 implica que o identificador do indicador é criado UMA VEZ e é feito (como regra) em OnInit

3.1. Exemplo de como adicionar um indicador 'iRVI' (Relative Vigor Index, RVI)

Vamos criar o Expert Advisor 'Add indicator.mq5'. No MetaEditor chamamos o 'MQL Wizard', por exemplo, clicando no botão  New, e selecionamos 'Expert Advisor (template)'

Expert Advisor (template)

Fig. 3. 'MQL Wizard' -> 'Expert Advisor (template)'

Na próxima etapa, recomendo fortemente adicionar pelo menos um parâmetro de entrada 

Expert Advisor (template)

Fig. 4. 'Expert Advisor (template)' -> 'Add parameter'

Esta abordagem permite adicionar automaticamente ao código linhas para o bloco de parâmetros de entrada:

//--- input parameters
input int      Input1=9;

'MQL Wizard' criou um EA vazio, agora adicionamos a ele o indicador 'iRVI' (Relative Vigor Index, RVI). Em 'Indicators Code.mq5' buscamos 'handle_iRVI' (a pesquisa é chamada pressionando 'ctrl' + 'F'). A pesquisa encontra a variável na qual o identificador está armazenado:

iRVI

Fig. 5. handle RVI

Copiamos e colamos a string encontrada no cabeçalho do EA 'Add indicator':

//--- input parameters
input int      Input1=9;
//---
int      handle_iRVI;                           // variable for storing the handle of the iRVI indicator
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()

Continuamos a pesquisa e encontramos o bloco para criar o identificador:

iRVI

Fig. 6. handle iRVI

Copiamos e colamos as strings encontradas no cabeçalho do EA 'Add indicator' em OnInit:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create handle of the indicator iRVI
   handle_iRVI=iRVI(m_symbol.Name(),Inp_RVI_period,Inp_RVI_ma_period);
//--- if the handle is not created
   if(handle_iRVI==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the iRVI indicator for the symbol %s/%s, error code %d",
                  m_symbol.Name(),
                  EnumToString(Inp_RVI_period),
                  GetLastError());
      //--- the indicator is stopped early
      m_init_error=true;
      return(INIT_SUCCEEDED);
     }
//---
   return(INIT_SUCCEEDED);
  }

Agora vamos adicionar os parâmetros de entrada do indicador. Em 'Indicators Code.mq5' clicamos com o botão do meio do mouse, por exemplo, em 'Inp_RVI_period', somos levados diretamente ao bloco de parâmetros de entrada:

iRVI

Fig. 7. handle iRVI

Copiamos as strings e as inserimos nos parâmetros de entrada:

#property version   "1.00"
//--- input parameters
input group             "RVI"
input ENUM_TIMEFRAMES      Inp_RVI_period                = PERIOD_D1;      // RVI: timeframe
input int                  Inp_RVI_ma_period             = 15;             // RVI: averaging period
//---
int      handle_iRVI;                           // variable for storing the handle of the iRVI indicator
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+

Se compilarmos, obteremos o erro: falha no compilador a nível de 'm_symbol' e de 'm_init_error'. E está certo, uma vez que essas variáveis estão no código que obtemos após o funcionamento do construtor, enquanto o Expert Advisor 'Add indicator' foi criado exclusivamente para demonstrar como trabalhar usando o arquivo 'Indicators Code.mq5'.


4. Adicionando um indicador personalizado

Adicionamos o indicador personalizado MA on DeMarker. Em primeiro lugar, é um indicador personalizado e, em segundo lugar, ele usa group. Como na seção anterior, criamos o EA 'Add custom indicator'. Depois disso, precisamos copiar os parâmetros de entrada do indicador personalizado e colá-los no Expert Advisor:

#property version   "1.00"
//--- input parameters
input group             "DeMarker"
input int                  Inp_DeM_ma_period    = 14;             // DeM: averaging period
input double               Inp_DeM_LevelUP      = 0.7;            // DeM: Level UP
input double               Inp_DeM_LevelDOWN    = 0.3;            // DeM: Level DOWN
input group             "MA"
input int                  Inp_MA_ma_period     = 6;              // MA: averaging period
input ENUM_MA_METHOD       Inp_MA_ma_method     = MODE_EMA;       // MA: smoothing type
//---

No arquivo 'Indicators Code.mq5' encontramos a variável 'handle_iCustom' variável para armazenar o identificador do indicador personalizado  e a colocamos no Expert Advisor:

//+------------------------------------------------------------------+
//|                                         Add custom indicator.mq5 |
//|                              Copyright © 2021, Vladimir Karputov |
//|                      https://www.mql5.com/en/users/barabashkakvn |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2021, Vladimir Karputov"
#property link      "https://www.mql5.com/en/users/barabashkakvn"
#property version   "1.00"
//--- input parameters
input group             "DeMarker"
input int                  Inp_DeM_ma_period    = 14;             // DeM: averaging period
input double               Inp_DeM_LevelUP      = 0.7;            // DeM: Level UP
input double               Inp_DeM_LevelDOWN    = 0.3;            // DeM: Level DOWN
input group             "MA"
input int                  Inp_MA_ma_period     = 6;              // MA: averaging period
input ENUM_MA_METHOD       Inp_MA_ma_method     = MODE_EMA;       // MA: smoothing type
//---
int      handle_iCustom;                        // variable for storing the handle of the iCustom indicator
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()

No arquivo 'Indicators Code.mq5' em OnInit() encontramos o bloco para armazenar o identificador do indicador personalizado e o colocamos no Expert Advisor:  

int      handle_iCustom;                        // variable for storing the handle of the iCustom indicator
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create handle of the indicator iCustom
   handle_iCustom=iCustom(m_symbol.Name(),Inp_DEMA_period,"Examples\\DEMA",
                          Inp_DEMA_ma_period,
                          Inp_DEMA_ma_shift,
                          Inp_DEMA_applied_price);
//--- if the handle is not created
   if(handle_iCustom==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the iCustom indicator for the symbol %s/%s, error code %d",
                  m_symbol.Name(),
                  EnumToString(Inp_DEMA_period),
                  GetLastError());
      //--- the indicator is stopped early
      m_init_error=true;
      return(INIT_SUCCEEDED);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |

Aqui temos de fazer que resulte. É necessário especificar o timeframe ('InpWorkingPeriod'), o caminho para o indicador (presumimos que o indicador está na raiz da pasta 'Indicators') e os parâmetros de entrada:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create handle of the indicator iCustom
   handle_iCustom=iCustom(m_symbol.Name(),InpWorkingPeriod,"MA on DeMarker",
                          "DeMarker",
                          Inp_DeM_ma_period,
                          Inp_DeM_LevelUP,
                          Inp_DeM_LevelDOWN,
                          "MA",
                          Inp_MA_ma_period,
                          Inp_MA_ma_method);
//--- if the handle is not created
   if(handle_iCustom==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code
      PrintFormat("Failed to create handle of the iCustom indicator for the symbol %s/%s, error code %d",
                  m_symbol.Name(),
                  EnumToString(InpWorkingPeriod),
                  GetLastError());
      //--- the indicator is stopped early
      m_init_error=true;
      return(INIT_SUCCEEDED);
     }
//---
   return(INIT_SUCCEEDED);
  }

5. Pegamos a transação código simplificado We catch the transaction

NOTA: este Expert Advisor é uma versão simplificada. Muitas funções têm código mais curto em comparação com um construtor completo

Se no mercado não houver posições abertas por este EA, registramos uma solicitação para abrir uma posição BUY. Usamos OnTradeTransaction e OnTick para confirmação de que a posição está aberta. Pesquisa e registro de ordem de negociação na função 'SearchTradingSignals':

//+------------------------------------------------------------------+
//| Search trading signals                                           |
//+------------------------------------------------------------------+
bool SearchTradingSignals(void)
  {
   if(IsPositionExists())
      return(true);
//---
   int size_need_position=ArraySize(SPosition);
   if(size_need_position>0)
      return(true);
   ArrayResize(SPosition,size_need_position+1);
   SPosition[size_need_position].pos_type=POSITION_TYPE_BUY;
   if(InpPrintLog)
      Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY");
   return(true);
  }

Se no mercado não houver posições abertas pelo Expert Advisor e se o tamanho da matriz 'SPosition' for igual a zero, aumentamos o tamanho da matriz em um desse modo, criamos um objeto de estrutura 'STRUCT_POSITION', que por sua vez chama o construtor 'STRUCT_POSITION()'. Após a chamada do construtor, são inicializados os membros da estrutura (por exemplo, volume  o volume da posição está em '0.0' significa que o volume da posição será obtido a partir do grupo de parâmetros de entrada 'Position size management (lot calculation)'). Resta registrar apenas o tipo de ordem de negociação na estrutura neste caso, a ordem pode ser lida como: "Abrir posição BUY".

Após registrar a ordem de negociação, a matriz 'SPosition' consiste numa estrutura e seus elementos têm os seguintes valores:

Elemento Valor Observação 
 pos_type  POSITION_TYPE_BUY  registrado em 'SearchTradingSignals'
 volume  0.0  inicializado no construtor da estrutura
 lot_coefficient  0.0  inicializado no construtor da estrutura
 waiting_transaction  false  inicializado no construtor da estrutura
 waiting_order_ticket  0  inicializado no construtor da estrutura
 transaction_confirmed  false  inicializado no construtor da estrutura

5.1. No novo tick, vamos para OnTick

O princípio geral de ação em OnTick:

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   int size_need_position=ArraySize(SPosition);
   if(size_need_position>0)
     {
      for(int i=size_need_position-1; i>=0; i--)
        {
         if(SPosition[i].waiting_transaction)
           {
            if(!SPosition[i].transaction_confirmed)
              {
               if(InpPrintLog)
                  Print(__FILE__," ",__FUNCTION__,", OK: ","transaction_confirmed: ",SPosition[i].transaction_confirmed);
               return;
              }
            else
               if(SPosition[i].transaction_confirmed)
                 {
                  ArrayRemove(SPosition,i,1);
                  return;
                 }
           }
         if(SPosition[i].pos_type==POSITION_TYPE_BUY)
           {
            SPosition[i].waiting_transaction=true;
            OpenPosition(i);
            return;
           }
         if(SPosition[i].pos_type==POSITION_TYPE_SELL)
           {
            SPosition[i].waiting_transaction=true;
            OpenPosition(i);
            return;
           }
        }
     }
//--- search for trading signals only at the time of the birth of new bar
   if(!RefreshRates())
      return;
//--- search for trading signals
   if(!SearchTradingSignals())
      return;
//---
  }

No início de OnTick verificamos o tamanho da matriz 'SPosition' (ela é uma matriz de estruturas 'STRUCT_POSITION'). Se o tamanho da matriz for maior que zero  iniciamos uma passagem para zero, com dois possíveis cenários: 

  • se a estrutura tiver um sinalizador 'waiting_transaction' definido como 'true' (o que significa que a ordem de negociação foi preparada e concluída e é necessário aguardar sua confirmação), verificamos o sinalizador 'transaction_confirmed
    • se definido como 'false' é porque a transação ainda não foi confirmada (pode acontecer se a ordem foi emitida, surgiu um novo tick, mas em OnTradeTransaction ainda não há confirmação). Então imprimimos uma mensagem sobre isso e saímos usando return  aguardamos um novo tick na esperança de que as informações sejam atualizadas
    • se definido como 'true' é porque a transação foi confirmada — então removemos esta estrutura da matriz e saímos usando return
  • se a estrutura tiver um sinalizador 'waiting_transaction' definido como 'false' (significa que esta ordem acaba de ser registrada e ainda não foi executada) marcamos o sinalizador 'waiting_transaction' e encaminhamos a ordem para 'OpenPosition'. Note que o bloco de código poderia ser simplificado assim

             SPosition[i].waiting_transaction=true;
             OpenPosition(i);
             return;
    mas deixei assim para que fosse mais fácil entender a forma completa do construtor do EA:
             if(SPosition[i].pos_type==POSITION_TYPE_BUY)
               {
                if(InpCloseOpposite)
                  {
                   if(count_sells>0)
                     {
                      ClosePositions(POSITION_TYPE_SELL);
                      return;
                     }
                  }
                if(InpOnlyOne)
                  {
                   if(count_buys+count_sells==0)
                     {
                      SPosition[i].waiting_transaction=true;
                      OpenPosition(i);
                      return;
                     }
                   else
                     {
                      ArrayRemove(SPosition,i,1);
                      return;
                     }
                  }
                SPosition[i].waiting_transaction=true;
                OpenPosition(i);
                return;
               }
             if(SPosition[i].pos_type==POSITION_TYPE_SELL)
               {
                if(InpCloseOpposite)
                  {
                   if(count_buys>0)
                     {
                      ClosePositions(POSITION_TYPE_BUY);
                      return;
                     }
                  }
                if(InpOnlyOne)
                  {
                   if(count_buys+count_sells==0)
                     {
                      SPosition[i].waiting_transaction=true;
                      OpenPosition(i);
                      return;
                     }
                   else
                     {
                      ArrayRemove(SPosition,i,1);
                      return;
                     }
                  }
                SPosition[i].waiting_transaction=true;
                OpenPosition(i);
                return;
               }

Continuamos o acompanhamento e relembro o bloco de código:

         if(SPosition[i].pos_type==POSITION_TYPE_BUY)
           {
            SPosition[i].waiting_transaction=true;
            OpenPosition(i);
            return;
           }

A ordem de negociação foi registrada na estrutura (na função 'SearchTradingSignals') e sinalizador 'waiting_transaction' é definido como 'false significa marcamos o sinalizador 'waiting_transaction' como 'true' e passamos o parâmetro 'i' para a função 'OpenPosition'   ele é um número de sequência da estrutura na matriz 'OpenPosition'. Como nosso tipo de ordem de negociação é 'POSITION_TYPE_BUY', passamos o número de sequência da estrutura para a função 'OpenBuy'.

5.2. Função 'OpenBuy'

O propósito da função é passar nas verificações preliminares, enviar uma solicitação de negociação para abrir uma posição BUY e rastrear o resultado imediatamente.

A primeira verificação é a de SYMBOL_VOLUME_LIMIT

 SYMBOL_VOLUME_LIMIT  Volume total máximo permitido para um determinado símbolo, volume esse da posição aberta e das ordens pendentes numa direção (compra ou venda). Por exemplo, se o limite é de 5 lotes, podemos ter uma posição BUY aberta com um volume de 5 lotes e colocar uma ordem pendente Sell Limit com um volume de 5 lotes. No entanto, não podemos colocar uma ordem pendente Buy Limit (já que o volume total numa direção excede o limite) ou colocar Sell Limit com um volume de mais de 5 lotes.

Se a verificação falhar, removemos o elemento da estrutura da matriz 'SPosition'.

A segunda verificação é a de margem

Obtemos o tamanho da margem livre que permanece após a operação de negociação (FreeMarginCheck), o tamanho da margem necessário para a operação de negociação (MarginCheck). Depois disso, protegemo-nos, sempre nos cuidamos e após a operação deixamos pelo menos uma quantia de dinheiro igual a FreeMarginCheck:

   if(free_margin_check>margin_check)

Se a verificação falhar, imprimimos a variável 'free_margin_check' e removemos o elemento de estrutura da matriz 'SPosition'.

A terceira verificação é a do resultado bool da operação Buy

Se o método Buy retornar 'false', imprimimos o erro e no campo 'waiting_transaction' registramos o valor false' (o erro mais comum - erro 10004, requote). Desse modo, quando um novo tick for recebido, haverá uma nova tentativa de abrir uma posição BUY. Se o resultado 'true' (abaixo está um bloco de código, quando o método Buy retorna 'true')

         if(m_trade.ResultDeal()==0)
           {
            if(m_trade.ResultRetcode()==10009) // trade order went to the exchange
              {
               SPosition[index].waiting_transaction=true;
               SPosition[index].waiting_order_ticket=m_trade.ResultOrder();
              }
            else
              {
               SPosition[index].waiting_transaction=false;
               if(InpPrintLog)
                  Print(__FILE__," ",__FUNCTION__,", ERROR: ","#1 Buy -> false. Result Retcode: ",m_trade.ResultRetcode(),
                        ", description of result: ",m_trade.ResultRetcodeDescription());
              }
            if(InpPrintLog)
               PrintResultTrade(m_trade,m_symbol);
           }
         else
           {
            if(m_trade.ResultRetcode()==10009)
              {
               SPosition[index].waiting_transaction=true;
               SPosition[index].waiting_order_ticket=m_trade.ResultOrder();
              }
            else
              {
               SPosition[index].waiting_transaction=false;
               if(InpPrintLog)
                  Print(__FILE__," ",__FUNCTION__,", OK: ","#2 Buy -> true. Result Retcode: ",m_trade.ResultRetcode(),
                        ", description of result: ",m_trade.ResultRetcodeDescription());
              }
            if(InpPrintLog)
               PrintResultTrade(m_trade,m_symbol);
           }

verificamos  ResultDeal (ticket da transação).

Se o ticket da transação for igual a zero, verificamos ResultRetcode (código de resultado da execução da solicitação). Obtivemos o código '10009' (por exemplo, a ordem de negociação foi enviada para um sistema de negociação externo, por exemplo, para a Bolsa e, portanto, o ticket da transação é zero), o que significa que no campo 'waiting_transaction' registramos 'true', no campo 'waiting_order_ticket' registramos ResultOrder (ticket da ordem), caso contrário (código de retorno diferente de '10009'), no campo 'waiting_transaction' registramos 'false' e imprimimos a mensagem de erro.

Se o ticket da negociação não for igual a zero (por exemplo, a execução ocorreu neste servidor de negociação), então realizamos verificações semelhantes no código de retorno e de forma semelhante registramos os valores nos campos 'waiting_transaction'waiting_order_ticket'.

5.3. OnTradeTransaction

Se a ordem de negociação for enviada com sucesso, será necessário aguardar a confirmação de que a transação foi concluída e registrada no histórico de negociação. Em OnTradeTransaction trabalhamos usando a variável 'trans' (estrutura do tipo MqlTradeTransaction). Na estrutura só nos interessam dois campos - 'deal' e 'type':

struct MqlTradeTransaction
  {
   ulong                         deal;             // Тикет сделки
   ulong                         order;            // Тикет ордера
   string                        symbol;           // Имя торгового инструмента
   ENUM_TRADE_TRANSACTION_TYPE   type;             // Тип торговой транзакции
   ENUM_ORDER_TYPE               order_type;       // Тип ордера
   ENUM_ORDER_STATE              order_state;      // Состояние ордера
   ENUM_DEAL_TYPE                deal_type;        // Тип сделки
   ENUM_ORDER_TYPE_TIME          time_type;        // Тип ордера по времени действия
   datetime                      time_expiration;  // Срок истечения ордера
   double                        price;            // Цена 
   double                        price_trigger;    // Цена срабатывания стоп-лимитного ордера
   double                        price_sl;         // Уровень Stop Loss
   double                        price_tp;         // Уровень Take Profit
   double                        volume;           // Объем в лотах
   ulong                         position;         // Тикет позиции
   ulong                         position_by;      // Тикет встречной позиции
  };


Uma vez que em OnTradeTransaction pegamos a transação TRADE_TRANSACTION_DEAL_ADD (adição da transação ao histórico), verificamos: tentamos selecionar a transação no histórico por meio de HistoryDealSelect - se não foi possível selecionar a transação, imprimimos um erro; se a transação existe no histórico de negociação, começamos a percorrer a matriz 'SPosition' num loop. No ciclo vemos apenas as estruturas cujo campo 'waiting_transaction' é definido como 'true' e o campo 'waiting_order_ticket' é igual ao ticket da ordem da negociação que selecionamos. Se uma correspondência for encontrada, no campo 'transaction_confirmed' registramos o valor 'true', significa que a ordem de negociação foi executada e confirmada.

//+------------------------------------------------------------------+
//| TradeTransaction function                                        |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction &trans,
                        const MqlTradeRequest &request,
                        const MqlTradeResult &result)
  {
//--- get transaction type as enumeration value
   ENUM_TRADE_TRANSACTION_TYPE type=trans.type;
//--- if transaction is result of addition of the transaction in history
   if(type==TRADE_TRANSACTION_DEAL_ADD)
     {
      ResetLastError();
      if(HistoryDealSelect(trans.deal))
         m_deal.Ticket(trans.deal);
      else
        {
         Print(__FILE__," ",__FUNCTION__,", ERROR: ","HistoryDealSelect(",trans.deal,") error: ",GetLastError());
         return;
        }
      if(m_deal.Symbol()==m_symbol.Name() && m_deal.Magic()==InpMagic)
        {
         if(m_deal.DealType()==DEAL_TYPE_BUY || m_deal.DealType()==DEAL_TYPE_SELL)
           {
            int size_need_position=ArraySize(SPosition);
            if(size_need_position>0)
              {
               for(int i=0; i<size_need_position; i++)
                 {
                  if(SPosition[i].waiting_transaction)
                     if(SPosition[i].waiting_order_ticket==m_deal.Order())
                       {
                        Print(__FUNCTION__," Transaction confirmed");
                        SPosition[i].transaction_confirmed=true;
                        break;
                       }
                 }
              }
           }
        }
     }
  }

No novo tick, em OnTick a estrutura definida como 'true' no campo 'transaction_confirmed' será removida da matriz 'SPosition'. Desse modo, foi emitida a ordem de negociação e esta foi rastreada até que apareceu no histórico de negociação.


6. Criando um Expert Advisor (sinais para abrir posições) por meio do construtor

Antes de criar qualquer Expert Advisor, é necessário pensar sobre a própria estratégia de negociação. Consideremos uma estratégia simples com base no indicador iDEMA (Double Exponential Moving Average, DEMA), embutida no construtor por padrão. Procuramos um sinal para abrir uma posição apenas no momento em que surge uma nova barra; o próprio sinal de negociação é um indicador que sobe ou desce sequencialmente:

DEMA Strategy

Fig. 8. DEMA Strategy

Lembre-se: qualquer estratégia pode ser modificada ajustando os parâmetros. Por exemplo, podemos deixar Take Profit e Stop Loss, mas desativar Trailing; ou vice-versa, podemos desativar Take Profit e Stop Loss e deixar Trailing; ou limitar o sentido da negociação, permitindo apenas BUY ou apenas SELL. Também podemos habilitar 'Time control' e restringir a negociação à noite, ou vice-versa, ajustar a negociação apenas à noite. Também podemos alterar bastante o sistema de negociação ajustando os parâmetros do grupo 'Additional features'.

Em geral, a espinha dorsal da estratégia de negociação é construída na função 'SearchTradingSignals', e todos os outros parâmetros são "sondar" o mercado em busca de abordagens ótimas.

Criamos um novo arquivo, que será um EA preliminar (siga as etapas indicadas nas figuras 3 e 4). Na etapa 4, você precisa dar um nome exclusivo ao EA - digamos 'iDEMA Full EA.mq5'. Temos o seguinte:

//+------------------------------------------------------------------+
//|                                                iDEMA Full EA.mq5 |
//|                              Copyright © 2021, Vladimir Karputov |
//|                      https://www.mql5.com/en/users/barabashkakvn |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2021, Vladimir Karputov"
#property link      "https://www.mql5.com/en/users/barabashkakvn"
#property version   "1.00"
//--- input parameters
input int      Input1=9;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   
  }
//+------------------------------------------------------------------+

Agora copiamos todo o código do arquivo 'Trading engine 3.mq5' e inserir em vez de linhas. Você precisa editar o "cabeçalho do EA". Após a operação de inserção, obtivemos o seguinte "cabeçalho":

//+------------------------------------------------------------------+
//|                                                iDEMA Full EA.mq5 |
//+------------------------------------------------------------------+
//|                                             Trading engine 3.mq5 |
//|                              Copyright © 2021, Vladimir Karputov |
//|                      https://www.mql5.com/en/users/barabashkakvn |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2021, Vladimir Karputov"
#property link      "https://www.mql5.com/en/users/barabashkakvn"
#property version   "4.003"
#property description "barabashkakvn Trading engine 4.003"
#property description "Take Profit, Stop Loss and Trailing - in Points (1.00055-1.00045=10 points)"
/*
   barabashkakvn Trading engine 4.003
*/
#include <Trade\PositionInfo.mqh>

Modificamos o "cabeçalho" da seguinte forma:

//+------------------------------------------------------------------+
//|                                                iDEMA Full EA.mq5 |
//|                              Copyright © 2021, Vladimir Karputov |
//|                      https://www.mql5.com/en/users/barabashkakvn |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2021, Vladimir Karputov"
#property link      "https://www.mql5.com/en/users/barabashkakvn"
#property version   "1.001"
#property description "iDEMA EA"
#property description "Take Profit, Stop Loss and Trailing - in Points (1.00055-1.00045=10 points)"
/*
   barabashkakvn Trading engine 4.003
*/
#include <Trade\PositionInfo.mqh>

Se você compilar, não haverá erros. O EA resultante ainda será capaz de negociar.

6.1. Função 'SearchTradingSignals'

Esta é a função mais importante responsável por verificar a disponibilidade das ordens de negociação. Vamos considerar esta função bloco a bloco.

Não mais do que uma posição por barra:

   if(iTime(m_symbol.Name(),InpWorkingPeriod,0)==m_last_deal_in) // on one bar - only one deal
      return(true);

Verificamos o intervalo de tempo de negociação:

   if(!TimeControlHourMinute())
      return(true);

Recebemos dados do indicador. Recebemos dados do indicador na matriz 'dema' que, com a ajuda de ArraySetAsSeries, define a ordem inversa da indexação (o elemento da matriz [0] corresponderá à barra mais à direita do gráfico). Obtemos os dados por meio da função personalizada 'iGetArray':

   double dema[];
   ArraySetAsSeries(dema,true);
   int start_pos=0,count=6;
   if(!iGetArray(handle_iCustom,0,start_pos,count,dema))
     {
      return(false);
     }
   int size_need_position=ArraySize(SPosition);
   if(size_need_position>0)
      return(true);

Sinal para abrir uma posição BUY. Se necessário (variável 'InpReverse' armazena o valor do parâmetro de entrada 'Positions: Reverse'), o sinal de negociação será revertido. Se negociar em algum sentido for restrito (a variável 'InpTradeMode' armazena o valor do parâmetro de entrada 'Trade mode:'), tal restrição será levada em consideração:

//--- BUY Signal
   if(dema[m_bar_current]>dema[m_bar_current+1] && dema[m_bar_current+1]>dema[m_bar_current+3])
     {
      if(!InpReverse)
        {
         if(InpTradeMode!=sell)
           {
            ArrayResize(SPosition,size_need_position+1);
            SPosition[size_need_position].pos_type=POSITION_TYPE_BUY;
            if(InpPrintLog)
               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY");
            return(true);
           }
        }
      else
        {
         if(InpTradeMode!=buy)
           {
            ArrayResize(SPosition,size_need_position+1);
            SPosition[size_need_position].pos_type=POSITION_TYPE_SELL;
            if(InpPrintLog)
               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal SELL");
            return(true);
           }
        }
     }

O bloco de código para o sinal SELL é semelhante. 


7. Criando um Expert Advisor (sinais para colocar uma ordem pendente) por meio do construtor

O nome do expert advisor será 'iDEMA Full EA Pending.mq5', para isso abra o EA 'iDEMA Full EA.mq5' e salve-o com um novo nome.

Em primeiro lugar, é desenvolvida a estratégia de negociação e, somente depois, o código é aplicado para tal estratégia. Vamos mudar um pouco a estratégia usada no capítulo 6. Criamos um Expert Advisor (sinais para abrir posições) usando o construtor, em vez de um sinal para abrir uma posição BUY, haverá um sinal para colocar uma ordem pendente Buy Stop e, em vez de um sinal para abrir uma posição SELL, uma ordem pendente Sell Stop. Os seguintes parâmetros serão usados para ordens pendentes:

  • Pending: Expiration, in minutes ('0' -> OFF)  duração da ordem pendente ('0' significa que o parâmetro está desativado) -> 600
  • Pending: Indent  recuo da ordem pendente em relação ao preço atual (é usado quando o preço da ordem pendente não está explicitamente definido) -> 50
  • Pending: Maximum spread ('0' -> OFF)  spread máximo ( '0' significa que o parâmetro está desativado). Se o spread atual for maior do que o especificado, a ordem pendente não será colocada (o EA espera que o spread diminua) -> 12
  • Pending: Only one pending  sinalizador, ativar/desativar, o mercado permite apenas uma ordem pendente -> true
  • Pending: Reverse pending type   sinalizador, ativar/desativar, reversão de ordem pendente -> false
  • Pending: New pending -> delete previous ones  se houver uma solicitação de posicionamento de ordem pendente, todas as outras ordens pendentes são eliminadas de antemão -> true

A função 'SearchTradingSignals' será assim:

//+------------------------------------------------------------------+
//| Search trading signals                                           |
//+------------------------------------------------------------------+
bool SearchTradingSignals(void)
  {
   if(iTime(m_symbol.Name(),InpWorkingPeriod,0)==m_last_deal_in) // on one bar - only one deal
      return(true);
   if(!TimeControlHourMinute())
      return(true);
   double dema[];
   ArraySetAsSeries(dema,true);
   int start_pos=0,count=6;
   if(!iGetArray(handle_iCustom,0,start_pos,count,dema))
     {
      return(false);
     }
   int size_need_pending=ArraySize(SPending);
   if(size_need_pending>0)
      return(true);
//---
   if(InpPendingOnlyOne)
      if(IsPendingOrdersExists())
         return(true);
   if(InpPendingClosePrevious)
      m_need_delete_all=true;
//--- BUY Signal
   if(dema[m_bar_current]>dema[m_bar_current+1] && dema[m_bar_current+1]>dema[m_bar_current+3])
     {
      if(!InpReverse)
        {
         if(InpTradeMode!=sell)
           {
            ArrayResize(SPending,size_need_pending+1);
            SPending[size_need_pending].pending_type=ORDER_TYPE_BUY_STOP;
            if(InpPrintLog)
               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY STOP");
            return(true);
           }
        }
      else
        {
         if(InpTradeMode!=buy)
           {
            ArrayResize(SPending,size_need_pending+1);
            SPending[size_need_pending].pending_type=ORDER_TYPE_SELL_STOP;
            if(InpPrintLog)
               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal SELL STOP");
            return(true);
           }
        }
     }
//--- SELL Signal
   if(dema[m_bar_current]<dema[m_bar_current+1] && dema[m_bar_current+1]<dema[m_bar_current+3])
     {
      if(!InpReverse)
        {
         if(InpTradeMode!=buy)
           {
            ArrayResize(SPending,size_need_pending+1);
            SPending[size_need_pending].pending_type=ORDER_TYPE_SELL_STOP;
            if(InpPrintLog)
               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal SELL STOP");
            return(true);
           }
        }
      else
        {
         if(InpTradeMode!=sell)
           {
            ArrayResize(SPending,size_need_pending+1);
            SPending[size_need_pending].pending_type=ORDER_TYPE_BUY_STOP;
            if(InpPrintLog)
               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY STOP");
            return(true);
           }
        }
     }
//---
   /*if(InpPendingOnlyOne)
      if(IsPendingOrdersExists())
         return(true);
   if(InpPendingClosePrevious)
      m_need_delete_all=true;
   int size_need_pending=ArraySize(SPending);
   ArrayResize(SPending,size_need_pending+1);
   if(!InpPendingReverse)
      SPending[size_need_pending].pending_type=ORDER_TYPE_BUY_STOP;
   else
      SPending[size_need_pending].pending_type=ORDER_TYPE_SELL_STOP;
   SPending[size_need_pending].indent=m_pending_indent;
   if(InpPendingExpiration>0)
      SPending[size_need_pending].expiration=(long)(InpPendingExpiration*60);
   if(InpPrintLog)
      Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY STOP");*/
//---
   return(true);
  }

Observe que não escrevemos o preço da ordem pendente na estrutura SPending por isso será usado o preço atual mais o recuo.

Recebemos um sinal de negociação, mas ele foi acionado (a ordem pendente foi colocada) apenas quando o spread ficou menor do que o especificado:

iDEMA Full EA Pending

Fig. 9. iDEMA Full EA Pending


Arquivos anexados ao artigo:

Nome Tipo de arquivo Descrição
Indicators Code Expert Advisor Contém variáveis para armazenar identificadores, parâmetros de entrada de indicadores, blocos para criar indicadores
Add indicator.mq5 Expert Advisor Exemplo de uso do arquivo 'Add indicator.mq5' - adicionamos um indicador padrão
Add custom indicator.mq5 Expert Advisor
Exemplo de adição de um indicador personalizado
Trading engine 4.mq5 Expert Advisor Construtor
iDEMA Full EA.mq5
Expert Advisor
EA criado por meio do construtor - sinais para abrir posições
iDEMA Full EA Pending.mq5
Expert Advisor
EA criado por meio do construtor - sinais para posicionar ordens pendentes

Conclusão

Espero que este conjunto de funções de negociação o ajude a criar EAs mais robustos que estejam preparados para condições de mercado voláteis. E nunca hesite em experimentar os parâmetros, afinal, habilitando alguns e desabilitando outros, podemos mudar muitíssimo a estratégia.


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

Arquivos anexados |
Indicators_Code.mq5 (88.76 KB)
Add_indicator.mq5 (4.55 KB)
Trading_engine_4.mq5 (177.98 KB)
iDEMA_Full_EA.mq5 (177.93 KB)
Receitas MQL5: Calendário Econômico Receitas MQL5: Calendário Econômico
Este artigo se trata das funcionalidades programáticas usadas ao trabalhar usando o calendário econômico. Para implementá-las, criaremos uma classe para facilitar o acesso às propriedades do calendário e receber valores de eventos. Como exemplo prático, programaremos um indicador que utiliza dados da CFTC sobre as posições líquidas de especuladores.
Trabalhando com o tempo (Parte 1): princípios básicos Trabalhando com o tempo (Parte 1): princípios básicos
As funções e o código discutidos no artigo o ajudarão a entender melhor os princípios de processamento de tempo, de mudança de horário da corretora e de horário de verão ou de inverno. O uso adequado do tempo é um aspecto muito importante do trading. Este nos permite saber, por exemplo, se a Bolsa de Londres ou Nova Iorque já abriu ou ainda não ou a que horas começa/termina o pregão no mercado de moedas.
Conjunto de ferramentas para marcação manual de gráficos e negociação (Parte III). Otimização e novas ferramentas Conjunto de ferramentas para marcação manual de gráficos e negociação (Parte III). Otimização e novas ferramentas
Desenvolveremos o tema do desenho de objetos gráficos em gráficos usando atalhos de teclado. Foram acrescentadas novas ferramentas à biblioteca, em particular uma linha reta, que atravessa máximos arbitrários, e um conjunto de retângulos que permitem estimar tanto o nível quanto o tempo de reversão. Também veremos a possibilidade de otimizar o código para melhorar o desempenho. O exemplo de implementação será reescrito como um indicador, o que tornará possível definir Shortcuts junto com outros programas de negociação. O nível de proficiência do código está um pouco acima do nível de iniciante.
Gráficos na biblioteca DoEasy (Parte 88): coleção de objetos gráficos, matriz dinâmica bidimensional para armazenar propriedades de objetos que mudam dinamicamente Gráficos na biblioteca DoEasy (Parte 88): coleção de objetos gráficos, matriz dinâmica bidimensional para armazenar propriedades de objetos que mudam dinamicamente
Neste artigo, criaremos uma classe de matriz multidimensional dinâmica com a capacidade de alterar a quantidade de dados em qualquer dimensão. Com base na classe criada, criaremos uma matriz dinâmica bidimensional para armazenar algumas propriedades alteradas dinamicamente de objetos gráficos.