English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
Limitações e verificações em Expert Advisors

Limitações e verificações em Expert Advisors

MetaTrader 5Exemplos | 4 dezembro 2013, 12:41
4 151 1
MetaQuotes
MetaQuotes

Introdução

Quando se cria um algoritmo para uma negociação automatizada você deve ser capaz não só apenas de processar os preços para criar sinais de comércio, mas ser capaz de obter uma série de informações auxiliares sobre as limitações impostas sobre o funcionamento do Expert Advisors. Este artigo irá dizer-lhe como:

  • Obter informações sobre sessões de negociação;
  • Verificar se você tem recursos suficientes para abrir uma posição;
  • Impor uma limitação sobre o volume total de negociação por um símbolo;
  • Impor uma limitação sobre o número total de pedidos;
  • Calcular a perda de potencial entre o preço de entrada e o nível de cotação;
  • Verificar se há uma nova barra.

Sessões de Cotação e Negociação

Para receber informações sobre as sessões de negociação, você deve usar a função SymbolInfoSessionTrade, e para as sessões correspondentes a cotação use SymbolInfoSessionQuote. Ambas as funções trabalham da mesma maneira: se há uma sessão com o índice especificado para o dia especificado da semana (a indexação das sessões começa a partir de zero), então a função retorna para true. O tempo de início e fim de uma sessão é escrito ao quarto e quinto parâmetros passados pelo link.

//--- verificar se há uma sessão de cotação com o número session_index
bool session_exist=SymbolInfoSessionQuote(symbol,day,session_index,start,finish);
Para saber tudo do dia especificado da sessão, qualificar essa função em um ciclo até que ela retorne a false.
//+------------------------------------------------------------------+
//|  Exibir informações sobre sessões de cotação                     |
//+------------------------------------------------------------------+
void PrintInfoForQuoteSessions(string symbol,ENUM_DAY_OF_WEEK day)
  {
//--- início e fim de sessão
   datetime start,finish;
   uint session_index=0;
   bool session_exist=true;

//--- verificar todas as sessões deste dia
   while(session_exist)
     {
      //--- verificar se há uma sessão de cotação com o número session_index
      session_exist=SymbolInfoSessionQuote(symbol,day,session_index,start,finish);

      //--- se existe tal sessão
      if(session_exist)
        {
         //--- mostrar o dia da semana, o número da sessão e o tempo de início e fim
         Print(DayToString(day),": índice da sessão=",session_index,"  começo=",
               TimeToString(start,TIME_MINUTES),"    final=",TimeToString(finish-1,TIME_MINUTES|TIME_SECONDS));
        }
      //--- aumentar o contador de sessões
      session_index++;
     }
  }

O dia da semana é exibido no formato string utilizando a função de customização DayToString() que recebe o valor da enumeração ENUM_DAY_OF_WEEK como parâmetro.

//+------------------------------------------------------------------+
//| Receber a representação da string de dia de semana               |
//+------------------------------------------------------------------+
string DayToString(ENUM_DAY_OF_WEEK day)
  {
   switch(day)
     {
      case SUNDAY:    return "Domingo";
      case MONDAY:    return "Segunda";
      case TUESDAY:   return "Terça";
      case WEDNESDAY: return "Quarta";
      case THURSDAY:  return "Quinta";
      case FRIDAY:    return "Sexta";
      case SATURDAY:  return "Sábado";
      default:        return "Dia da semana não definido";
     }
   return "";
  }

O código final do script SymbolInfoSession.mq5 está ligado à parte inferior do artigo. Vamos mostrar aqui apenas a sua parte principal.

