English Русский 中文 Español Deutsch 日本語
Uma pausa entre operações

Uma pausa entre operações

MetaTrader 4Exemplos | 18 fevereiro 2016, 09:18
1 859 0
Andrey Khatimlianskii
Andrey Khatimlianskii

1. Necessidade ou boa vontade?

No terminal do cliente MetaTrader 3 era impossível realizar 2 operações em um intervalo inferior a 10 segundos. Ao desenvolver o MT4, a MetaQuotes Software Corporation correspondeu às expectativas dos operadores, removendo esta limitação. De fato, há situações nas quais é bastante aceitável realizar várias operações de comércio uma após a outra (a movimentação de níveis de StopLoss para várias posições, a remoção de ordens pendentes, etc.). Mas alguns operadores interpretaram mal a situação, e resolveram escrever sistemas especializados "aniquiladores", capazes de abrir posições em sucessão sem intervalos. Isto resultou no bloqueio de contas ou, pelo menos, em atitudes pouco amigáveis por parte de operadores.

O artigo não é destinado a estes indivíduos. Ele é destinado àqueles que desejam tornar as operações confortáveis para si mesmos e para os seus corretores.


2. Um sistema especializado ou vários sistemas especializados: qual é a diferença?

Caso você possua apenas um terminal ativado e apenas um sistema especializado trabalhando nele, organizar uma pausa entre operações de comércio é extremamente simples: basta criar uma variável global (uma variável declarada a nível global, que não deve ser confundida com as variedades globais do terminal) e registrar nela o momento da última operação. E, é claro, antes de realizar qualquer operação de comércio você deve verificar se o tempo transcorrido desde a última tentativa foi suficiente.

Isso ocorrerá da seguinte forma:

datetime LastTradeTime = 0;
int start()
 {
  // check whether we should enter the market
  ...
  // calculate the levels of StopLoss and TakeProfit and the lot size
  ...
  // check whether sufficient time has elapsed after the last trade
  if(LocalTime() - LastTradeTime < 10)
   {
    Comment("Less than 10 seconds have elapsed after the last trade!",
            " The expert won't trade!"); 
    return(-1);
   }
 
  // open a position
  if(OrderSend(...) < 0)
   {
    Alert( "Error opening position #", GetLastError() );
    return(-2);
   }
    
  // memorize the time of the last trade
  LastTradeTime = LocalTime();
 
  return(0);
 }


Este exemplo é adequado para um sistema especializado trabalhando em um terminal. Caso um ou vários sistemas especializados sejam inicializados simultaneamente, eles não respeitarão a pausa de 10 segundos. Eles não estarão apenas cientes do momento em que outro sistema especializado estiver realizando uma transação. Cada sistema especializado terá a sua própria variável LastTradeTime local. A saída desta situação é óbvia. Você deve criar uma variável global e registrar o momento da transação nela. Aqui estamos falando da variável global do terminal, e todos os sistemas especializados terão acesso a ela.


3. A função _PauseBeforeTrade()

Dado que o código que realiza a pausa será o mesmo para todos os sistemas especializados, será mais razoável dispô-lo como uma função. Isto garantirá o máximo de usabilidade e o mínimo volume para o código do sistema especializado.

Antes de escrever o código, vamos definir a nossa tarefa de forma mais concreta. Isso economizará tempo e recursos. Desse modo, isso é o que a função deve realizar:

  • verificar se uma variável global foi criada e, em caso negativo, criá-la. Seria mais lógico e econômico fazer isso a partir da função init() do sistema especializado, mas neste caso seria provável que ele fosse deletado pelo usuário, e então todos os sistema especializados trabalhando simultaneamente iriam parar de respeitar a pausa entre as transações. Portanto nós o colocamos na função a ser criada.
  • memorizar o tempo atual na variável global para que os outros sistemas especializados respeitem a pausa;
  • verificar se tempo suficiente transcorreu após a última transação. Para fins de usabilidade, também é necessário adicionar uma variável externa que defina a duração necessária da pausa. O seu valor pode ser alterado com relação a cada um dos sistemas especializados, separadamente;
  • exibir informações a respeito do processo e de todos os erros que venham a ocorrer durante o trabalho;
  • devolver valores diferentes dependendo dos resultados de performance.

