◆ New — Strategy Validator, Code Fixer & Prop Compliance Checker are live. Try one free →
Home / Learn / Why Your EA Isn't Taking Trades: A Diagnostic Checklist
MetaTrader

Why Your EA Isn't Taking Trades: A Diagnostic Checklist

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.

Why is my EA attached but not opening any trades?

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.

Is anything reaching the broker? Read the Experts and Journal tabs

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.

Symbol suffixes: the EA is asking for a symbol that doesn't exist

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.

Orders are being sent but rejected: volume, stops, and filling mode

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:

  • Invalid volume (MT5 retcode 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.
  • Invalid stops (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.
  • Invalid fill (MT5 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.
  • Market closed (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.

The platform is fine — the logic never fires

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:

  • Magic-number filters that miscount. Most EAs loop over open positions and count only those matching their magic number before deciding whether they may open another. If the magic input was changed between attachments, the EA can orphan its own old position — or, with a max-positions check written against the wrong filter, count someone else's trades as its own and conclude it is already fully invested. It then waits forever, correctly, by its own lights.
  • Time filters in the wrong clock. 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.
  • New-bar detection that never resets. A 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.
  • Spread or volatility filters that are permanently binding — especially after a broker change where digits or typical spread differ.

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.

Key takeaways

Educational only — not financial advice. Trading involves substantial risk of loss.

Catch the bug that compiles.Run auditGet Pro