void OnStart()
  {
//--- a matriz onde os dias da semana são armazenados
   ENUM_DAY_OF_WEEK days[]={SUNDAY,MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY};
   int size=ArraySize(days);

//---
   Print("Sessões de cotação");
//--- verificar todas as sessões deste dia
   for(int d=0;d<size;d++)
     {
      PrintInfoForQuoteSessions(Symbol(),days[d]);
     }

//---
   Print("Sessões de negociação");
//--- verificar todas as sessões deste dia
   for(int d=0;d<size;d++)
     {
      PrintInfoForTradeSessions(Symbol(),days[d]);
     }
  }


Verificando a Margem

Para descobrir a quantidade de margem requerida para aumentar ou abrir uma posição, você pode usar a função OrderCalcMargin(), o primeiro parâmetro que é passado para ele é um valor de enumeração ENUM_ORDER_TYPE. Para uma operação de compra você deve qualificá-la com o parâmetro de ORDER_TYPE_BUY; e para vender, use o parâmetro ORDER_TYPE_SELL. A função retorna a quantidade de margem em função do número de lotes e o preço aberto.

void OnStart()
  {
//--- variável para receber o valor da margem
   double margin;
//--- para receber informações sobre o último tick
   MqlTick last_tick;
//--- tentar receber o valor do último tick
   if(SymbolInfoTick(Symbol(),last_tick))
     {
      //--- zerar o último código de erro
      ResetLastError();
      //--- calcular o valor da margem
      bool check=OrderCalcMargin(type,Symbol(),lots,last_tick.ask,margin);
      if(check)
        {
         PrintFormat("Para a operação, %s  %s %.2f em %G requer margem de %.2f %s",OrderTypeToString(type),
                     Symbol(),lots,last_tick.ask,margin,AccountInfoString(ACCOUNT_CURRENCY));
        }
     }
   else
     {
      Print("Execução mal-sucedida da função SymbolInfoTick(), erro  ",GetLastError());
     }
  }

Deve-se notar que a função OrderCalcMargin() permite calcular o valor da margem, não só para as ordens de mercado, mas também para ordens pendentes. Você pode verificar os valores que são retornados para todos os tipos de ordens usando o script Check_Money.mq5.

função OrderCalcMargin() é destinada ao cálculo do tamanho da margem de ordens pendentes, visto que um apoio financeiro pode ser necessário em alguns sistemas de negociação para ordens pendentes também. Geralmente, o tamanho da margem para ordens pendentes é calculado através de um coeficiente para o tamanho da margem para as posições curtas e longas.

Identificador

Descrição

Tipo de Propriedade

SYMBOL_MARGIN_LONG

Taxa do carregamento de margem em posições longas

duplo

SYMBOL_MARGIN_SHORT

Taxa do carregamento de margem em posições curtas

duplo

SYMBOL_MARGIN_LIMIT

Taxa do carregamento de margem em ordens de Limite

duplo

SYMBOL_MARGIN_STOP

Taxa do carregamento de margem em ordem de Parada

duplo

SYMBOL_MARGIN_STOPLIMIT

Taxa do carregamento de margem em ordens de Limite de Parada

duplo


Você pode obter os valores desses coeficientes utilizando um código simples:

//--- Calcular as taxas de margem de carregamento para diferentes tipos de ordens
   PrintFormat("Taxa de margem em posições de compra é igual a  %G",SymbolInfoDouble(Symbol(),SYMBOL_MARGIN_LONG));
   PrintFormat("Taxa de margem em posições de venda é igual a %G",SymbolInfoDouble(Symbol(),SYMBOL_MARGIN_SHORT));
   PrintFormat("Taxa de margem em ordens limite é igual a %G",SymbolInfoDouble(Symbol(),SYMBOL_MARGIN_LIMIT));
   PrintFormat("Taxa de margem em ordens Stop é igual a  %G",SymbolInfoDouble(Symbol(),SYMBOL_MARGIN_STOP));
   PrintFormat("Taxa de margem em ordens Stop Limit é igual a  %G",SymbolInfoDouble(Symbol(),SYMBOL_MARGIN_STOPLIMIT));

