English Русский 中文 Español Deutsch 日本語
LifeHack para traders: "amassando" ForEach com os define (#define)

LifeHack para traders: "amassando" ForEach com os define (#define)

MetaTrader 5Exemplos | 14 março 2018, 11:51
1 959 0
Vladimir Karputov
Vladimir Karputov

 — Onde está a força, irmão?                                
 —A força, irmão, está nos define                    

                                  (c) fxsaber                  

Você escreve em MQL4 e deseja migrar para MQL5, mas ainda não sabe por onde começar? Então, é nossa vez de ajudar você! Agora você pode trabalhar confortavelmente no editor MetaEditor MQL5 e, ao mesmo tempo, usar a notação MQL4. Deve-se dizer, porém, que ela já existia. Neste artigo eu quero apresentar uma descrição mais completa e detalhada sobre a compatibilização de funções MQL4 com as de MQL5.


Um bom programador é um programador preguiçoso

A criação de experts ou robôs de negociação implica quase sempre um monte de trabalho com ciclos. Os ciclos estão ao nosso redor em toda parte: pesquisa detalhada de ordens, operações no histórico, objetos no gráfico, símbolos na Observação do mercado, barras no buffer de indicador. Para facilitar a vida do programador, ao MetaEditor foram adicionados trechos de código ("snippets"), eles se desenrolam automaticamente num pequeno pedaço de código quando você digita os primeiros caracteres de uma função ou tarefa e pressiona o Tab. Veja como funciona um trecho de código para o ciclo for:


Não é ruim, mas não cobre todas as nossas necessidades. O exemplo mais simples pode ser quando queremos examinar todos os símbolos na Observação do mercado.

   int total=SymbolsTotal(true);
   for(int i=0;i<total;i++)
     {
      string symbol=SymbolName(i,true);
      PrintFormat("%d. %s",i+1,symbol);
     }

Seria fantástico criar, no MetaEditor, um trecho de código próprio que começasse com fes (for_each_symbol) e se desenrolasse no seguinte bloco:


Mas, no MetaEditor, não existem "snippets" personalizados, por isso teremos de tomar um outro caminho, isto é, usaremos os define. A substituição de macros #define foi inventada por programadores inteligentes e preguiçosos que perseguiam vários objetivos. Um deles era alcançar a simplicidade de leitura e facilidade de escrita de códigos recorrentes.

Em muitas linguagens de programação, além do ciclo clássico for , existem variantes do tipo for(<typename> element:Collection) ou for each (type identifier in expression). Se fosse possível escrever código do tipo

for(ulong order_id in History)
  {
   trabalho com order_id  
  }

, a vida do programador seria um pouco mais fácil. Na internet você vai encontrar inimigos e partidários desta abordagem. Aqui vou mostrar como fazer algo parecido com a ajuda de macros #define.

Comecemos com uma tarefa simples, isto é, obter os nomes de todos os símbolos da Observação do mercado. Vamos para o cabeçalho e escrevemos este macro:

#define ForEachSymbol(s,i)  string s; int total=SymbolsTotal(true); for(int i=0;i<total;i++,s=SymbolName(i,true))
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   ForEachSymbol(symbol,index)
     {
      PrintFormat("%d. %s",index,symbol);
     }
  }

O compilador entende esta entrada e não produz erros. Executamos a depuração pressionando F5 e vemos que algo deu errado:

1. (null)
2. GBPUSD
3. USDCHF
4. USDJPY
...

O problema é que a expressão s=SymbolName(i,true) no ciclo for é avaliada após a iteração, e nossa variável s não é inicializada de maneira nenhuma na primeira iteração, quando i=0. Operador de ciclo for:

O operador for consiste em três expressões e um operador executável:

for(expressão1; expressão2; expressão3)
   operador;

A expressão1 descreve a inicialização do ciclo. A expressão2 é a verificação das condições de conclusão do ciclo. Se ela for True, será executado o operador do corpo do ciclo for. Tudo é repetido até que a expressão2 se torna false. Se ela for false, o ciclo termina e o controle passa para o próximo operador. A expressão3 é calculada após cada iteração.

Isso é facilmente resolvido. Fazemos um par de alterações:

#define ForEachSymbol(s,i)  string s=SymbolName(0,true); int total=SymbolsTotal(true); for(int i=1;i<total;i++,s=SymbolName(i,true))
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   ForEachSymbol(symbol,index)
     {
      PrintFormat("%d. %s",index,symbol); // em vez de index+1, agora aparece simplesmente index
     }
  }

e obtemos o resultado desejado. Escrevemos o macro ForEachSymbol com parâmetros symbol e index, como se fosse do habitual ciclo for, e no corpo do pseudo ciclo trabalhamos com estas variáveis, ​​como se tivessem sido declaradas e inicializadas usando o valor necessário. Assim, podemos obter as propriedades desejadas dos símbolos a partir da Observação do mercado utilizando funções do tipo SymbolInfoXXX(). Por exemplo, assim:

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   ForEachSymbol(symbol,index)
     {
      //--- preparamos os dados
      double spread=SymbolInfoDouble(symbol,SYMBOL_ASK)-SymbolInfoDouble(symbol,SYMBOL_BID);
      double point=SymbolInfoDouble(symbol,SYMBOL_POINT);
      long digits=SymbolInfoInteger(symbol,SYMBOL_DIGITS);
      string str_spread=DoubleToString(spread/point,0);
      string str_point=DoubleToString(point,digits);
      //--- imprimimos as informações
      Print(index,". ",symbol," spread=",str_spread," points (",
            digits," digits",", point=",str_point,")");
     }
/* Exemplo de impressão
        1. EURUSD spread=3 points (5 digits, point=0.00001)
        2. USDCHF spread=8 points (5 digits, point=0.00001)
        3. USDJPY spread=5 points (3 digits, point=0.001)
        4. USDCAD spread=9 points (5 digits, point=0.00001)
        5. AUDUSD spread=5 points (5 digits, point=0.00001)
        6 NZDUSD spread=10 points (5 digits, point=0.00001)
        7. USDSEK spread=150 points (5 digits, point=0.00001)
*/
  }

Agora podemos escrever um macro desse tipo, para pesquisa detalhada de objetos gráficos no gráfico:

#define ForEachObject(name,i)   string name=ObjectName(0,0); int total=ObjectsTotal(0); for(int i=1;i<=total;i++,name=ObjectName(0,i-1))
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   ForEachObject(objectname,index)
     {
      Print(index,": objectname=\"",objectname,"\", objecttype=",
            EnumToString((ENUM_OBJECT)ObjectGetInteger(0,objectname,OBJPROP_TYPE)));
     }
