English Русский 中文 Español Deutsch 日本語
Dormir ou não dormir?

Dormir ou não dormir?

MetaTrader 4Exemplos | 8 fevereiro 2016, 13:17
1 768 0
Sergey Gridnev
Sergey Gridnev

Durante suas operações, um Expert Advisor às vezes produz situações nas quais deve fazer pausas entre as operações. Isso pode ser causado pela necessidade de alcançar a exigência de manter um certo intervalo entre as solicitações repetidas para o servidor de negociação (no caso de erros de execução) e pela espera por um certo evento (por exemplo, para reconectar o servidor, para contexto de negociação livre etc.).

Dormir() ou não dormir()?

Para realizar pausas, o MQL4 há uma função chamada Sleep() que toma como parâmetro o valor do intervalo de tempo expresso na quantidade de milissegundos. A função Sleep() interrompe a execução do código do programa e permite sua continuação somente após que dado intervalo de tempo tenha passado.

Na minha opinião, o uso dessa função tem duas desvantagens. Primeiro, o tempo de máquina e usado de forma pouco prática: durante a pausa nas ações de um tipo, o programa pode executar as ações de outro tipo independente do anterior (por exemplo, durante uma pausa nas negociações, o programa pode executar alguns cálculos, monitorar os ticks de chegada etc.) Segundo, que é mais essencial, a função Sleep() não pode ser chamada a partir dos indicadores personalizados (consulte a Documentação) Entretanto, uma linguagem de programação deve ser usada para programar!

Vamos considerar como uma pausa de dez segundos é feita em um programa MQL4. Um exemplo usando a função Sleep() é dada abaixo:

if ( /* condition that requires to hold a pause */ )
   Sleep(10000); // sleep for 10 seconds

// program block to be executed upon the expiry of the pause
// ...

Como alternativa, vamos considerar um código de programa usando uma variável adicional. No caso de você precisar fazer uma pausa antes de executar uma ação, essa pausa deve ser inicializada pelo valor do tempo local de seu fim. Ao comparar o valor do tempo local com o valor dessa variável, é possível estabelecer o fato do fim da pausa. Para aproveitar as vantagens de usar essa alternativa de abordagem, você deve organizar para o período de espera pelo fim da pausa uma execução cíclica do código do programa para o qual não é preciso fazer uma pausa. É possível fazer isso usando um ciclo (por exemplo while) e pela realização correspondente da função start() que pode ser chamada pelos ciclos de acordo com o ciclo de chegada de tick. A alternativa anterior é adequada para os scripts personalizados, a última é para EAs e indicadores. Ambas são dadas abaixo.

Alternativa 1 (usando o ciclo "while").

int _time_waiting=0;
// ...
if ( ... ) // condition that requires to hold a pause
   _time_waiting = TimeLocal() + 10; // the pause ends in 10 seconds after the current local time
while ( TimeLocal() < _time_waiting )
{ // program block to be executed cyclically while waiting for the end of the pause
   // ...
}
// program block to be executed after the end of the pause
// ...

Alternativa 2 (usando o ciclo das chamadas de função start()).


static int _time_waiting=0;
// ...
if ( ... ) // condition that requires to hold a pause
   _time_waiting = TimeLocal() + 10; // the pause ends in 10 seconds after the current local time
if ( TimeLocal() >= _time_waiting )
{ // program block to be executed after the end of the pause
   // ...
}
// program block to be executed at every tick, not related to waiting for the end of the pause
// ...

A principal diferença entre as alternativas representadas é que a alternativa 1 garante a execução do bloco de programa parado para o período da pausa, enquanto a alternativa 2 não. Isso está relacionado ao fato de que o fluxo de tick pode ser interrompido por alguns motivos sem reiniciar. Além disso, na alternativa 2, a variável _time_waiting é descrita como static, o que representa seu valor entre as chamadas da função start(), o que não é necessário na alternativa 1.

Alguma redundância de código nas alternativas, em comparação à realização da pausa através da chamada de função Sleep(), é um pagamento por se livrar do tempo de inatividade. Entretanto, nenhum tempo de inatividade gera o problema dos usos repetidos da variável _time_waiting no código do programa, porque você não pode inicializá-lo com um novo valor até que a pausa precedente seja expirada. Esse problema pode ser resolvido de pelo menos duas maneiras, a escolha de uma ou de outra alternativa dependendo do estilo e das preferências do programador:

1) você pode usar sua própria variável para cada grupo de condições para armazenar o tempo expirado da pausa correspondente; ou

2) você pode descrever _time_waiting como uma série.

Acredito que seja razoável criar uma pequena biblioteca com a realização das funções de temporizador. Esse temporizador deve conter uma quantidade suficientes de variáveis de contador e ter as funções de inicialização, adicionando e excluindo os extratos controlados. Além disso, é possível realizar a contagem regressiva (temporizador de espera) e a contagem progressiva (cronômetro). Um exemplo de como realizar tal biblioteca está anexado a esse artigo (o artigo chamado ExLib_Timer.mq4 que contém o texto fonte). Um arquivo de cabeçalho contendo os protótipos das funções realizadas é dado abaixo:

#import "ExLib_Timer.ex4"
//
// Note.
// The counter identifier <CounterID> can take any values except "0",
// since "0" is reserved for the designation of nonactivated counters
// in a general array.
//
void timer_Init();
// start initialization
//
int timer_NumberTotal();
// request for the total amount of timer counters
// Return:
//    total amount of counters
//
int timer_NumberUsed();
// request for the amount of activated counters
// Return:
//    amount of activated counters
//
int timer_NumberFree();
// request for the amount of nonactivated (free) counters
// Return:
//    amount of free counters
//
void timer_ResetAll();
// resetting (zeroing) all counters
//
bool timer_Reset(int CounterID);
// resetting (zeroing) a counter by ID
// Parameters:
//    <CounterID> - counter identifier
// Return:
//    true  - resetted
//    false - no counter with such ID is found
//
void timer_DeleteAll();
// deletion of all counters
//
bool timer_Delete(int CounterID);
// deleting a counter by ID
// Parameters:
//    <CounterID> - counter identifier
// Return:
//    true  - deleted
//    false - no counter with such ID is found
//

bool timer_StartWaitable(int CounterID, int timeslice);
// starting a counter of the "wait timer" type
// Parameters:
//    <CounterID> - counter identifier (if it is not available, a counter is added)
//    <timeslice> - wait period (seconds)
// Return:
//    true  - started
//    false - no free counters
//
bool timer_StartStopwatch(int CounterID);
// starting a counter of the "stopwatch" type
// Parameters:
//    <CounterID> - counter identifier (if it is not available, a counter is added)
// Return:
//    true  - started
//    false - no free counters
//
int timer_GetCounter(int CounterID);
// request for the indications of the counter with ID <CounterID>
// Return:
//    for a counter of the "stopwatch" type, it is the amount of seconds elapsed since the start
//    for a counter of the "wait timer" type, it is the amount of seconds left till the end of wait period
// Note:
//    in case of no counter with ID <CounterID>, -1 is returned
//
int timer_GetType(int CounterID);
// request for a counter with ID <CounterID>
// Parameters:
//    <CounterID> - counter identifier
// Return:
//     1 - counter of the "stopwatch" type
//    -1 - counter of the "wait timer" type
//     0 - no counter with such ID is found
//
int timer_GetCounterIDbyPOS(int CounterPOS);
// request for a counter ID by its position among the activated ones
// Parameters:
//    <CounterPOS> - the number of the counter position among the activated ones
// Return:
//    counter identifier or "0" if a nonexisting position is specified
// Note:
//    <CounterPOS> can take the values ranging from 0 up to the amount of the activated counters,
//    returned by function timer_NumberUsed(). Otherwise, it returns 0
//
#import

As diferenças entre o uso da chamada de função Sleep() e a alternativa de realização de uma pausa fazendo as entradas em um log é demonstrada claramente por um pequeno Expert Advisor cujo texto é dado abaixo: A realização de pausa alternativa é definida pela inserção do parâmetro de Use_Sleep - "true" para usar Sleep() ou "false" para recusar o uso de Sleep().

#include "include/ExLib_Timer.mqh"
// --
//---- input parameters
extern bool Use_Sleep = false;
// =true  - using function "Sleep()"
// =false - using a timer
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
{
   timer_Init();
   if ( Use_Sleep )
      Print("init(). * Using function Sleep() *");
   else
      Print("init(). * Using a timer *");
   timer_StartWaitable(101, 10);
   timer_StartStopwatch(102);
   return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
{
   timer_DeleteAll();
   Comment("");
   return(0);
}
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
   Comment("Waitable:",timer_GetCounter(101)," / Stopwatch:",timer_GetCounter(102));
   Print("start() - initial block -");
// --
   if ( Use_Sleep )
   {
      //  - using function "Sleep()" -
      Sleep( 10000 ); // sleep for 10 seconds
      // program block to be executed after the pause ends
      Print("start() - block to be executed after the pause -");
   }
   else
   {
      //  - using a timer -
      if ( timer_GetType(101) == 0 )
         timer_StartWaitable(101, 10); // sleep for 10 seconds
         
      if ( timer_GetCounter(101) == 0 )
      {
         // program block to be executed after the pause ends
         timer_Delete(101);
         Print("start() - block to be executed after the pause -");
      }
   }
// --
   Print("start() - end block -");
   return(0);
}

Além do EA dado acima, há mais duas demonstrações de EA anexadas a esse artigo:
Ex_Timer_OrderLimits_TrailByTime.mq4 demonstra como realizar o rastreamento de SL e TP pelo tempo, e
Ex_Timer_OrderSend_wMinTimeLimit.mq4 demonstra como colocar a ordem de forma não mais frequente que uma vez dentro do conjunto de período definido no gráfico atual.

Desvantagens menores ou "Um pequeno porém"?

Infelizmente, a dada biblioteca não pode substituir completamente Sleep(). Há dois aspectos negativos aqui que devem ser destacados ao leitor.

Primeiro, ao usar Sleep(), a execução do programa continua imediatamente após a pausa terminar. No caso do uso de um temporizador, ele só continua quando o primeiro tick chega depois da pausa. Isso pode fazer com que o bloco atrasado seja executado muito tarde, ou, como foi mencionado acima, nem ser executado (por exemplo, no caso de um erro crítico no canal do link).

Segundo, a função Sleep() permite que você defina uma pausa com a etapa de 0,1 s, enquanto o temporizador faz apenas 1 s.

Conclusões

Como acontece com frequência, as vantagens da realização da pausa alternativa descrita acima quanto ao uso de Sleep() não são infalíveis, há alguns pontos bons. Tudo tem seus pontos fortes e fracos, seu significado dependendo da finalidade buscada. Dormir() ou não dormir(), o que sacrificar e o que preferir - tudo isso não deve ser decidido de maneira geral, mas dentro da estrutura do projeto a ser realizado.

Anexos:

Biblioteca da função:

  • ExLib_Timer.mqh - arquivo de cabeçalho;
  • ExLib_Timer.mq4 -texto fonte.

Exemplos de uso:

  • Ex_Timer_SleepOrNot.mq4 - um Expert Advisor que claramente demonstra as diferenças entre as alternativas da realização de pausa;
  • Ex_Timer_OrderLimits_TrailByTime.mq4 - um EA que demonstra o rastreamento de SL e TP pelo tempo;
  • Ex_Timer_OrderSend_wMinTimeLimit.mq4 - um EA que demonstra o posicionamento de ordens com frequência não maior que uma vez dentro do período definido no gráfico atual.

Importante! Os EAs de "Ex_Timer_OrderLimits_TrailByTime" e "Ex_Timer_OrderSend_wMinTimeLimit" são considerados para serem usados somente em contas de demonstração!


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

Pasta do programa do terminal do cliente MetaTrader 4 Pasta do programa do terminal do cliente MetaTrader 4
O artigo descreve os conteúdos da pasta do programa do terminal do cliente MetaTrader 4. Ele será útil para aqueles que já começaram a compreender os detalhes da operação do terminal do cliente.
Teste visual da rentabilidade de indicadores e alertas Teste visual da rentabilidade de indicadores e alertas
Normalmente, decide-se qual indicador de alerta de negociação ou apenas quais métodos do seu cálculo usar ao se testar EAs usando esses alertas. No entanto, não é sempre possível/necessário/razoável escrever um EA para cada indicador. Você pode calcular rapidamente a rentabilidade de negociação de alertas a partir de outros indicadores, usando um indicador especial que coleta seus alertas sozinho e desenha uma figura de negociação com ela. Isso pode ajudar a fazer uma estimativa visual dos resultados obtidos e escolher rapidamente os parâmetros mais adequados.
Receitas para redes neurais Receitas para redes neurais
O artigo destina-se a iniciantes na panificação de bolos "multicamadas".
A ociosidade é o estímulo do progresso. Marcação semiautomática de um modelo A ociosidade é o estímulo do progresso. Marcação semiautomática de um modelo
Entre as dezenas de exemplos de como trabalhar com gráficos, há um método de marcação manual de um modelo. Linhas de tendência, canais, níveis de suporte/resistência etc. são impostos em um gráfico. Com certeza, há alguns programas especiais para esse tipo de trabalho. Todo mundo decide sobre qual método usar. Neste artigo, ofereço uma opção para você considerar de métodos de marcação manual com a automatização subsequente de alguns elementos das ações de rotina repetidas.