Para símbolos de Forex, as taxas do carregamento de margem para ordens pendentes são geralmente igual a 0, ou seja, não há requisitos de margem para o deles.

Resultados da execução do script Check_Money.mq5.

Resultados da execução do script Check_Money.mq5.

Dependendo do modo do carregamento de margem, o sistema de gestão financeira pode mudar, assim como o próprio sistema de negociação pode ter algumas limitações se uma margem é necessária para ordens pendentes. É por isso que estes parâmetros também podem ser as limitações naturais de uma operação de Expert Advisor.

Contabilizando possíveis lucros e perdas

Ao colocar um nível de parada de proteção, você deve estar pronto para o seu acionamento. O risco de perda potencial deve ser tomado em consideração em termos de dinheiro, e a OrderCalcProfit() é destinada para este fim. É muito semelhante à função OrderCalcMargin() já considerada, mas exige tanto os preços abertos e fechados para calculação.

Especificar um dos dois valores da enumeração ENUM_ORDER_TYPE como o primeiro parâmetro - ORDER_TYPE_BUY ou ORDER_TYPE_SELL; outros tipos de ordens conduzirão a um erro. No último parâmetro, você deve passar uma variável usando a referência, para qual a função OrderCalcProfit() escreverá o valor do lucro/prejuízo em caso de execução bem sucedida.

A exemplo do uso da função CalculateProfitOneLot() que calcula o lucro ou prejuízo, ao fechar uma posição de compra com níveis específicos de entrada e saída:

//+------------------------------------------------------------------+
//| Calcular o potencial de lucro/prejuízo para a compra de 1 lote   |
//+------------------------------------------------------------------+
double CalculateProfitOneLot(double entry_price,double exit_price)
  {
//--- receber o valor de lucro para esta variável
   double profit=0;
   if(!OrderCalcProfit(ORDER_TYPE_BUY,Symbol(),1.0,entry_price,exit_price,profit))
     {
      Print(__FUNCTION__,"  Falhou em calcular OrderCalcProfit(). Erro ",GetLastError());
     }
//---
   return(profit);
  }

O resultado do cálculo desta função é mostrado na figura:

O exemplo de cálculo e exibição da perda potencial no gráfico usando a função OrderCalcProfit()

Todo o código pode ser encontrado em CalculateProfit_EA.mq5 Expert Advisor.

Verificar se há uma nova barra

O desenvolvimento de muitos sistemas de negociação pressupõe que os sinais de comércio são calculados apenas quando uma nova barra aparece e todas as ações comerciais são realizadas apenas uma vez. O modo "Somente os preços abertos" do testador de estratégia no terminal do cliente do MetaTrader 5 é bom para a verificação desses sistemas automáticos de negociação.

No modo "Apenas preços abertos", todos os cálculos de indicadores e qualificação da função OnTick(), no Expert Advisor, são realizadas apenas uma vez por barra durante o teste. É o modo mais rápido de negociação e, como regra, a forma mais tolerante à falhas ao meio de oscilações de preços insignificantes da criação dos sistemas de negociação. Ao mesmo tempo, é claro, os indicadores utilizados em um Expert Advisor devem ser escritos corretamente e não devem distorcer seus valores quando uma nova barra surge.

O testador de estratégia no modo "Preços abertos apenas" permite aliviá-lo de se preocupar que o Expert Advisor seja lançado apenas uma vez por barra, e é muito conveniente. Mas enquanto estiver trabalhando no modo de tempo real em um demo ou em uma conta real, um negociador deve controlar a atividade de seu Expert Advisor, para fazê-lo executar apenas uma operação de negócio por sinal recebido. A maneira mais fácil para essa finalidade é o acompanhamento de abertura da barra de informe atual.