/* Exemplo de impressão
        1: objectname="H1 Arrow 61067", objecttype=OBJ_ARROW_UP
        2: objectname="H1 Rectangle 31152", objecttype=OBJ_RECTANGLE
        3: objectname="H1 StdDev Channel 56931", objecttype=OBJ_STDDEVCHANNEL
        4: objectname="H1 Trendline 6605", objecttype=OBJ_TREND
*/     
  }

Na verdade, a linha que define o macro ForEachObject virou um pouco mais comprida, e agora não é tão simples compreender o código de substituição escrito numa única linha. Mas acontece que este problema já foi resolvido, isto é, a definição de macro pode ser dividida em linhas usando uma barra invertida '\'. Assim:

#define ForEachObject(name,i)   string name=ObjectName(0,0);   \
   int ob_total=ObjectsTotal(0);                               \
   for(int i=1;i<=ob_total;i++,name=ObjectName(0,i-1))

Para o compilador, todas essas três linhas aparecerão como uma linha longa, o que facilitará que o programador leia este código. Resta criar esse tipo de macros para trabalhar com entidades de negociação: ordens, posições e transações.

Comecemos com a pesquisa detalhada de ordens. Agora é adicionada apenas a função de escolha de histórico HistorySelect():

#define ForEachOrder(ticket,i)    HistorySelect(0,TimeCurrent());    \
  ulong ticket=OrderGetTicket(0);                                    \ 
  int or_total=OrdersTotal();                                        \
  for(int i=1;i<or_total;i++,ticket=OrderGetTicket(i))
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   ForEachOrder(orderticket,index)
     {
      Print(index,": #",orderticket," ",OrderGetString(ORDER_SYMBOL)," ",
            EnumToString((ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE)));
     }
/* Exemplo de impressão     
   1: #13965457 CADJPY ORDER_TYPE_SELL_LIMIT
   2: #14246567 AUDNZD ORDER_TYPE_SELL_LIMIT
*/ 
  }

Pode-se notar que neste macro (e nos dois anteriores) não existe tratamento de erros. Por exemplo, se HistorySelect() retornar false? Pode-se dizer que, neste caso, não podemos entrar no ciclo de todas as ordens. E, além disso, quem é que var analisar o resultado da execução de HistorySelect()? Acontece que, neste macro, não há nada proibido no que diz respeito ao método convencional de escrita de programas.

Mas a crítica mais forte do uso de #define é o fato de que o uso da substituição de macro não permite a depuração de código. Concordo com isso, porém, como fxsaber diz, "Um paciente bem estabilizado não necessita de anestesia, e um macro depurado não requer depuração."

Mais adiante, fazemos um macro para percorrer cada posição:

#define ForEachPosition(ticket,i) HistorySelect(0,TimeCurrent());    \
   ulong ticket=PositionGetTicket(0);                                \
   int po_total=PositionsTotal();                                    \
   for(int i=1;i<=po_total;i++,ticket=PositionGetTicket(i-1))        
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   ForEachPosition(positionid,index)
     {
      Print(index,": ",PositionGetString(POSITION_SYMBOL)," postionID #",positionid);
     }
/* Exemplo de impressão 
   1: AUDCAD postionID #13234934
   2: EURNZD postionID #13443909
   3: AUDUSD postionID #14956799
   4: EURUSD postionID #14878673
*/ 

Pesquisa detalhada de transações no histórico:

#define ForEachDeal(ticket,i) HistorySelect(0,TimeCurrent());        \
   ulong ticket=HistoryDealGetTicket(0);                             \
   int total=HistoryDealsTotal();                                    \
   for(int i=1;i<=total;i++,ticket=HistoryDealGetTicket(i-1))
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   //---
   ForEachDeal(dealticket,index)
     {
      Print(index,": deal #",dealticket,",  order ticket=",
            HistoryDealGetInteger(dealticket,DEAL_ORDER));
     }
  }

Pesquisa detalhada de ordens no histórico:

#define ForEachHistoryOrder(ticket,i) HistorySelect(0,TimeCurrent());\
   ulong ticket=HistoryOrderGetTicket(0);                            \
   int total=HistoryOrdersTotal();                                   \
   for(int i=1;i<=total;i++,ticket=HistoryOrderGetTicket(i-1))
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   ForEachHistoryOrder(historyorderticket,index)
     {
      Print(index,": #",historyorderticket);
     }
  }

Coletamos todas as substituições de macros num arquivo ForEach.mqh4:

//+------------------------------------------------------------------+
//|                                                      ForEach.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| Ciclo da pesquisa detalhada de símbolos na Observação do mercado |
//+------------------------------------------------------------------+
#define ForEachSymbol(symbol,i)  string symbol=SymbolName(0,true);   \
   int os_total=SymbolsTotal(true);                                  \
   for(int i=1;i<os_total;i++,symbol=SymbolName(i,true))
//+---------------------------------------------------------------------------+
//| Ciclo da pesquisa detalhada de objetos na janela principal do gráfico     |
//+---------------------------------------------------------------------------+   
#define ForEachObject(name,i)   string name=ObjectName(0,0);         \
   int ob_total=ObjectsTotal(0);                                     \
   for(int i=1;i<=ob_total;i++,name=ObjectName(0,i-1))      
//+------------------------------------------------------------------+
//| Ciclo da pesquisa detalhada de ordens existentes                 |
//+------------------------------------------------------------------+
#define ForEachOrder(ticket,i)    HistorySelect(0,TimeCurrent());    \
   ulong ticket=OrderGetTicket(0);                                   \
   int or_total=OrdersTotal();                                       \
   for(int i=1;i<or_total;i++,ticket=OrderGetTicket(i))   
//+------------------------------------------------------------------+
//| Ciclo da pesquisa detalhada de posições abertas                  |
//+------------------------------------------------------------------+
#define ForEachPosition(ticket,i) HistorySelect(0,TimeCurrent());    \
   ulong ticket=PositionGetTicket(0);                                \
   int po_total=PositionsTotal();                                    \
   for(int i=1;i<=po_total;i++,ticket=PositionGetTicket(i-1))      
//+------------------------------------------------------------------+
//| Ciclo da pesquisa detalhada de transações no histórico           |
//+------------------------------------------------------------------+
#define ForEachDeal(ticket,i) HistorySelect(0,TimeCurrent());        \
   ulong ticket=HistoryDealGetTicket(0);                             \
   int dh_total=HistoryDealsTotal();                                 \
   for(int i=1;i<=dh_total;i++,ticket=HistoryDealGetTicket(i-1))        
