Problem Description
Solution
To ensure robust execution in MQL4, you should perform these checks sequentially. Since the trading context can be temporarily busy (e.g., another Expert Advisor is currently trading), it is best practice to implement a retry mechanism rather than immediately failing.
Here is the complete MQL4 code implementing a robust check function.
MQL4 Implementation
//+------------------------------------------------------------------+
//| CheckTradeStatus.mq4 |
//| Copyright 2023, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Example logic: Place a Buy order if conditions are met
// This is just a trigger example
if(OrdersTotal() == 0)
{
// 1. Perform the safety checks before attempting to trade
if(CheckTradingEnvironment())
{
// 2. If checks pass, refresh rates to ensure Ask/Bid are current
RefreshRates();
// 3. Place the order
int ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, 0, 0, "My Order", 0, 0, clrGreen);
if(ticket < 0)
{
Print("OrderSend failed with error #", GetLastError());
}
else
{
Print("Order placed successfully. Ticket: ", ticket);
}
}
}
}
//+------------------------------------------------------------------+
//| Function to check connection, permissions, and trade context |
//+------------------------------------------------------------------+
bool CheckTradingEnvironment()
{
// 1. Check connection to the server
if(!IsConnected())
{
Print("Error: Terminal is not connected to the server.");
return(false);
}
// 2. Check if trading is allowed (AutoTrading button + EA Permission)
// Note: IsTradeAllowed() checks both the global terminal setting and the specific EA setting.
if(!IsTradeAllowed())
{
Print("Error: Trading is not allowed. Check 'AutoTrading' button and EA properties.");
return(false);
}
// 3. Check if Trade Context is busy (with retry mechanism)
// The trade context might be busy if another EA is trading at the exact same moment.
int retryCount = 0;
int maxRetries = 10;
int sleepTime = 100; // Milliseconds
while(IsTradeContextBusy())
{
// If context is busy, wait and try again
Sleep(sleepTime);
retryCount++;
// If we exceeded max retries, abort
if(retryCount >= maxRetries)
{
Print("Error: Trade context is busy. Timeout after ", (maxRetries * sleepTime), "ms.");
return(false);
}
}
// If we waited for the context to clear, we must refresh market info
// because prices might have moved during the Sleep()
if(retryCount > 0)
{
RefreshRates();
}
// All checks passed
return(true);
}
Explanation of Functions Used
-
IsConnected():- Returns
trueif the client terminal is connected to the broker's server. If this returnsfalse,OrderSendwill inevitably fail.
- Returns
-
IsTradeAllowed():- This function performs a dual check:
- Is the "AutoTrading" button in the terminal toolbar enabled?
- Is the "Allow live trading" checkbox enabled in the specific Expert Advisor's properties (Common tab)?
- If either is disabled, it returns
false.
- This function performs a dual check:
-
IsTradeContextBusy():- In MetaTrader 4, only one thread is available for trading operations across the entire terminal. If you have multiple charts with different EAs, they cannot trade simultaneously.
- If EA #1 is sending an order, the context becomes "Busy". If EA #2 tries to trade at that exact millisecond,
OrderSendwould fail with error 146 (ERR_TRADE_CONTEXT_BUSY). - The Solution: The
whileloop in the code above waits (usingSleep) for the context to free up before proceeding.
-
RefreshRates():- If the code enters the
Sleep()loop because the context was busy, time passes. During that time, theAskandBidvariables stored in the cache might become outdated.RefreshRates()updates these variables to the absolute latest market prices.
- If the code enters the
Q&A
Q: Why do I need RefreshRates() after checking IsTradeContextBusy()?
A: MQL4 stores Ask and Bid prices when OnTick starts. If your code pauses (using Sleep) to wait for the trade context to clear, the market prices may change. RefreshRates() forces the EA to fetch the newest prices, preventing "Invalid Price" or "Requote" errors.
Q: Can IsTradeAllowed() return false even if AutoTrading is on?
A: Yes. It can return false if the specific EA does not have the "Allow live trading" permission checked in its properties, or if the terminal is logged in with an Investor (read-only) password.
Q: Does IsTradeContextBusy() exist in MQL5?
A: No. MQL5 is multi-threaded regarding trading operations, so multiple EAs can trade simultaneously without blocking each other. This check is specific to the architecture of MQL4.