Caso a função detecte que não transcorreu tempo suficiente desde a última transação, ela deve esperar. A função Sleep() garantirá a espera e a verificação da função IsStopped(). Ou seja, caso você delete o sistema especializado do gráfico durante o seu "descanso", ele não desligará ou ser parado forçadamente.

Mas, para obter um caráter mais auto-descritivo, vamos exibir (a cada segundo durante o "descanso") informações sobre o tempo restante de espera.

Isto é o que devemos obter como resultado:

extern int PauseBeforeTrade = 10; // pause between trades (in seconds)
 
/////////////////////////////////////////////////////////////////////////////////
// int _PauseBeforeTrade()
//
// The function sets the local time value for the global variable LastTradeTime.
// If the local time value at the moment of launch is less than LastTradeTime + 
// PauseBeforeTrade value, the function will wait.
// If there is no global variable LastTradeTime at all, the function will create it.
// Return codes:
//  1 - successful completion
// -1 - the expert was interrupted by the user (the expert was deleted from the chart, 
//      the terminal was closed, the chart symbol or period was changed, etc.)
/////////////////////////////////////////////////////////////////////////////////
int _PauseBeforeTrade()
 {
  // there is no reason to keep the pause during testing - just terminate the function
  if(IsTesting()) 
      return(1); 
  int _GetLastError = 0;
  int _LastTradeTime, RealPauseBeforeTrade;
 
  //+------------------------------------------------------------------+
  //| Check whether the global variable exists and, if not, create it  |
  //+------------------------------------------------------------------+
  while(true)
   {
    // if the expert was interrupted by the user, stop working
    if(IsStopped()) 
     { 
      Print("The expert was stopped by the user!"); 
      return(-1); 
     }
    // check whether a global variable exists
    // if yes, exit this loop
    if(GlobalVariableCheck("LastTradeTime")) 
      break;
    else
     // if the GlobalVariableCheck returns FALSE, it means that either global variable does not exist, or 
     // an error occurred during checking
     {
      _GetLastError = GetLastError();
      // if it is still an error, display information, wait during 0.1 sec, and start to 
      // recheck
      if(_GetLastError != 0)
       {
        Print("_PauseBeforeTrade()-GlobalVariableCheck(\"LastTradeTime\")-Error #",
              _GetLastError );
        Sleep(100);
        continue;
       }
     }
    // if no error occirs, it just means that there is no global variable, try to create it
    // if GlobalVariableSet > 0, it means that the global variable has been successfully created. 
    // Exit the function
    if(GlobalVariableSet("LastTradeTime", LocalTime() ) > 0) 
      return(1);
    else
     // if GlobalVariableSet returns a value <= 0, it means that an error occurred during creation 
     // of the variable
     {
      _GetLastError = GetLastError();
      // display information, wait 0.1 sec, and restart the attempt 
      if(_GetLastError != 0)
       {
        Print("_PauseBeforeTrade()-GlobalVariableSet(\"LastTradeTime\", ", 
              LocalTime(), ") - Error #", _GetLastError );
        Sleep(100);
        continue;
       }
     }
   }
  //+--------------------------------------------------------------------------------+
  //| If the function performance has reached this point, it means that the global   |
  //| variable exists.                                                                    |
  //| Wait until LocalTime() becomes > LastTradeTime + PauseBeforeTrade               |
  //+--------------------------------------------------------------------------------+
  while(true)
   {
    // if the expert was stopped by the user, stop working
    if(IsStopped()) 
     { 
      Print("The expert was stopped by the user!"); 
      return(-1); 
     }
    // get the value of the global variable
    _LastTradeTime = GlobalVariableGet("LastTradeTime");
    // if an error occurs at this, display information, wait 0.1 sec, and try 
    // again
    _GetLastError = GetLastError();
    if(_GetLastError != 0)
     {
      Print("_PauseBeforeTrade()-GlobalVariableGet(\"LastTradeTime\")-Error #", 
            _GetLastError );
      continue;
     }
    // count how many seconds have been elapsed since the last trade
    RealPauseBeforeTrade = LocalTime() - _LastTradeTime;
    // if less than PauseBeforeTrade seconds have elapsed,
    if(RealPauseBeforeTrade < PauseBeforeTrade)
     {
      // display information, wait one second, and check again
      Comment("Pause between trades. Remaining time: ", 
               PauseBeforeTrade - RealPauseBeforeTrade, " sec" );
      Sleep(1000);
      continue;
     }
    // if the time elapsed exceeds PauseBeforeTrade seconds, stop the loop
    else
      break;
   }
  //+--------------------------------------------------------------------------------+
  //| If the function performance has reached this point, it means that the global   |
  //| variable exists and the local time exceeds LastTradeTime + PauseBeforeTrade    |
  //| Set the local time value for the global variable LastTradeTime                 |
  //+--------------------------------------------------------------------------------+
  while(true)
   {
    // if the expert was stopped by the user, stop working
    if(IsStopped()) 
     { 
      Print("The expert was stopped by the user!"); 
      return(-1);
     }

    // Set the local time value for the global variable LastTradeTime.
    // In case it cusseeds - exit
    if(GlobalVariableSet( "LastTradeTime", LocalTime() ) > 0) 
     { 
      Comment(""); 
      return(1); 
     }
    else
    // if the GlobalVariableSet returns a value <= 0, it means that an error occurred
     {
      _GetLastError = GetLastError();
      // display the information, wait 0.1 sec, and restart attempt
      if(_GetLastError != 0)
       {
        Print("_PauseBeforeTrade()-GlobalVariableSet(\"LastTradeTime\", ", 
              LocalTime(), " ) - Error #", _GetLastError );
        Sleep(100);
        continue;
       }
     }
   }
 }