//+------------------------------------------------------------------+
//| Ciclo da pesquisa detalhada de ordens no histórico               |
//+------------------------------------------------------------------+
#define ForEachHistoryOrder(ticket,i) HistorySelect(0,TimeCurrent());\
   ulong ticket=HistoryOrderGetTicket(0);                            \
   int oh_total=HistoryOrdersTotal();                                \
   for(int i=1;i<=oh_total;i++,ticket=HistoryOrderGetTicket(i-1))   
//+------------------------------------------------------------------+

Repare que, para cada macro, para a variável total, tivemos de adicionar o prefixo, a fim de evitar conflitos caso decidamos usar no nosso código mais de um macro. Esta é a maior desvantagem deste macro, isto é, nós escondemos atrás dele a declaração da variável que será visível do exterior. Isso pode levar a erros dificilmente detetáveis durante compilação.

Além disso, ao usar um macro paramétrico, o compilador não dá nenhuma pista de como faz isso para as funções. Você vai ter que decorar estes seis macros se quiser usá-los. Embora não seja tão difícil, o primeiro parâmetro sempre é aquilo essencial que é procurado exaustivamente no ciclo, enquanto o segundo parâmetro é sempre o índice do ciclo que começa com 1 (um).

Por fim, adicionamos alguns macros para rastreamento no sentido inverso. Neste caso, é necessário se mover a partir do final da lista para o início. Adicionamos ao nombre do macro o sufixo Back e fazemos pequenas alterações. Veja como se vê o macro para rastreamento de símbolos na Observação do mercado.

#define ForEachSymbolBack(symbol,i) int s_start=SymbolsTotal(true)-1;\
   string symbol=SymbolName(s_start,true);                           \
   for(int i=s_start;i>=0;i--,symbol=SymbolName(i,true))
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   ForEachSymbolBack(symbol,index)
     {
      //--- preparamos os dados
      double spread=SymbolInfoDouble(symbol,SYMBOL_ASK)-SymbolInfoDouble(symbol,SYMBOL_BID);
      double point=SymbolInfoDouble(symbol,SYMBOL_POINT);
      long digits=SymbolInfoInteger(symbol,SYMBOL_DIGITS);
      string str_spread=DoubleToString(spread/point,0);
      string str_point=DoubleToString(point,digits);
      //--- imprimimos as informações
      Print(index,". ",symbol," spread=",str_spread," points (",
            digits," digits",", point=",str_point,")");
     }
/* Exemplo de impressão
   3. USDJPY spread=5 points (3 digits, point=0.001)
   2. USDCHF spread=8 points (5 digits, point=0.00001)
   1. GBPUSD spread=9 points (5 digits, point=0.00001)
   0. EURUSD spread=2 points (5 digits, point=0.00001)
*/
  }

Como você pode ver, neste caso, o valor da variável index muda entre size-1 e 0. Assim conclui nossa introdução a #define e avançamos para a escrita de funções, para facilitar o acesso, em estilo MQL4.


1. Grupos de funções MQL4 descritas no artigo

Atenção: as variáveis como Point, Digits e Bar devem ser alteradas de modo independente para Point(), Digits() e Bar(Symbol(),Period())

Os grupos MQL4 AccountXXXX, MQL4 MarketInfo, MQL4 Verificação de estado, MQL4 Variáveis pré-definidas serão convertidos em MQL5. Desse modo, na pasta [date folder]\MQL5\Include\SimpleCall\ são adicionados quatro arquivos: AccountInfo.mqhMarketInfo.mqhCheck.mqhPredefined.mqh. No total, na pasta, haverá sete arquivos para converter funções MQL4 em MQL5: AccountInfo.mqh, Check.mqh, IndicatorsMQL4.mqh, IndicatorsMQL5.mqh, MarketInfo.mqh, Predefined.mqh e Series.mqh.

Para trabalhar, você precisará conectar por si só estes arquivos. Além disso, há uma restrição, isto é, os arquivos  IndicatorsMQL4.mqh e IndicatorsMQL5.mqh não podem ser conectados ao mesmo tempo, portanto é necessário selecionar um deles. Por isso, na pasta, há dois arquivos: SimpleCallMQL4.mqh, que conecta todos os arquivos mais IndicatorsMQL4.mqh, e SimpleCallMQL5.mqh, que conecta todos os arquivos mais IndicatorsMQL5.mqh.

Exemplo de conexão com MACD Sample.mq4

Copiamos o arquivo MACD Sample.mq4 na pasta MQL5 com os EAs, por exemplo, em [data folder]\MQL5\Experts\, e alteramos a extensão do arquivo para mq5. Assim, obtemos o arquivo MACD Sample.mq5. Compilamos e, imediatamente, obtemos 59 erros e um aviso.

Agora conectamos o arquivo SimpleCallMQL4.mqh:

//+------------------------------------------------------------------+
//|                                                  MACD Sample.mq4 |
//|                   Copyright 2005-2014, MetaQuotes Software Corp. |
//|                                              http://www.mql4.com |
//+------------------------------------------------------------------+
#property copyright   "2005-2014, MetaQuotes Software Corp."
#property link        "http://www.mql4.com"
//---
#include <SimpleCall\SimpleCallMQL4.mqh>
//---
input double TakeProfit    =50;

Novamente, compilamos e obtemos já 39 erros e um aviso. Agora, é necessário substituir manualmente (usando Ctrl+H) Bars por Bars(Symbol(),Period()) e Point por Point(). Compilamos. Restam 35 erros, todos eles pertencem a funções de negociação. Não vamos falar sobre tais funções, neste artigo.

1.1. MQL4 AccountXXXX

A conversão de funções MQL4 AccountXXXX é realizada no arquivo [date folder]\MQL5\Include\SimpleCall\AccountInfo.mqh

Veja a tabela de correspondências entres as funções MQL4 e MQL5:

MQL4 MQL5 AccountInfoXXXX MQL5 CAccountInfo  Comentário: 
 AccountInfoDouble  AccountInfoDouble  CAccountInfo::InfoDouble ou CAccountInfo::double métodos  
 AccountInfoInteger  AccountInfoInteger  CAccountInfo::InfoInteger ou CAccountInfo::métodos inteiros  
 AccountInfoString  AccountInfoString  CAccountInfo::InfoString ou CAccountInfo::métodos de texto  
 AccountBalance  AccountInfoDouble(ACCOUNT_BALANCE) ou   CAccountInfo::Balance  
 AccountCredit  AccountInfoDouble(ACCOUNT_CREDIT) ou   CAccountInfo::Credit  
 AccountCompany  AccountInfoString(ACCOUNT_COMPANY) ou   CAccountInfo::Company  
 AccountCurrency  AccountInfoString(ACCOUNT_CURRENCY) ou   CAccountInfo::Currency  
 AccountEquity  AccountInfoDouble(ACCOUNT_EQUITY) ou   CAccountInfo::Equity  
 AccountFreeMargin  AccountInfoDouble(ACCOUNT_FREEMARGIN) ou   CAccountInfo::FreeMargin  
 AccountFreeMarginCheck  --- /---  CAccountInfo::FreeMarginCheck   
 AccountFreeMarginMode  Não tem substituto  Não tem substituto  
 AccountLeverage  AccountInfoInteger(ACCOUNT_LEVERAGE)   CAccountInfo::Leverage  Em MQL4, existe o tipo int, enquanto em MQL5 - long
 AccountMargin  AccountInfoDouble(ACCOUNT_MARGIN)  CAccountInfo::Margin  
 AccountName  AccountInfoString(ACCOUNT_NAME)  CAccountInfo::Name  
 AccountNumber  AccountInfoInteger(ACCOUNT_LOGIN)  CAccountInfo::Login  Em MQL4, existe o tipo int, enquanto em MQL5 - long
 AccountProfit  AccountInfoDouble(ACCOUNT_PROFIT)  CAccountInfo::Profit   
 AccountServer  AccountInfoString(ACCOUNT_SERVER)  CAccountInfo::Server  
 AccountStopoutLevel  AccountInfoDouble(ACCOUNT_MARGIN_SO_SO)  CAccountInfo::MarginStopOut  Em MQL4, existe o tipo int, enquanto em MQL5 - double
 AccountStopoutMode  AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE)  CAccountInfo::StopoutMode  

Atenção, para MQL4 AccountFreeMarginMode não existe substituto em MQL5. Use MQL4 AccountFreeMarginMode por sua própria conta e risco. No caso de MQL4 AccountFreeMarginMode, no log será impresso um aviso e será retornado NaN - "não é um número".

Para as outras funções MQL4 AccountXXXX existem substitutos, ainda por cima, em duas formas: através de AccountInfoXXXX ou através da classe de negociação CAccountInfo. Para AccountInfoDouble, AccountInfoInteger e AccountInfoString, não existem diferenças entre MQL4 e MQL5.

No cabeçalho do arquivo, encontra-se o seguinte código. Como isso funciona?

//---
#define  OP_BUY                     ORDER_TYPE_BUY
#define  OP_SELL                    ORDER_TYPE_SELL
//--- returns balance value of the current account

Para começar, demos uma vista de olhos para a ajuda do #define:

A diretiva #define pode ser utilizada para atribuir às expressões nomes mnemônicos. Existem duas formas:

#define identifier expression                   // forma não paramétrica 
#define identifier(par1,... par8) expression    // forma paramétrica

A diretiva #define substitui expression por todas as ocorrências subsequentes de identifier, encontradas no texto original.

No caso do nosso código, essa descrição será assim (usamos a forma não paramétrica): diretiva #define substitui ORDER_TYPE_BUY por todas as ocorrências subsequentes OP_BUY encontradas no texto de origem. Diretiva #define substitui ORDER_TYPE_SELL por todas as ocorrências subseqüentes OP_SELL, encontradas no texto de origem. Ou seja, após conectar o arquivo [date folder]\MQL5\Include\SimpleCall\AccountInfo.mqh ao seu EA MQL5, você poderá usar nele de maneira usual os tipos MQL4 OP_BUY e OP_SELL. O compilador não gerará erros.

Assim, o primeiro grupo de funções que apresentamos em estilo MQL5 é: AccountBalance(), AccountCredit(), AccountCompany(), AccountCurrency(), AccountEquity() e AccountFreeMargin():

//--- returns balance value of the current account
#define  AccountBalance(void)       AccountInfoDouble(ACCOUNT_BALANCE)
//--- returns credit value of the current account
#define  AccountCredit(void)        AccountInfoDouble(ACCOUNT_CREDIT)
//--- returns the brokerage company name where the current account was registered
#define  AccountCompany(void)       AccountInfoString(ACCOUNT_COMPANY)
//--- returns currency name of the current account 
#define  AccountCurrency(void)      AccountInfoString(ACCOUNT_CURRENCY)
//--- returns equity value of the current account
#define  AccountEquity(void)        AccountInfoDouble(ACCOUNT_EQUITY)
//--- returns free margin value of the current account
#define  AccountFreeMargin(void)    AccountInfoDouble(ACCOUNT_MARGIN_FREE)
Neste caso, nas funções MQL4 XXXX(void), usa-se a forma paramétrica #define, onde "void" serve como parâmetro. Isto é fácil de verificar, pois se você remover o "void", durante a compilação, irá obter o erro "unexpected in macro format parameter list":


unexpected in macro format parameter list

No caso de MQL4 AccountFreeMarginCheck, agimos de forma diferente, quer dizer, implementamos AccountFreeMarginCheck como uma função habitual dentro da qual é usado apenas código MQL5:

//--- returns free margin that remains after the specified order has been opened 
//---    at the current price on the current account
double   AccountFreeMarginCheck(string symbol,int cmd,double volume)
  {
   double price=0.0;
   ENUM_ORDER_TYPE trade_operation=(ENUM_ORDER_TYPE)cmd;
   if(trade_operation==ORDER_TYPE_BUY)
      price=SymbolInfoDouble(symbol,SYMBOL_ASK);
   if(trade_operation==ORDER_TYPE_SELL)
      price=SymbolInfoDouble(symbol,SYMBOL_BID);
//---
   double margin_check=EMPTY_VALUE;
   double margin=EMPTY_VALUE;
   margin_check=(!OrderCalcMargin(trade_operation,symbol,volume,price,margin))?EMPTY_VALUE:margin;
//---
   return(AccountInfoDouble(ACCOUNT_FREEMARGIN)-margin_check);
  }

Como mencionado acima, para AccountFreeMarginMode não existe substituto em MQL5, por isso, se, no código, aparecer AccountFreeMarginMode, será emitido um aviso e retornado "não é um número":

//--- returns the calculation mode of free margin allowed to open orders on the current account
double AccountFreeMarginMode(void)
  {
   string text="MQL4 functions \"AccountFreeMarginMode()\" has no analogs in MQL5. Returned \"NAN - not a number\"";
   Alert(text);
   Print(text);
   return(double("nan"));
  }

Para as outras funções MQL4, agimos como com as anteriores:

//--- returns leverage of the current account
#define  AccountLeverage(void)      (int)AccountInfoInteger(ACCOUNT_LEVERAGE)
//--- returns margin value of the current account
#define  AccountMargin(void)        AccountInfoDouble(ACCOUNT_MARGIN)
//--- returns the current account name
#define  AccountName(void)          AccountInfoString(ACCOUNT_NAME)
//--- returns the current account number
#define  AccountNumber(void)        (int)AccountInfoInteger(ACCOUNT_LOGIN)
//--- returns profit value of the current account
#define  AccountProfit(void)        AccountInfoDouble(ACCOUNT_PROFIT)
//--- returns the connected server name
#define  AccountServer(void)        AccountInfoString(ACCOUNT_SERVER)
//--- returns the value of the Stop Out level
#define  AccountStopoutLevel(void)  (int)AccountInfoDouble(ACCOUNT_MARGIN_SO_SO)
//--- returns the calculation mode for the Stop Out level
int      AccountStopoutMode(void)
  {
   ENUM_ACCOUNT_STOPOUT_MODE stopout_mode=(ENUM_ACCOUNT_STOPOUT_MODE)AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE);
   if(stopout_mode==ACCOUNT_STOPOUT_MODE_PERCENT)
      return(0);
   return(1);
  }

1.2. MQL4 MarketInfo

A conversão de funções MQL4 MarketInfotXXXX é realizada no arquivo [date folder]\MQL5\Include\SimpleCall\MarketInfo.mqh

MQL4 MarketInfo tem o tipo double, mas, em MQL5, existem substitutos de MarketInfo em SymbolInfoInteger() (retorna o tipo long) e em SymbolInfoDouble() (retorna o tipo double). Neste caso, faz-se notar toda a trapalhada ao usar funções obsoletas MarketInfo: conversão de tipos. Como exemplo de conversão MQL5 SYMBOL_DIGITS:

MarketInfo(Symbol(),MODE_DIGITS) <= (double)SymbolInfoInteger(symbol,SYMBOL_DIGITS)

1.2.1 Ambiguidade com MQL4 MODE_TRADEALLOWED 

Em MQL4, ele é simplesmente um sinalizador bool, enquanto em MQL5, para os símbolos, pode haver vários tipos de autorizações/proibições:

ENUM_SYMBOL_TRADE_MODE

Identificador Descrição
 SYMBOL_TRADE_MODE_DISABLED  Proibida negociação segundo o símbolo
 SYMBOL_TRADE_MODE_LONGONLY  Habilitadas apenas compras
 SYMBOL_TRADE_MODE_SHORTONLY  Habilitadas apenas vendas
 SYMBOL_TRADE_MODE_CLOSEONLY  Habilitadas apenas operações de fechamento de posições
 YMBOL_TRADE_MODE_FULL  Não há restrições sobre as operações de negociação

Proponho retornar false apenas se SYMBOL_TRADE_MODE_DISABLED, enquanto para restrições parciais ou para acesso completo - true (e, ao mesmo tempo, emitir Alert e Print com um aviso de restrição parcial).

1.2.2. Ambiguidade com MQL4 MODE_SWAPTYPE

Em MQL4, MODE_SWAPTYPE retorna apenas quatro valores (método de avaliação de swaps. 0 - em pontos; 1 - em moeda base do instrumento; 2 - em porcentagem; 3 - em moeda de garantia), enquanto em MQL5 a enumeração ENUM_SYMBOL_SWAP_MODE contém nove valores que se cruzam com os valores em MQL4:

MQL4 MODE_SWAPTYPE MQL5 ENUM_SYMBOL_SWAP_MODE
 Sem correspondência  SYMBOL_SWAP_MODE_DISABLED
 0 - em pontos  SYMBOL_SWAP_MODE_POINTS
 1 - na moeda base do instrumento  SYMBOL_SWAP_MODE_CURRENCY_SYMBOL
 3 - na moeda da garantia  SYMBOL_SWAP_MODE_CURRENCY_MARGIN
 Sem correspondência  SYMBOL_SWAP_MODE_CURRENCY_DEPOSIT
 2 - em porcentagem  SYMBOL_SWAP_MODE_INTEREST_CURRENT
 2 - em porcentagem  SYMBOL_SWAP_MODE_INTEREST_OPEN
 Sem correspondência  SYMBOL_SWAP_MODE_REOPEN_CURRENT
 Sem correspondência  SYMBOL_SWAP_MODE_REOPEN_BID

Em MQL5, para cálculo dos swaps em porcentagem, existem duas opções:

/*
SYMBOL_SWAP_MODE_INTEREST_CURRENT
Swaps são calculados em porcentagem anual do preço do instrumento no momento do cálculo do swap (modo bancário - 360 dias por ano)
SYMBOL_SWAP_MODE_INTEREST_OPEN
Swaps são calculados em porcentagem anual do preço de abertura da posição segundo o símbolo (modo bancário - 360 dias por ano)
*/

Vamos considerá-los como um tipo. Para o resto de variantes MQL5, que não têm análogos em MQL4, será emitido um aviso e retornado "não é um número".

1.2.3. Ambiguidade com MQL4 MODE_PROFITCALCMODE e MODE_MARGINCALCMODE

Em MQL4 MODE_PROFITCALCMODE (método de cálculo do lucro) retorna três valores: 0 - Forex; 1 - CFD; 2 - Futures, enquanto MODE_MARGINCALCMODE (método de cálculo da garantia) - quatro: 0 - Forex; 1 - CFD; 2 - Futures; 3 - CFD para índices. Em MQL5, para o instrumento, pode ser definido o método de cálculo da garantia (enumeração ENUM_SYMBOL_CALC_MODE), mas não o método para calcular o lucro. Assumo que em MQL5, o cálculo da garantia é como o de lucros, por isso, para MQL4 MODE_PROFITCALCMODE  e MODE_MARGINCALCMODE, será retornado o mesmo valor com MQL5 ENUM_SYMBOL_CALC_MODE.

A enumeração MQL5 ENUM_SYMBOL_CALC_MODE contém dez maneiras. Comparamos MQL4 MODE_PROFITCALCMODE com MQL5 ENUM_SYMBOL_CALC_MODE:

MQL4 MODE_PROFITCALCMODE "Forex" <==> MQL5 SYMBOL_CALC_MODE_FOREX

MQL4 MODE_PROFITCALCMODE "CFD" <==> MQL5 SYMBOL_CALC_MODE_CFD

MQL4 MODE_PROFITCALCMODE "Futures" <==> MQL5 SYMBOL_CALC_MODE_FUTURES