Para obter o tempo de abertura da última barra, você deve usar a função SeriesInfoInteger() com o nome especificado do símbolo, período de tempo e propriedade SERIES_LASTBAR_DATE. Pela constante comparação do tempo de abertura da barra atual com a da barra armazenada em uma variável, você pode facilmente detectar o momento em que uma nova barra aparece. Ela permite criar a função personalizada de isNewBar() que pode parecer com a seguinte:

//+----------------------------------------------------------------------+
//| Retorna true se uma nova barra aparece para o par de símbolo/período |
//+----------------------------------------------------------------------+
bool isNewBar()
  {
//--- lembrar o tempo de abertura da última barra na variável estática
   static datetime last_time=0;
//--- tempo corrente
   datetime lastbar_time=SeriesInfoInteger(Symbol(),Period(),SERIES_LASTBAR_DATE);

//--- if it is the first call of the function
   if(last_time==0)
     {
      //--- definir tempo e sair
      last_time=lastbar_time;
      return(false);
     }

//--- se o tempo é diferente
   if(last_time!=lastbar_time)
     {
      //--- memorizar tempo e retornar true
      last_time=lastbar_time;
      return(true);
     }
//--- se passarmos desta linha e a barra não é nova, retorna false
   return(false);
  }

Um exemplo do uso da função é dado no anexo CheckLastBar.mq5 do Expert Advisor.

As mensagens do CheckLastBar Expert Advisor sobre o aparecimento de novas barras no período de tempo M1.

As mensagens do CheckLastBar do Expert Advisor sobre o aparecimento de novas barras no período de tempo M1

Limitando Número de Ordens Pendentes

Se você precisa limitar o número de ordens pendentes ativas que podem ser simultaneamente colocadas em uma conta, você pode escrever sua própria função customizada. Vamos nomeá-la de ordemIsNewpermitida; que verificará se é permitido colocar outra ordem pendente. Vamos escrevê-la em conformidade com as regras do campeonato de negociação automatizado.

//+------------------------------------------------------------------+
//| Verifica se é permitido colocar uma outra ordem                  |
//+------------------------------------------------------------------+
bool IsNewOrderAllowed()
  {
//--- obter o número permitido de pedidos pendentes em uma conta
   int max_allowed_orders=(int)AccountInfoInteger(ACCOUNT_LIMIT_ORDERS);

//--- se não há limitações, retorna true; você pode enviar uma ordem
   if(max_allowed_orders==0) return(true);

//--- se passarmos dessa linha, então há limitações; detectar quantos pedidos já estão ativos
   int orders=OrdersTotal();

//--- retorna o resultado da comparação
   return(orders<max_allowed_orders);
  }

A função é simples: obter o número permitido de ordens para a variável max_allowed_orders, e se o seu valor não é igual a zero, comparar com o número atual de ordens. No entanto, esta função não considera uma outra possível limitação - a limitação do volume total permitido de posições abertas e ordens pendentes por um símbolo específico.

Limitando o número de grandes quantidades por um símbolo específico

Para obter o tamanho de uma posição aberta por um símbolo específico, primeiro de tudo, você precisa selecionar uma posição usando a função PositionSelect(). E só depois disso, você pode solicitar o volume da posição aberta usando o PositionGetDouble(), que retorna várias propriedades da posição selecionada que tem o tipo duplo. Vamos escrever a função PositionVolume() para obter o volume de posição por um símbolo determinado.

//+------------------------------------------------------------------+
//| Retorna o tamanho da posição de um símbolo específico            |
//+------------------------------------------------------------------+
double PositionVolume(string symbol)
  {
//--- tentar selecionar uma posição de um símbolo
   bool selected=PositionSelect(symbol);
//--- a posição existe
   if(selected)
      //--- retorna o volume da posição
      return(PositionGetDouble(POSITION_VOLUME));
   else
     {
      //--- informa sobre a tentativa frustrada de selecionar a posição
      Print(__FUNCTION__," Falhou em executar PositionSelect() para o símbolo ",
            symbol," Erro ",GetLastError());
      return(-1);
     }
  }

