Uma pausa entre operações
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
- 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