4. Integração nos sistemas especializados e como usá-la

Para verificar a operabilidade da função, nós criamos um sistema especializado de diagnóstico que deveria realizar transações respeitando pausas entre cada transação. A função _PauseBeforeTrade() foi colocada de forma preliminar no arquivo PauseBeforeTrade.mq4 incluído no sistema especializado através da diretiva #include.

Atenção! Este sistema especializado é dedicado exclusivamente à verificação da operabilidade do sistema! Ele não pode ser utilizado para realizar transações!

#include <PauseBeforeTrade.mq4>
 
int ticket = 0;
int start()
 {
  // if there is no position opened by this expert
  if(ticket <= 0)
   {
    // keep a pause between trades, if an error has occurred, exit
    if(_PauseBeforeTrade() < 0) 
      return(-1);
    // update the market information
    RefreshRates();
 
    // and try to open a position
    ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 5, 0.0, 0.0, "PauseTest", 123, 0, 
                       Lime);
    if(ticket < 0)
      Alert("Error OrderSend № ", GetLastError());
   }
  // if there is a position opened by this expert
  else
   {
    // keep the pause between trades (if an error has occurred, exit)
    if(_PauseBeforeTrade() < 0)
      return(-1);
    // update the market information
    RefreshRates();


 
    // and try to close the position
    if (!OrderClose( ticket, 0.1, Bid, 5, Lime ))
      Alert("Error OrderClose № ", GetLastError());
    else
      ticket = 0;
   }
  return(0);
 }



Em seguida, um sistema especializado foi ligado ao gráfico EURUSD-M1, e outro, absolutamente idêntico, foi ligado ao gráfico GBPUSD-M1. Os resultados não demoraram a chegar: Ambos sistemas especializados começaram a realizar transações respeitando a pausa prescrita de 10 segundos entre cada transação:







5. Problemas possíveis

Quando vários sistemas especializados trabalham com uma variável global, podem ocorrer erros. Para evitar isso, nós devemos delimitar o acesso à variável. Um algoritmo de trabalho para uma "delimitação" do tipo é descrito em detalhes no artigo chamado "Erro 146 ("O contexto de negociações está ocupado") e como lidar com isso". Este é o algoritmo que iremos usar.

A versão final do sistema especializado terá a seguinte aparência:

#include <PauseBeforeTrade.mq4>
#include <TradeContext.mq4>
 
int ticket = 0;
int start()
 {
  // if there is no a position opened by this expert
  if(ticket <= 0)
   {
    // wait until the trade is not busy and occupy it (if an error has occurred, 
    // exit)
    if(TradeIsBusy() < 0)
      return(-1);
    // keep the pause between trades
    if(_PauseBeforeTrade() < 0)
     {
      // if an error has occurred, free the trade and exit
      TradeIsNotBusy();
      return(-1);
     }
    // update the market information
    RefreshRates();
 
    // and try to open a position
    ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 5, 0.0, 0.0, "PauseTest", 123, 0, 
                       Lime);
    if (ticket < 0)
      Alert("Error OrderSend № ", GetLastError());
    // free the trade
    TradeIsNotBusy();
   }
  // if there is a position opened by this expert
  else
   {
    // wait until the trade is not busy and occupy it (if an error has occurred, 
    // exit)
    if(TradeIsBusy() < 0)
      return(-1);
    // keep the pause between trades
    if(_PauseBeforeTrade() < 0)
     {
      // if an error occurs, free the trade and exit
      TradeIsNotBusy();
      return(-1);
     }
    // update the market information
    RefreshRates();
 
    // and try to close the position
    if(!OrderClose( ticket, 0.1, Bid, 5, Lime))
      Alert("Error OrderClose № ", GetLastError());
    else
      ticket = 0;
 
    // free the trade
    TradeIsNotBusy();
   }
  return(0);
 }

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

Arquivos anexados |
TradeContext.mq4 (9.27 KB)
MagicNumber: Identificador "mágico" do pedido MagicNumber: Identificador "mágico" do pedido
O artigo trata do problema relativo a transações livres de conflito de vários sistemas especializados no mesmo terminal do cliente MT4. Ele "ensina" o sistema especializado a gerenciar apenas os seus "próprios" pedidos sem modificar ou fechar as posições "alheias" (abertas manualmente ou por outros sistemas especializados). O artigo foi escrito para usuários que possuam habilidades básicas no trabalho com o terminal e em programação em MQL4.
Teoria de Mercado Teoria de Mercado
A lógica completa da teoria do mercado que cobre todos os tipos e variedades de mercados de bens e serviços, não estava disponível até agora aos mercados micro e macro, como o Forex. Este artigo aborda a essência de uma nova teoria do mercado com base na análise do lucro, revela padrões de mudança dos preços em andamento e o princípio da operação de um mecanismo a permitir que o preço encontre o seu valor ideal, através da formação de uma cadeia de preços virtuais que desenvolvem um controle sobre o preço real. Mecanismos de formação e de mudança das tendências do mercado também são identificados aqui.
Expert Advisor gráfico: AutoGraf Expert Advisor gráfico: AutoGraf
O artigo mostra a operacionalidade de gráficos na criação de uma interface conveniente para o gerenciamento de transações.
Ação de preço. Como automatizar a estratégia de negociação de padrão de engolfo Ação de preço. Como automatizar a estratégia de negociação de padrão de engolfo
Esse artigo descreve um processo de criação de um Expert Advisor para MetaTrader 4 baseado no padrão de engolfo, assim como no princípio de reconhecimento de padrão, nas regras de definição de ordens pendentes e ordens de parada. Os resultados de teste e otimização são fornecidos para sua informação.