Antes de fazer um pedido de negócio para estabelecer uma ordem pendente por um símbolo, você deve verificar a limitação do volume total da posição em aberto e ordens pendentes para aquele símbolo - SYMBOL_VOLUME_LIMIT. Se não houver nenhuma limitação, então o volume de uma ordem pendente não pode exceder o volume máximo permitido, que pode ser recebido usando o volume SymbolInfoDouble().

double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_LIMIT);
if(max_volume==0) volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);

No entanto, esta abordagem não considera o volume das ordens pendentes atuais pelo símbolo especificado. Vamos escrever uma função que calcula este valor:

//+------------------------------------------------------------------+
//| Retorna o tamanho da posição de um símbolo especificado          |
//+------------------------------------------------------------------+
double PositionVolume(string symbol)
  {
//--- tentar selecionar uma posição de um símbolo
   bool selected=PositionSelect(symbol);
//--- a posição existe
   if(selected)
      //--- retorna o volume da posição
      return(PositionGetDouble(POSITION_VOLUME));
   else
     {
      //--- retorna zero se não tiver posição
      return(0);
     }
  }

Com a consideração do volume da posição aberta e do volume de ordens pendentes, a verificação final será da seguinte forma:

//+------------------------------------------------------------------+
//|  Retorna o volume máximo permitido de uma ordem de um símbolo    |
//+------------------------------------------------------------------+
double NewOrderAllowedVolume(string symbol)
  {
   double allowed_volume=0;
//--- obter a limitação do volume máximo de uma ordem
   double symbol_max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
//--- obter a limitação do volume de um símbolo
   double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_LIMIT);

//--- obter o volume de uma posição aberta de um símbolo
   double opened_volume=PositionVolume(symbol);
   if(opened_volume>=0)
     {
      //--- se nós já utilizamos o volume disponível
      if(max_volume-opened_volume<=0)
         return(0);

      //--- volume da posição aberta não ultrapassa o max_volume
      double orders_volume_on_symbol=PendingsVolume(symbol);
      allowed_volume=max_volume-opened_volume-orders_volume_on_symbol;
      if(allowed_volume>symbol_max_volume) allowed_volume=symbol_max_volume;
     }
   return(allowed_volume);
  }

Todo o código do Check_Order_And_Volume_Limits.mq5 Expert Advisor que contém as funções mencionadas nesta seção, é ligado ao artigo.

A exemplo de verificação usando o Check_Order_And_Volume_Limits Expert Advisor na conta de um participante do campeonato de negociação automatizado de 2010.

A exemplo de verificação usando o Check_Order_And_Volume_Limits Expert Advisor na conta de um participante do campeonato de negociação automatizado de 2010

Verificando a exatidão do volume

Uma parte significativa de qualquer negociação automática é a capacidade de escolher um volume correto para a realização de uma operação comercial. Aqui, nós não vamos falar sobre os sistemas de gestão de dinheiro e gestão de risco, mas sobre o volume a ser corrigido de acordo com as propriedades de um símbolo correspondente.

Identificador

Descrição

Tipo de Propriedade

SYMBOL_VOLUME_MIN

Volume mínimo para um negócio

duplo

SYMBOL_VOLUME_MAX

Volume máximo para um negócio

duplo

SYMBOL_VOLUME_STEP

Volume mínimo da etapa de mudança para a execução de negócios

duplo


Para realizar essa verificação, podemos escrever a função personalizada CheckVolumeValue():

//+------------------------------------------------------------------+
//|  Verificar a validade do volume de uma ordem                     |
//+------------------------------------------------------------------+
bool CheckVolumeValue(double volume,string &description)
  {
//--- Mínimo de volume permitido para uma negociação
   double min_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN);
   if(volume<min_volume)
     {
      description=StringFormat("Volume é menor que o mínimo permitido SYMBOL_VOLUME_MIN=%.2f",min_volume);
      return(false);
     }

