Dormir ou não dormir?
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
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso