
Error 146 ("Trade context busy") and How to Deal with It
1. What Is "Trade Context" in Terms of MetaTrader 4 Client Terminal
Extract from MetaEditor Reference:
Better to say, only one expert (script) can trade at a time. All other experts that try to start trading will be stopped by Error 146. This article will find solutions for this problem.
2. Function IsTradeAllowed()
The simplest way to find out whether the trade context is busy is to use the function named IsTradeAllowed().
Extract from MetaEditor Reference:
"bool IsTradeAllowed()
Returns true if the expert is allowed to trade and a thread for trading is not occupied, otherwise returns false.
This means that one can try to trade only if the IsTradeAllowed() function returns TRUE.
The check must be done just before a trade operation.
An example of wrong usage of the function:
int start() { // check whether the trade context is free if(!IsTradeAllowed()) { // if the IsTradeAllowed() function has returned FALSE, inform the user about it, Print("Trade context is busy! The expert cannot open position!"); // and terminate the expert operation. It will be restarted when the next tick // comes return(-1); } else { // if the IsTradeAllowed() function has returned TRUE, inform the user about it // and go on working Print("Trade context is free! We go on working..."); } // check whether the market should be entered now ... // calculate Stop Loss and Take Profit levels and the lot size ... // open a position if(OrderSend(...) < 0) Alert("Error opening position # ", GetLastError()); return(0); }
In this example, the trade context status is checked at the very
beginning of the start() function. It is a wrong idea: The trade
context can be occupied by another expert during the time taken by our
expert to calculate everything (the necessity to enter the market, Stop
Loss and Take Profit levels, lot size, etc.). In such case, the attempt
to open a position will not succeed.
An example of proper usage of the function:
int start() { // check whether the market should be entered now ... // calculate the Stop Loss and Take Profit levels, as well as the lot size ... // now let us check whether the trade context is free if(!IsTradeAllowed()) { Print("Trade context is busy! The expert cannot open position!"); return(-1); } else Print("Trade context is free! Trying to open position..."); // if checking succeeded, open a position if(OrderSend(...) < 0) Alert("Error opening position # ", GetLastError()); return(0); }
The trade context status is checked here immediately
before opening of position, and probability that another expert will
interpose between these two actions is much less. (It still exists,
though. This will be considered below.)
This method has two essential disadvantages:
- it is still probable that experts will check status simultaneously and, having received positive results, will try to trade at the same time
- if the checking fails, the expert will try to trade again only at the next tick; such delay is highly undesirable
The second problem can be solved rather easily: one has just to wait until the trade context becomes free. Then the expert will start trading immediately after the other expert has finished it.
This will probably look like this:
int start() { // check whether the market should be entered now ... // calculate the Take Profit and Stop Loss levels, and the lot size ... // check whether the trade context is free if(!IsTradeAllowed()) { Print("Trade context is busy! Wait until it is free..."); // infinite loop while(true) { // if the expert was stopped by the user, stop operation if(IsStopped()) { Print("The expert was stopped by the user!"); return(-1); } // if trade context has become free, terminate the loop and start trading if(IsTradeAllowed()) { Print("Trade context has become free!"); break; } // if no loop breaking condition has been met, "wait" for 0.1 sec // and restart checking Sleep(100); } } else Print("Trade context is free! Trying to open a position..."); // try to open a position if(OrderSend(...) < 0) Alert("Error opening position # ", GetLastError()); return(0); }In this current realization, we have some problem points again:
- since the IsTradeAllowed() function is responsible not only for the trade context status, but also for the enabling/disabling experts to trade, the expert can "hang" in an infinite loop; it will then stop only if it is removed from the chart manually
- if the expert waits until the trade context is free, for just some seconds, prices can change, and it will be impossible to trade using them - the data should be refreshed, the open, Take Profit and Stop Loss levels of the position to be opened should be recalculated
The corrected code will look like this:
// time (in seconds) whithin which the expert will wait until the trade // context is free (if it is busy) int MaxWaiting_sec = 30; int start() { // check whether the market should be entered now ... // calculate the Stop Loss and Take Profit levels and the lot size ... // check whether the trade context is free if(!IsTradeAllowed()) { int StartWaitingTime = GetTickCount(); Print("Trade context is busy! Wait until it is free..."); // infinite loop while(true) { // if the expert was terminated by the user, stop operation if(IsStopped()) { Print("The expert was stopped by the user!"); return(-1); } // if it is waited longer than it is specified in the variable named // MaxWaiting_sec, stop operation, as well if(GetTickCount() - StartWaitingTime > MaxWaiting_sec * 1000) { Print("The standby limit (" + MaxWaiting_sec + " sec) exceeded!"); return(-2); } // if the trade context has become free, if(IsTradeAllowed()) { Print("Trade context is free!"); // refresh the market information RefreshRates(); // recalculate the Stop Loss and Take Profit levels ... // leave the loop and start trading break; } // if no loop breaking condition has been met, "wait" for 0.1 // second and then restart checking Sleep(100); } } else Print("Trade context is free! Trying to open a position..."); // try to open a position if(OrderSend(...) < 0) Alert("Error opening position # ", GetLastError()); return(0); }In the above example, we added:
- refreshing of the market info (RefreshRates()) and consequent Stop Loss and Take Profit recalculation
- maximal time of waiting MaxWaiting_sec, after exceeding of which the expert will stop operation
As such, the above code can be used in your experts already.
The final touch: Let us put all concerning checking into a separate function. This will simplify its integration in experts and its usage.
///////////////////////////////////////////////////////////////////////////////// // int _IsTradeAllowed( int MaxWaiting_sec = 30 ) // // the function checks the trade context status. Return codes: // 1 - trade context is free, trade allowed // 0 - trade context was busy, but became free. Trade is allowed only after // the market info has been refreshed. // -1 - trade context is busy, waiting interrupted by the user (expert was removed from // the chart, terminal was shut down, the chart period and/or symbol was changed, etc.) // -2 - trade context is busy, the waiting limit is reached (MaxWaiting_sec). // Possibly, the expert is not allowed to trade (checkbox "Allow live trading" // in the expert settings). // // MaxWaiting_sec - time (in seconds) within which the function will wait // until the trade context is free (if it is busy). By default,30. ///////////////////////////////////////////////////////////////////////////////// int _IsTradeAllowed(int MaxWaiting_sec = 30) { // check whether the trade context is free if(!IsTradeAllowed()) { int StartWaitingTime = GetTickCount(); Print("Trade context is busy! Wait until it is free..."); // infinite loop while(true) { // if the expert was terminated by the user, stop operation if(IsStopped()) { Print("The expert was terminated by the user!"); return(-1); } // if the waiting time exceeds the time specified in the // MaxWaiting_sec variable, stop operation, as well if(GetTickCount() - StartWaitingTime > MaxWaiting_sec * 1000) { Print("The waiting limit exceeded (" + MaxWaiting_sec + " seconds)!"); return(-2); } // if the trade context has become free, if(IsTradeAllowed()) { Print("Trade context has become free!"); return(0); } // if no loop breaking condition has been met, "wait" for 0.1 // second and then restart checking Sleep(100); } } else { Print("Trade context is free!"); return(1); } }
A template for the expert that uses the function:
int start() { // check whether the market should be entered now ... // calculate the Stop Loss and Take Profit levels, and lot size ... // check whether trade context is free int TradeAllow = _IsTradeAllowed(); if(TradeAllow < 0) { return(-1); } if(TradeAllow == 0) { RefreshRates(); // recalculate the Take Profit and Stop Loss levels ... } // open a position if(OrderSend(...) < 0) Alert("Error opening position # ", GetLastError()); return(0); }
Let us draw some conclusions:
The IsTradeAllowed() function is easy to use and ideally suits for differentiation of accesses to trade context for two or three experts working simultaneously. Due to some disadvantages thereof, its use does not ensure from Error 146 when many experts work simultaneously. It can also cause "hanging" of the expert if the "Allow live trading" is disabled.
This is why we will consider an alternative solution for this problem -a global variable as a "semaphore".
3. Client Terminal Global Variables
First, the definition:
The client terminal global variables are variables accessible to all experts, scripts and indicators. This means a global variable created by one expert can be used in other experts (in our case, to distribute accesses).
There are several functions provided in MQL 4 to work with global variables:
- GlobalVariableCheck() - to check whether a global variable exists
- GlobalVariableDel() - to delete a global variable
- GlobalVariableGet() - to get the value of the global variable
- GlobalVariableSet() - to create or modify a global variable
- GlobalVariableSetOnCondition() - to change the value of the global variable specified by the user for another one. It differs from GlobalVariableSet() in that the new value will be set only at a certain previous value. It is this function, which is a key function to create a semaphore.
- GlobalVariablesDeleteAll() - to delete all global variables (I cannot imagine who may need this:)
Why should the GlobalVariableSetOnCondition() be used, but not the combination of functions GlobalVariableGet() and GlobalVariableSet()? For the same reasons: Some time can ellapse between uses of two functions. And another expert can interpose into the semaphore switching. But this is not what we need.
4. The Basic Concept of Semaphore
Expert that is going to trade should check the semaphore status. If the semaphore shows "red light" (global variable = 1), it means that another expert is trading, so it is necessary to wait. If it shows "green light" (global variable = 0), the trading can be started immediately (but not to forget to set the "red light" for other experts).
Thus, we have to create 2 functions: one for setting the "red light", another one for setting the "green light". On the face of it, the task is simple. But we will not jump to conclusions, but try to formulate the sequence of actions to be executed by each function (let us name them TradeIsBusy() and TradeIsNotBusy()) and finally realize them.
5. Function TradeIsBusy()
As has been said before, the main task of the
function will be to wait until the "green light" appears and to switch
on the "red light".
Besides, we have to check whether the global variable exists, and
create it, if not. This checking would be more reasonable (and more
efficient) to perform from the init() function
of the expert.
But then a probability could exist that the user would delete it and no
one of working expert would be able to trade. This is why we will place
it in the body of the created function.
All this should be accompanied by information displaying and processing
of errors that have occurred when working with the global variable. The
"hanging" should not be forgotten, as well: The function operation time
should be limited.
This is what we will finally get:
///////////////////////////////////////////////////////////////////////////////// // int TradeIsBusy( int MaxWaiting_sec = 30 ) // // The function replaces the TradeIsBusy value 0 with 1. // If TradeIsBusy = 1 at the moment of launch, the function waits until TradeIsBusy is 0, // and then replaces. // If there is no global variable TradeIsBusy, the function creates it. // Return codes: // 1 - successfully completed. The global variable TradeIsBusy was assigned with value 1 // -1 - TradeIsBusy = 1 at the moment of launch of the function, the waiting was interrupted by the user // (the expert was removed from the chart, the terminal was closed, the chart period and/or symbol // was changed, etc.) // -2 - TradeIsBusy = 1 at the moment of launch of the function, the waiting limit was exceeded // (MaxWaiting_sec) ///////////////////////////////////////////////////////////////////////////////// int TradeIsBusy( int MaxWaiting_sec = 30 ) { // at testing, there is no reason to divide the trade context - just terminate // the function if(IsTesting()) return(1); int _GetLastError = 0, StartWaitingTime = GetTickCount(); //+------------------------------------------------------------------+ //| Check whether a global variable exists and, if not, create it | //+------------------------------------------------------------------+ while(true) { // if the expert was terminated by the user, stop operation if(IsStopped()) { Print("The expert was terminated by the user!"); return(-1); } // if the waiting time exceeds that specified in the variable // MaxWaiting_sec, stop operation, as well if(GetTickCount() - StartWaitingTime > MaxWaiting_sec * 1000) { Print("Waiting time (" + MaxWaiting_sec + " sec) exceeded!"); return(-2); } // check whether the global variable exists // if it does, leave the loop and go to the block of changing // TradeIsBusy value if(GlobalVariableCheck( "TradeIsBusy" )) break; else // if the GlobalVariableCheck returns FALSE, it means that it does not exist or // an error has occurred during checking { _GetLastError = GetLastError(); // if it is still an error, display information, wait for 0.1 second, and // restart checking if(_GetLastError != 0) { Print("TradeIsBusy()-GlobalVariableCheck(\"TradeIsBusy\")-Error #", _GetLastError ); Sleep(100); continue; } } // if there is no error, it means that there is just no global variable, try to create // it // if the GlobalVariableSet > 0, it means that the global variable has been successfully created. // Leave the function if(GlobalVariableSet( "TradeIsBusy", 1.0 ) > 0 ) return(1); else // if the GlobalVariableSet has returned a value <= 0, it means that an error // occurred at creation of the variable { _GetLastError = GetLastError(); // display information, wait for 0.1 second, and try again if(_GetLastError != 0) { Print("TradeIsBusy()-GlobalVariableSet(\"TradeIsBusy\",0.0 )-Error #", _GetLastError ); Sleep(100); continue; } } } //+----------------------------------------------------------------------------------+ //| If the function execution has reached this point, it means that global variable | //| variable exists. | //| Wait until the TradeIsBusy becomes = 0 and change the value of TradeIsBusy for 1 | //+----------------------------------------------------------------------------------+ while(true) { // if the expert was terminated by the user, stop operation if(IsStopped()) { Print("The expert was terminated by the user!"); return(-1); } // if the waiting time exceeds that specified in the variable // MaxWaiting_sec, stop operation, as well if(GetTickCount() - StartWaitingTime > MaxWaiting_sec * 1000) { Print("The waiting time (" + MaxWaiting_sec + " sec) exceeded!"); return(-2); } // try to change the value of the TradeIsBusy from 0 to 1 // if succeed, leave the function returning 1 ("successfully completed") if(GlobalVariableSetOnCondition( "TradeIsBusy", 1.0, 0.0 )) return(1); else // if not, 2 reasons for it are possible: TradeIsBusy = 1 (then one has to wait), or // an error occurred (this is what we will check) { _GetLastError = GetLastError(); // if it is still an error, display information and try again if(_GetLastError != 0) { Print("TradeIsBusy()-GlobalVariableSetOnCondition(\"TradeIsBusy\",1.0,0.0 )-Error #", _GetLastError ); continue; } } //if there is no error, it means that TradeIsBusy = 1 (another expert is trading), then display // information and wait... Comment("Wait until another expert finishes trading..."); Sleep(1000); Comment(""); } }
Well, everything seems to be clear here:
- checking for whether the global variable exists and, if not, creation of it
- attempt to change the value of the global variable from 0 to 1; it will trigger only if its value is = 0.
The maximum amount of seconds during which the function can work is MaxWaiting_sec. The function is no objection to deletion of the expert from the chart.
Information about all errors that occur is shown in the log.
6. Function TradeIsNotBusy()
The TradeIsNotBusy function solves the inverse problem: It switches the "green light" on.
It is not limited by the operation time and cannot be terminated by user. Motivation is rather simple: If the "green light" is off, no expert will be able to trade.
It does not naturally have any return codes: The result can be only a successful completion.
This is how it looks:
///////////////////////////////////////////////////////////////////////////////// // void TradeIsNotBusy() // // The function sets the value of the global variable TradeIsBusy = 0. // If the TradeIsBusy does not exist, the function creates it. ///////////////////////////////////////////////////////////////////////////////// void TradeIsNotBusy() { int _GetLastError; // at testing, there is no sense to divide the trade context - just terminate // the function if(IsTesting()) { return(0); } while(true) { // if the expert was terminated by the user, stop working if(IsStopped()) { Print("The expert was terminated by the user!"); return(-1); } // try to set the global variable value = 0 (or create the global // variable) // if the GlobalVariableSet returns a value > 0, it means that everything // has succeeded. Leave the function if(GlobalVariableSet( "TradeIsBusy", 0.0 ) > 0) return(1); else // if the GlobalVariableSet returns a value <= 0, this means that an error has occurred. // Display information, wait, and try again { _GetLastError = GetLastError(); if(_GetLastError != 0 ) Print("TradeIsNotBusy()-GlobalVariableSet(\"TradeIsBusy\",0.0)-Error #", _GetLastError ); } Sleep(100); } }
7. Integration into Experts and Use
Now we have 3 functions to distribute access to the trading flow. To simplify their integration into experts, we can create the TradeContext.mq4 file and enable it using the #include directive (file attached).
Here is the template of the expert that uses functions TradeIsBusy() and TradeIsNotBusy():
#include <TradeContext.mq4> int start() { // check whether the market should be entered now ... // calculate the StopLoss and TakeProfit levels, and the lot size ... // wait until the trade context is free and then occupy it (if an error occurs, // leave it) if(TradeIsBusy() < 0) return(-1); // refresh the market info RefreshRates(); // recalculate the levels of StopLoss and TakeProfit ... // open a position if(OrderSend(...) < 0) { Alert("Error opening position # ", GetLastError()); } // set the trade context free TradeIsNotBusy(); return(0); }
In the use of functions TradeIsBusy() and TradeIsNotBusy(), only one problem can occur: If the expert is removed from the chart after the trade context has become busy, the variable TradeIsBusy will remain equal to 1. Other experts will not be able to trade after that.
The problem can be solved easily: The expert should not be removed from the chart when it is trading ;)
It is also possible that the variable TradeIsBusy is not zeroized at disorderly close-down of the terminal. In this case, the TradeIsNotBusy() function from the expert's init() function can be used.
And, of course, the value of
the variable can be changed manually at any time: F3 button in the
terminal (it is an undocumented possibility to disable all experts to
trade).
komposter (komposterius@mail.ru), 2006.04.11
Translated from Russian by MetaQuotes Ltd.
Original article: https://www.mql5.com/ru/articles/1412




- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
Hey,
Iam try ing to use the 2 functions. But I don't get it to work
This is my test:
The Print function returns: 1
But the Global Variable table returns: 0
Do I do something wrong?
Hey,
Iam try ing to use the 2 functions. But I don't get it to work
This is my test:
The Print function returns: 1
But the Global Variable table returns: 0
Do I do something wrong?
Here is explanation.
But you don't need to use these functions. There are 8 trade contexts in MT4 several years already.
Hey Andrey,
thanks for reply. So you mean using
is enough?
What are the "8" contexts?
Hey Andrey,
thanks for reply. So you mean using
is enough?
What are the "8" contexts?
Terminal have 8 trade contexts now, so it can send as much as 8 trade requests simulateously.
If you use less then 8 EAs at the same time, you could even not to check IsTradeContextBusy(). Otherwise, just check it and have a little sleep in case it returns false ;)
Terminal have 8 trade contexts now, so it can send as much as 8 trade requests simulateously.
If you use less then 8 EAs at the same time, you could even not to check IsTradeContextBusy(). Otherwise, just check it and have a little sleep in case it returns false ;)