Para o resto de variantes MQL5, que não têm análogos em MQL4, será emitido um aviso e retornado "não é um número":

...
#define MODE_PROFITCALCMODE   1000//SYMBOL_TRADE_CALC_MODE
#define MODE_MARGINCALCMODE   1001//SYMBOL_TRADE_CALC_MODE
...
      case MODE_PROFITCALCMODE:
        {
         ENUM_SYMBOL_CALC_MODE profit_calc_mode=(ENUM_SYMBOL_CALC_MODE)SymbolInfoInteger(symbol,SYMBOL_TRADE_CALC_MODE);
         switch(profit_calc_mode)
           {
            case  SYMBOL_CALC_MODE_FOREX:
               return((double)0);
            case  SYMBOL_CALC_MODE_FUTURES:
               return((double)2);
            case  SYMBOL_CALC_MODE_CFD:
               return((double)1);
            default :
              {
               string text="MQL4 MODE_PROFITCALCMODE returned MQL5 "+EnumToString(profit_calc_mode);
               Alert(text);
               Print(text);
               return(double("nan"));
              }
           }
        }
      case MODE_MARGINCALCMODE:
        {
         ENUM_SYMBOL_CALC_MODE profit_calc_mode=(ENUM_SYMBOL_CALC_MODE)SymbolInfoInteger(symbol,SYMBOL_TRADE_CALC_MODE);
         switch(profit_calc_mode)
           {
            case  SYMBOL_CALC_MODE_FOREX:
               return((double)0);
            case  SYMBOL_CALC_MODE_FUTURES:
               return((double)2);
            case  SYMBOL_CALC_MODE_CFD:
               return((double)1);
            default :
              {
               string text="MQL4 MODE_MARGINCALCMODE returned MQL5 "+EnumToString(profit_calc_mode);
               Alert(text);
               Print(text);
               return(double("nan"));
              }
           }
        }

1.3. MQL4 Verificação de estado

A conversão de funções MQL4 para verificação de status é realizada no arquivo  [date folder]\MQL5\Include\SimpleCall\Check.mqh

Isto inclui os seguintes elementos:

  • Digits
  • Point
  • IsConnected
  • IsDemo
  • IsDllsAllowed
  • IsExpertEnabled
  • IsLibrariesAllowed
  • IsOptimization
  • IsTesting
  • IsTradeAllowed
  • IsTradeContextBusy
  • IsVisualMode
  • TerminalCompany
  • TerminalName
  • TerminalPath
MQL4 MQL5 MQL5 classes Observação
 Digits

 MQL4 permite usar simultaneamente Digits e Digits()
 Point

 MQL4 permite usar simultaneamente Point e Point()
 IsConnected  TerminalInfoInteger(TERMINAL_CONNECTED)  CTerminalInfo::IsConnected 
 IsDemo  AccountInfoInteger(ACCOUNT_TRADE_MODE)  CAccountInfo::TradeMode  Retorna um dos valores da enumeração ENUM_ACCOUNT_TRADE_MODE
 IsDllsAllowed  TerminalInfoInteger(TERMINAL_DLLS_ALLOWED) e MQLInfoInteger(MQL_DLLS_ALLOWED)  CTerminalInfo::IsDLLsAllowed   TERMINAL_DLLS_ALLOWED - tem o mais alto status, e MQL_DLLS_ALLOWED pode ser ignorado
 IsExpertEnabled  TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)   CTerminalInfo::IsTradeAllowed  Status do botão "Autotrading" no terminal
 IsLibrariesAllowed  MQLInfoInteger(MQL_DLLS_ALLOWED)  -/-  A verificação não faz sentido, porque, se o programa usa DLL e você não permite sua utilização (a guia "Dependência" do programa), você simplesmente não poderá executar o programa.
 IsOptimization  MQLInfoInteger(MQL_OPTIMIZATION)  -/-  Os programas MQL5 podem ter quatro modos: depuração, criação de perfil do código, testador, otimização
 IsTesting  MQLInfoInteger(MQL_TESTER)  -/-  Os programas MQL5 podem ter quatro modos: depuração, criação de perfil do código, testador, otimização
 IsTradeAllowed  MQLInfoInteger(MQL_TRADE_ALLOWED)  -/-  Estado da caixa de verificação "Ativar negociação automatizada" nas propriedades do programa
 IsTradeContextBusy  -/-  -/-  Será retornado "false"
 IsVisualMode  MQLInfoInteger(MQL_VISUAL_MODE)
 Os programas MQL5 podem ter quatro modos: depuração, criação de perfil do código, testador, otimização
 TerminalCompany  TerminalInfoString(TERMINAL_COMPANY)  CTerminalInfo::Company  
 TerminalName  TerminalInfoString(TERMINAL_NAME)  CTerminalInfo::Name  
 TerminalPath  TerminalInfoString(TERMINAL_PATH)  CTerminalInfo::Path  

Os primeiros dois pontos (Digits e Point) são completamente irrealizáveis, ​​uma vez que MQL4 e MQL5 estão totalmente misturadas. Ou seja, em MQL4, podem-se encontrar simultaneamente Digits e Digits(), Point e Point(). Por exemplo, eu pessoalmente não sei como, através de define, Digits e Digits() podem ser reduzidos a Digits(). Os pontos restantes são encontrados exclusivamente na forma XXXX() e podem ser substituídos por análogos MQL5.

E a realização em si:

//+------------------------------------------------------------------+
//|                                                        Check.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "http://wmua.ru/slesar/"
#property version   "1.003" 
//--- checks connection between client terminal and server
#define IsConnected        (bool)TerminalInfoInteger(TERMINAL_CONNECTED)
//--- checks if the Expert Advisor runs on a demo account
#define IsDemo             (bool)(AccountInfoInteger(ACCOUNT_TRADE_MODE)==(ENUM_ACCOUNT_TRADE_MODE)ACCOUNT_TRADE_MODE_DEMO)
//--- checks if the DLL function call is allowed for the Expert Advisor
#define IsDllsAllowed      (bool)TerminalInfoInteger(TERMINAL_DLLS_ALLOWED) 
//--- checks if Expert Advisors are enabled for running
#define IsExpertEnabled    (bool)TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) 
//--- checks if the Expert Advisor can call library function
#define IsLibrariesAllowed (bool)MQLInfoInteger(MQL_DLLS_ALLOWED)
//--- checks if Expert Advisor runs in the Strategy Tester optimization mode
#define IsOptimization     (bool)MQLInfoInteger(MQL_OPTIMIZATION)
//--- checks if the Expert Advisor runs in the testing mode
#define IsTesting                (bool)MQLInfoInteger(MQL_TESTER)
//--- checks if the Expert Advisor is allowed to trade and trading context is not busy 
#define IsTradeAllowed     (bool)MQLInfoInteger(MQL_TRADE_ALLOWED)
//--- returns the information about trade context 
#define IsTradeContextBusy  false
//--- checks if the Expert Advisor is tested in visual mode 
#define IsVisualMode          (bool)MQLInfoInteger(MQL_VISUAL_MODE)
//--- returns the name of company owning the client terminal 
#define TerminalCompany    TerminalInfoString(TERMINAL_COMPANY)
//--- returns client terminal name
#define TerminalName          TerminalInfoString(TERMINAL_NAME)
//--- returns the directory, from which the client terminal was launched
#define TerminalPath          TerminalInfoString(TERMINAL_PATH)
//+------------------------------------------------------------------+

1.4. MQL4 Variáveis pré-definidas

Realização no arquivo [data folder]\MQL5\Include\SimpleCall\Predefined.mqh

MQL4 variáveis pré-definidas:

  • _Digits
  • _Point
  • _LastError
  • _Period
  • _RandomSeed
  • _StopFlag
  • _Symbol
  • _UninitReason
  • Ask
  • Bars
  • Bid
  • Close
  • Digits
  • High
  • Low
  • Open
  • Point
  • Time
  • Volume

Variáveis pré-definidas _XXXX são convertidas em funções MQL5 usando os formulários sem parâmetros #define:

//--- the _Digits variable stores number of digits after a decimal point,
#define _Digits         Digits()
//--- the _Point variable contains the point size of the current symbol in the quote currency
#define _Point          Point()
//--- the _LastError variable contains code of the last error
#define _LastError      GetLastError()
//--- the _Period variable contains the value of the timeframe of the current chart
#define _Period         Period()
//#define _RandomSeed
//--- the _StopFlag variable contains the flag of the program stop
#define _StopFlag       IsStopped()
//--- the _Symbol variable contains the symbol name of the current chart
#define _Symbol         Symbol()
//--- the _UninitReason variable contains the code of the program uninitialization reason
#define _UninitReason   UninitializeReason()
//#define Bars            Bars(Symbol(),Period());
//#define Digits
//#define Point

A exceção é para "_RandomSeed", isto é, nesta variável, por um lado, é armazenado o estado atual do gerador de números inteiros pseudo-aleatórios e, por outro lado, em MQL5, também não há conversão em Bars (mais precisamente, Bars é deixado para substituição manual). Para Digits e Point não há solução. Como mencionado acima, no texto, podem ocorrer simultaneamente Digits e Digits(), e Point e Point().

MQL4 Ask e Bid são substituídas pelas funções personalizadas GetAsk() e GetBid():

//--- the latest known seller's price (ask price) for the current symbol
#define Ask             GetAsk()
//--- the latest known buyer's price (offer price, bid price) of the current symbol
#define Bid             GetBid()
...
//--- the latest known seller's price (ask price) for the current symbol                  
double GetAsk()
  {
   MqlTick tick;
   SymbolInfoTick(Symbol(),tick);
   return(tick.ask);
  }
//--- the latest known buyer's price (offer price, bid price) of the current symbol             
double GetBid()
  {
   MqlTick tick;
   SymbolInfoTick(Symbol(),tick);
   return(tick.bid);
  }

Claro, nós poderíamos escrever um macro para Ask mais simples:

#define Ask SymbolInfoDouble(__Symbol,SYMBOL_ASK)

Mas a nota a SymbolInfoDouble diz:

Se a função é usada para obter informações sobre o último tick, é melhor utilizar SymbolInfoTick(). É possível que, desde a conexão do terminal à conta de negociação, este símbolo não tenha tido cotações. Nesse caso, o valor consultado é indefinido.

Na maioria dos casos, basta usar a função SymbolInfoTick(). Ela permite, numa única chamada, obter os valores Ask, Bid, Last, Volume e hora de chegada do último tick.

E agora algo novo, usamos "operator"

Usaremos a palavra-chave operator, para sobrecarregar o operador de indexação []. Isto é necessário para converter, em MQL5, as matrizes e timeseries MQL4 (Open[], High[], Low[], Close[], Time[], Volume[]).

A ajuda do "operator" nos diz:

A sobrecarga de operações permite utilizar a notação operacional (entrada na forma de expressões simples) para objetos complexos - estruturas e classes.

Com base na ajuda, pode se presumir que, para sobrecarregar o operador de indexação [], é preciso criar uma classe.

Lembrando sobre #define:

A diretiva #define pode ser utilizada para atribuir às expressões nomes mnemônicos. Existem duas formas:

#define identifier expression                   // forma não paramétrica 
#define identifier(par1,... par8) expression    // forma paramétrica

A diretiva #define substitui expression por todas as ocorrências subsequentes de identifier, encontradas no texto original.

o seguinte código pode ser lido como: diretiva #define substitui 159 por todas as ocorrências subseqüentes encontradas no texto de origem.

#define SeriesVolume(Volume,T) 159
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   long a=SeriesVolume(Volume,long);
  }

Ou seja, o código em OnStart é convertido na forma:

   long a=159;

Passo 2

Aqui dentro de #define é colocada uma classe inteira

//+------------------------------------------------------------------+
//|                                                      Test_en.mq5 |
//|                                      Copyright 2012, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
#define SeriesVolume(Volume,T) class CVolume       \
  {                                                \
  public:                                          \
    T operator[](const int i) const                \
    {                                              \
    long val[1];                                   \
    if(CopyTickVolume(Symbol(),Period(),i,1,val)==1)\
      return(val[0]);                              \
    else                                           \
      return(-1);                                  \
    }                                              \
  };                                               \
CVolume Volume;
//---
SeriesVolume(Volume,long)
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   Print(Volume[4]);
  }
//+------------------------------------------------------------------+

Esta substituição pode ser apresentada da seguinte forma:

//+------------------------------------------------------------------+
//|                                                      Test_en.mq5 |
//|                                      Copyright 2012, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
class CVolume      
  {                                                
  public:                                          
    long operator[](const int i) const                
    {                                              
    long val[1];                                   
    if(CopyTickVolume(Symbol(),Period(),i,1,val)==1)
      return(val[0]);                              
    else                                           
      return(-1);                                  
    }                                              
  };                                               
CVolume Volume;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   Print(Volume[4]);
  }

Ou seja, em OnStart, nós, na realidade, acessamos o objeto Volume da classe CVolume, o método [], em que redirecionamos o índice i. Usando o mesmo princípio, escrevemos para as séries MQL4 Open, High, Low, Close e Time.

