Download MetaTrader 5

A Pause between Trades

8 August 2006, 09:54
Andrey Khatimlianskii
0
3 107


1. A Must or a Goodwill?

In the МetaТrader 3 Client Terminal, it was impossible to perform 2 trades at an interval under 10 seconds. Developing its МТ4, the MetaQuotes Software Corporation met the wishes of traders to remove this limitation. Indeed, there are situations where it is quite acceptable to perform a number of trades one after another (moving of StopLoss levels for several positions, removing of pending orders, etc.). But some traders took it in a wrong way and set about writing "killer" experts that could open positions one-by-one without a break. This resulted in blocked accounts or, at least, in the broker's unfriendly attitude.

This article is not for the above writers. It is for those who would like to make their trading comfortable for both themselves and their broker.


2. One Expert or Several Experts: What Is the Difference?

If you have only one terminal launched and only one expert working on it, it is simplicity itself to arrange a pause between trades: it is sufficient to create a global variable (a variable declared at global level, not to be confused with the terminal's Global Variables) and store the time for the last operation in it. And, of course, you should check before performing of each trade operation, whether the time elapsed after the last attempt to trade is sufficient.

This will look like this:

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);
 }

This example is suitable for one expert working on one terminal. If one or several more experts are launched simultaneously, they will not keep the 10-second pause. They will not just be aware of when another expert was trading. Every expert will have its own, local LastTradeTime variable. The way out of this is obvious: You should create a Global Variable and store the time of the trade in it. Here we mean the terminal's Global Variable, all experts will be able to access to it.


3. The _PauseBeforeTrade() Function

Since the code realizing the pause will be the same for all experts, it will be more reasonable to arrange it as a function. This will provide maximum usability and minimum volume of the expert code.

Prior to writing the code, let as define our task more concretely - this will save our time and efforts. Thus, this is what the function must do:

  • check whether a global variable has been created and, if not, create it. It would be more logical and saving to do it from the expert's init() function, but then the would be a probability that the user will delete it and all experts working at the time will stop keeping the pause between trades. So we will place it in the function to be created;
  • memorize the current time in the global variable in order for other experts to keep the pause;
  • check whether enough time has elapsed after the last trade. For usability, it is also necessary to add an external variable that would set the necessary duration of the pause. Its value can be changed for each expert separately;
  • display information about the process and about all the errors occurred during the work;
  • return different values depending on the performance results.

If the function detects that not enough time has elapsed after the last trade, it must wait. The Sleep() function will provide both waiting and checking of the IsStopped(). I.e., if you delete the expert from the chart during it "sleeps", it will not hang up or be stopped forcedly.

But, for more self-descriptiveness, let us (every second during the "sleep") display information about how long it still remains to wait.

This is what we have to get as a result:

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 occurs, 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 succeeds - 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. Integration into Experts and How to Use It

To check operability of the function, we created a diagnostic expert that had to trade keeping pauses between trades. The _PauseBeforeTrade() function was preliminarily placed into the PauseBeforeTrade.mq4 file included into the expert using the #include directive.

Attention! This expert is only dedicated for checking the function operability! It may not be used for trading!

#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);
 }

After that, one expert was attached to the EURUSD-M1 chart and another one, absolutely identical, to the GBPUSD-M1 chart. The result did not keep one waiting long: Both experts started trading keeping the prescribed 10-second pause between trades:





5. Possible Problems

When several experts work with one global variable, error can occur. To avoid this, we must delimit access to the variable. A working algorithm of such "delimitation" is described in details in the article named "Error 146 ("Trade context busy") and How to Deal with It". It is this algorithm that we will use.

The final version of the expert will look like this:

#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);
 }

Translated from Russian by MetaQuotes Software Corp.
Original article: https://www.mql5.com/ru/articles/1355

Attached files |
TradeContext.mq4 (9.27 KB)
Step on New Rails: Custom Indicators in MQL5 Step on New Rails: Custom Indicators in MQL5

I will not list all of the new possibilities and features of the new terminal and language. They are numerous, and some novelties are worth the discussion in a separate article. Also there is no code here, written with object-oriented programming, it is a too serous topic to be simply mentioned in a context as additional advantages for developers. In this article we will consider the indicators, their structure, drawing, types and their programming details, as compared to MQL4. I hope that this article will be useful both for beginners and experienced developers, maybe some of them will find something new.

Here Comes the New MetaTrader 5 and MQL5 Here Comes the New MetaTrader 5 and MQL5

This is just a brief review of MetaTrader 5. I can't describe all the system's new features for such a short time period - the testing started on 2009.09.09. This is a symbolical date, and I am sure it will be a lucky number. A few days have passed since I got the beta version of the MetaTrader 5 terminal and MQL5. I haven't managed to try all its features, but I am already impressed.

False trigger protection for Trading Robot False trigger protection for Trading Robot

Profitability of trading systems is defined not only by logic and precision of analyzing the financial instrument dynamics, but also by the quality of the performance algorithm of this logic. False trigger is typical for low quality performance of the main logic of a trading robot. Ways of solving the specified problem are considered in this article.

Using text files for storing input parameters of Expert Advisors, indicators and scripts Using text files for storing input parameters of Expert Advisors, indicators and scripts

The article describes the application of text files for storing dynamic objects, arrays and other variables used as properties of Expert Advisors, indicators and scripts. The files serve as a convenient addition to the functionality of standard tools offered by MQL languages.