//--- Máximo de volume permitido para uma negociação
   double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
   if(volume>max_volume)
     {
      description=StringFormat("Volume é maior que o máximo permitido SYMBOL_VOLUME_MAX=%.2f",max_volume);
      return(false);
     }

//--- retorna o valor da precisão do volume
   double volume_step=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP);

   int ratio=(int)MathRound(volume/volume_step);
   if(MathAbs(ratio*volume_step-volume)>0.0000001)
     {
      description=StringFormat("Volume não é múltiplo de SYMBOL_VOLUME_STEP=%.2f, o valor correto do volume mais próximo é %.2f",
                               volume_step,ratio*volume_step);
      return(false);
     }
   description="Valor correto do volume ";
   return(true);
  }

Você pode verificar o funcionamento desta função usando o script CheckVolumeValue.mq5 ligado ao artigo.

As mensagens do CheckVolumeValue.mq5 que verifica o volume a ser corrigido.

As mensagens do CheckVolumeValue.mq5 que verifica o volume a ser corrigido

Conclusão

O artigo descreve as verificações básicas para possíveis limitações no trabalho de um Expert Advisor, que podem ser enfrentadas ao criar seu próprio sistema de negociação automatizado. Estes exemplos não cobrem todas as condições possíveis que devem ser verificadas durante a operação de um Expert Advisor em uma conta comercial. Mas espero que esses exemplos ajudem os novatos a entenderem como implementar as verificações mais populares na linguagem MQL5.

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

Últimos Comentários | Ir para discussão (1)
[Excluído] | 23 dez 2013 em 12:28
Attached source code files and source code insets in HTML code are now completely translated into Portuguese for your convenience.
A ordem de destruição e criação do objeto em MQL5 A ordem de destruição e criação do objeto em MQL5
Cada objeto, quer seja um objeto personalizado, um array dinâmico ou um array de objetos, é criado e excluído no programa MQL5 desta forma em particular. Geralmente, alguns objetos são parte de outros objetos, e a ordem de exclusão do objeto na desinicialização se torna especialmente importante. Este artigo fornece alguns exemplos que cobrem os mecanismos de trabalho com objetos.
Aplicar um indicador a outro Aplicar um indicador a outro
Ao escrever um indicador que usa a forma curta da solicitação da função OnCalculate(), você pode deixar passar o fato de que um indicador pode ser calculado, não apenas pelos dados de preço, mas também pelos dados de algum outro indicador (não importando se for incorporado ou um personalizado). Você quer melhorar um indicador para sua aplicação correta a outros dados do indicador? Vamos analisar neste artigo todas as etapas necessárias para tal modificação.
Novas oportunidades com o MetaTrader 5 Novas oportunidades com o MetaTrader 5
O MetaTrader 4 ganhou sua popularidade com negociantes de todo o mundo e parecia que nada mais poderia ser desejado. Com sua alta velocidade de processamento, estabilidade, grande variedade de possibilidades para escrever indicadores, Expert Advisors e sistemas de negócio informativos, e a habilidade de escolher entre centenas de diferentes brokers, - o terminal se diferenciava-se muito do restante. Mas, o tempo não para e nos deparamos tendo que escolher entre o MetaTrade 4 ou MetaTrade 5. Neste artigo, descreveremos as principais diferenças do terminal da 5ª geração a nosso favor.
MQL5: Crie o seu próprio indicador MQL5: Crie o seu próprio indicador
O que é um indicador? É um conjunto de valores calculados que deseja-se que sejam exibidos em uma tela de forma conveniente. Os conjuntos de valores são representados em programas como arrays. Deste modo, a criação de um indicador significa escrever um algorítimo que manuseia algumas séries (séries de preço) e registra os resultados do manuseamento para outras séries (valores de indicador). Descrevendo a criação do Force Index, o autor mostra como escrever indicadores no MQL5.