E, finalmente, ficam as funções iXXX MQL4: iOpen, iHigh, iLow, iClose, iTime e iVolume. Para elas, implementamos o método de declaração de funções personalizadas.

Exemplo para iClose:

//--- returns Close price value for the bar of specified symbol with timeframe and shift
double   iClose(
                string                    symbol,              // symbol
                ENUM_TIMEFRAMES           timeframe,           // timeframe
                int                       shift                // shift
                )
  {
   double result=0.0;
//---
   double val[1];
   ResetLastError();
   int copied=CopyClose(symbol,timeframe,shift,1,val);
   if(copied>0)
      result=val[0];
   else
      Print(__FUNCTION__,": CopyClose error=",GetLastError());
//---
   return(result);
  }

2. Alterações em outros arquivos

Em [data folder]\MQL5\Include\SimpleCall\IndicatorsMQL4.mqh, todos os nomes de linhas MQL4 agora estão no cabeçalho:

double NaN=double("nan");
#define MODE_MAIN          0   
#define MODE_SIGNAL        1
#define MODE_PLUSDI        1
#define MODE_MINUSDI       2  
#define MODE_GATORJAW      1
#define MODE_GATORTEETH    2
#define MODE_GATORLIPS     3 
#define MODE_UPPER         1
#define MODE_LOWER         2  
#define MODE_TENKANSEN     1     
#define MODE_KIJUNSEN      2                                   
#define MODE_SENKOUSPANA   3                                 
#define MODE_SENKOUSPANB   4                                 
#define MODE_CHIKOUSPAN    5   

Em [data folder]\MQL5\Include\SimpleCall\Series.mqh foram retirados 

#define MODE_OPEN    0
//#define MODE_LOW     1
//#define MODE_HIGH    2
#define MODE_CLOSE   3
#define MODE_VOLUME  4
//#define MODE_TIME    5

Agora eles estão em [data folder]\MQL5\Include\SimpleCall\Header.mqh :

//+------------------------------------------------------------------+
//|                                                       Header.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "http://wmua.ru/slesar/"
//---
#define MODE_LOW     10001
#define MODE_HIGH    10002
#define MODE_TIME    10005

e iClose, iHigh, iLow, iOpen, iTime e iVolume agora estão em [data folder]\MQL5\Include\SimpleCall\Predefined.mqh


Fim do artigo

No artigo anterior, vimos como escrever chamadas de indicadores em estilo MQL4 e o que isso acarreta. Acontece que, devido à simplicidade da escrita, é mais lento o trabalho dos EA, que não têm controle sobre os indicadores criados. Neste artigo, nós continuamos a procurar maneiras de simplificar a escrita de código e revisamos a substituição de macros #define.

Como resultado, vemos que, com a ajuda dos código anexados ao artigo, quase qualquer EA MQL4 pode ser obrigado a funcionar no MetaTrader 5. Só é necessário conectar os arquivos necessários que sobrecarregam ou adicionam funções necessárias e variáveis ​​pré-definidas.

Para ser completamente compatível, não basta usar apenas funções de negociação MQL4 simplificadas. Mas este problema é resolvido, se desejado. Resumindo, mais uma vez os prós e contras desta abordagem:

Contras:

  • restrição no processamento do erro de retorno ao acessar o indicador;
  • queda da velocidade de teste ao acessar simultaneamente mais de um indicador;
  • necessidade de especificar corretamente a linha dos indicadores dependendo da conexão de "IndicatorsMQL5.mqh" ou "IndicatorsMQL4.mqh".
  • impossibilidade para depurar a substituição de macros #define;
  • inexistência de dica de balão sobre os argumentos do #define paramétrico;
  • potenciais conflitos de variáveis escondidas atrás de macros.
Prós
  • simplicidade na escrita do código, isto é, uma linha em vez de várias;
  • clareza e concisão, isto é, quanto menos código, é mais fácil de compreendê-lo;
  • substituições de macros são realçadas a vermelho no editor, o que facilita a visualização de identificadores e funções personalizados;
  • podem-se criar substitutos dos trechos de código.

Eu próprio considero que as técnicas mostradas no artigo são, justamente, "lifehacks", isto é, truques para superar a sobrecarga de informação, e continuo empenhado na abordagem clássica MQL5. Talvez aqueles que estão acostumados a escrever em MQL4 possam ser ajudados por estes artigos a superar a barreira psicológica na transição para a plataforma MetaTrader 5, que em todos os aspectos é muito mais conveniente.



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

Arquivos anexados |
ForEachSymbol.mq5 (3.74 KB)
ForEachObject.mq5 (2.82 KB)
ForEachOrder.mq5 (2.59 KB)
ForEachDeal.mq5 (1.24 KB)
SimpleCall.zip (25.38 KB)
Teste de padrões que surgem ao negociar cestas de pares de moedas. Parte III Teste de padrões que surgem ao negociar cestas de pares de moedas. Parte III
Neste artigo, nós terminamos de testar os padrões que podem ser detectados ao negociar cestas de par de moedas. Aqui nós apresentamos os resultados do teste dos padrões que rastreiam o movimento das moedas dos pares em relação uns aos outros.
Gerenciamento de capital de Vince. Realização como módulo de Assistente MQL5 Gerenciamento de capital de Vince. Realização como módulo de Assistente MQL5
O artigo foi escrito com base no livro de Ralph Vince, “The Mathematics of Money Management”. Nele, são discutidos os métodos empíricos e paramétricos, a fim de encontrar o tamanho ideal de lotes de negociação, em cuja base estão escritos os módulos de gerenciamento de capital para o assistente MLQ5.
ZUP - ZigZag universal com padrões Pesavento. Pesquisa de padrões ZUP - ZigZag universal com padrões Pesavento. Pesquisa de padrões
A plataforma-indicador do ZUP permite pesquisar padrões populares com parâmetros já definidos. Embora eles estejam definidos, você também pode ajustá-los de acordo com suas necessidades. Há também a possibilidade de criar novos padrões usando a interface gráfica do ZUP e salvar seus parâmetros num arquivo. Depois disso, você pode verificar rapidamente se há novos padrões nos gráficos.
O padrão Rompimento de Canal O padrão Rompimento de Canal
As tendências de preços formam canais de preços que podem ser observados nos gráficos dos instrumentos financeiros. O rompimento do canal atual é um forte sinal de reversão de tendência. Neste artigo, eu sugiro uma maneira de automatizar o processo de encontrar esses sinais e ver se o padrão de rompimento de canal pode ser usado para criar uma estratégia de negociação.