A step-by-step diagnostic checklist for an Expert Advisor that is attached to a chart but never opens a trade — from the AutoTrading button and account-level permissions down to symbol suffixes, order-level rejections, and silent logic bugs, with MQL5 snippets that print exactly which layer is blocking you. This is educational material only, not financial advice: the goal here is an EA that executes what its code says, and an EA that trades is not the same thing as an EA that makes money — trading carries a real risk of loss.
An Expert Advisor that sits on a chart and never trades is almost always blocked at one of four layers: terminal-level permissions (the AutoTrading/Algo Trading button or platform options), account-level permissions (broker settings or an investor login), order-level rejections (the EA is sending orders and the server is refusing them), or logic that never fires (the entry condition is simply never true). The fastest path to a diagnosis is to work down those layers in order rather than guessing — each one has a visible symptom.
Start with the chart itself. In MT4, the top-right corner of the chart shows a smiley face when the EA is allowed to trade and a sad face (or an ✕) when it is not. In MT5, the equivalent is the small hat icon next to the EA name — solid blue means algo trading is permitted, greyed means it is blocked. If the face is sad or the hat is grey, no amount of code will trade; something above the EA is switched off.
The usual culprit is the big toolbar button: AutoTrading in MT4 (green play icon when on, red when off) or Algo Trading in MT5. It is a single global kill switch, it persists across restarts, and some VPS images ship with it off. One layer below that sits the per-EA setting: when you attach the EA, the Common tab has "Allow live trading" (MT4) or "Allow Algo Trading" (MT5), and unchecking it silently mutes that one instance. And in MT4, Tools → Options → Expert Advisors → Allow automated trading must also be enabled. All of these must be on simultaneously. Only once the icon is happy is it worth reading a single line of your own code.
Before changing code, establish whether the EA is attempting trades at all. The Experts tab (Toolbox/Terminal panel) shows everything your EA prints and every error MQL raises; the Journal tab shows what the terminal and trade server did. An EA that is trying and failing leaves fingerprints — OrderSend error 130, failed ... [Invalid stops], requote messages. An EA that is not trying leaves silence, which points you at permissions or logic instead.
You can make the permission layer print its own diagnosis. In MQL5, four properties cover the whole chain:
5
// Educational only — validate before trading; not financial advice.
void CheckTradingAllowed()
{
if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
Print("Blocked: Algo Trading button is off in the terminal.");
if(!MQLInfoInteger(MQL_TRADE_ALLOWED))
Print("Blocked: this EA instance — check the Common tab.");
if(!AccountInfoInteger(ACCOUNT_TRADE_ALLOWED))
Print("Blocked: trading disabled on this account (investor login?).");
if(!AccountInfoInteger(ACCOUNT_TRADE_EXPERT))
Print("Blocked: broker has disabled EA trading on this account.");
}Call it from OnInit() and OnTick() while debugging. Two of these catch problems people rarely suspect. ACCOUNT_TRADE_ALLOWED is false when you are logged in with the investor (read-only) password — a shockingly common cause on rented VPSes, because everything looks normal except that nothing can trade. ACCOUNT_TRADE_EXPERT is false when the broker has disabled algorithmic trading for the account type — some cent or bonus accounts do this, and only support can change it. Neither produces an obvious UI error; both produce an EA that waits forever.
Many brokers publish symbols with suffixes: EURUSD.pro, EURUSD.raw, EURUSDm, EURUSD.a. An EA with "EURUSD" hard-coded into OrderSend() or into an indicator call will fail on such an account — MT4 raises error 4106 (unknown symbol) or the order simply never validates, and in MT5 SymbolInfoDouble() calls quietly return zeros that poison every downstream calculation (lot sizing dividing by a zero tick value is a classic).
The robust fix is to never hard-code the symbol at all: use _Symbol, which always names the chart's actual symbol, suffix included. When an EA genuinely must reference other symbols — a correlation filter, a currency-strength basket — resolve the broker's real name at startup:
5
// Educational only — validate before trading; not financial advice.
string ResolveSymbol(string base)
{
if(SymbolSelect(base, true)) // exact match exists
return base;
for(int i = 0; i < SymbolsTotal(false); i++)
{
string s = SymbolName(i, false);
if(StringFind(s, base) == 0) // prefix match: "EURUSD.pro"
{
SymbolSelect(s, true);
return s;
}
}
Print("No symbol matching ", base, " on this account.");
return "";
}Note the SymbolSelect(..., true) calls: a symbol must be visible in Market Watch before you can reliably trade it or request its quotes, and selecting it programmatically saves a support ticket. Suffixes have a second-order effect worth checking too: some suffixed symbols carry different digits or point sizes than the EA's author assumed, which can turn a "max spread 20 points" filter into one that is never satisfied — an EA that is perfectly healthy and permanently filtered out.
If the Experts tab shows failed sends, the server's return code tells you exactly why — read it instead of re-attaching the EA and hoping. The frequent offenders:
10014, MT4 error 131): the lot size violates SYMBOL_VOLUME_MIN, SYMBOL_VOLUME_MAX, or is not a multiple of SYMBOL_VOLUME_STEP. Risk-based sizing code that computes 0.0273 lots and sends it raw fails on every attempt.10016 / MT4 130): the SL or TP is closer to price than SYMBOL_TRADE_STOPS_LEVEL allows, on the wrong side of price, or not normalized to the symbol's digits.10030): the order's filling mode (ORDER_FILLING_FOK, ORDER_FILLING_IOC, ORDER_FILLING_RETURN) is one the symbol does not support. This is the classic reason an EA that worked on one MT5 broker sends nothing but rejections on another.10018 / MT4 132), not enough money (10019 / MT4 134), and trading disabled for the symbol (10017 / MT4 133) — check the symbol's trade mode in its specification; some brokers set instruments to close-only around events.Defensive sizing looks like this:
5
// Educational only — validate before trading; not financial advice.
double NormalizeLots(double lots)
{
double minL = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxL = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
double v = MathFloor(lots / step) * step;
return MathMin(MathMax(v, minL), maxL);
}And in MT4 specifically, remember error 146 (trade context busy): two EAs trying to trade at once collide, and the losing one looks mysteriously inert unless it retries.
When permissions pass and no rejections appear, the EA is healthy and its entry condition is simply never true. These bugs are silent by nature, so the cure is instrumentation: Print() the inputs to your entry decision every bar and read what the EA actually sees, rather than what you assume it sees.
The recurring patterns:
TimeCurrent() is broker server time, not your local time and not GMT. A "trade only 08:00–17:00" filter written for London hours against a UTC+3 server is quietly shifted, and on some symbols that shift moves the window into the dead zone the filter was meant to avoid.static datetime lastBar guard that compares the wrong timeframe, or a once-per-bar flag that is set and never cleared, produces exactly one near-miss and then permanent silence.One honest closing note: the finish line of this checklist is an EA that executes its logic faithfully. That is a correctness property, not an edge. Educational only, not financial advice — an EA that trades flawlessly can still lose money, and trading always carries a real risk of loss.
Educational only — not financial advice. Trading involves substantial risk of loss.