An Expert Advisor only ever sees the last price the terminal received. Most of the time that is fine. But when the feed freezes, the market closes for the night, or the symbol has no liquidity for a few minutes, your EA keeps reading the same old Bid and Ask and happily calculates signals and stop distances from a price that no longer exists.
This article shows a small, reusable check that tells your EA how old the current quote is and whether it is safe to act on.
Where the quote time comes from
SymbolInfoTick fills an MqlTick structure. Its time field is the server time of the last price update, and time_msc gives the same moment in milliseconds.
MqlTick tick;
if(!SymbolInfoTick(_Symbol, tick))
{
Print("SymbolInfoTick failed, error ", GetLastError());
return;
}
Print("Last quote at ", TimeToString(tick.time, TIME_DATE|TIME_SECONDS));
To know how old that quote is, compare it with the current trade server time. TimeTradeServer is estimated from your local clock and the known server offset, so it keeps moving even when no ticks arrive. That is exactly what we need.
A quote age function
// Returns the age of the last quote in seconds, or a negative value on failure.
long QuoteAgeSeconds(const string symbol)
{
MqlTick tick;
if(!SymbolInfoTick(symbol, tick))
return -1;
if(tick.time == 0)
return -1;
return (long)(TimeTradeServer() - tick.time);
}
Do not use TimeCurrent for this. TimeCurrent returns the time of the last tick received for any symbol in Market Watch, so on a frozen feed it can freeze too, and the age will always look close to zero.
Is the market actually open?
A quote that is two hours old on Saturday is normal. The same age on Tuesday afternoon is a problem. Before raising an alarm, check whether the symbol has a trade session right now.
bool InTradeSession(const string symbol)
{
datetime serverNow = TimeTradeServer();
MqlDateTime now;
TimeToStruct(serverNow, now);
datetime secondsToday = serverNow % 86400; // seconds since midnight, server time
datetime from, to;
for(uint i = 0; SymbolInfoSessionTrade(symbol, (ENUM_DAY_OF_WEEK)now.day_of_week, i, from, to); i++)
{
if(secondsToday >= from && secondsToday < to)
return true;
}
return false;
}
SymbolInfoSessionTrade returns the session start and end as seconds from the start of the day, and you loop over the session index until it returns false. Some symbols have two or three sessions per day with a break in between.
Putting it together
input int InpMaxQuoteAgeSec = 30; // treat quotes older than this as stale
bool QuoteIsFresh()
{
if(!InTradeSession(_Symbol))
return false; // market closed, do not trade
long age = QuoteAgeSeconds(_Symbol);
if(age < 0)
return false; // could not read the tick
if(age > InpMaxQuoteAgeSec)
{
static datetime lastWarn = 0;
if(TimeTradeServer() - lastWarn > 300)
{
PrintFormat("%s quote is %d seconds old, skipping signals", _Symbol, age);
lastWarn = TimeTradeServer();
}
return false;
}
return true;
}
void OnTick()
{
if(!QuoteIsFresh())
return;
// signal and order logic here
}
The warning is rate limited so a long freeze does not flood the Experts log.
Why OnTick is not enough on its own
If the feed is completely dead, OnTick will not fire at all, so the check above never runs. For EAs that manage open positions, also run the same check from OnTimer and log or alert when the quote has been stale for longer than your threshold during a trading session. That way you hear about a frozen feed while it is happening, not the next morning.
int OnInit()
{
EventSetTimer(10);
return INIT_SUCCEEDED;
}
void OnTimer()
{
if(InTradeSession(_Symbol) && QuoteAgeSeconds(_Symbol) > InpMaxQuoteAgeSec)
Print("Feed looks frozen on ", _Symbol);
}
void OnDeinit(const int reason)
{
EventKillTimer();
}
Picking the threshold
There is no single right number. Major forex pairs tick several times a second during the London and New York sessions, so 30 seconds without a quote is already suspicious. An exotic pair or a thin CFD during the Asian session can legitimately go a minute or more without a tick. Measure the normal gaps on your broker for the symbols you trade and set the threshold a few times above that.
Testing it
The Strategy Tester generates ticks continuously, so you will rarely see a stale quote there. To test the logic, run the EA on a demo chart for a symbol whose session ends while you watch, or temporarily lower InpMaxQuoteAgeSec to a few seconds on a quiet symbol and confirm the skip message appears.
A stale quote check is a few dozen lines of code, and it prevents a whole class of strange trades that are very hard to explain after the fact.








