After 14 years of reviewing and rescuing Expert Advisors — across 30+ code reviews over the past three years alone — the structural problems repeat with remarkable consistency. This is not about strategy logic. The strategies are often fine. The failures are in the plumbing: error handling, state management, environment assumptions, execution validation, and defensive guards.
Here are the five patterns I encounter most often, with MQL4 code examples showing both the problem and the fix.
1. No Error Handling on OrderSend
The EA sends a trade request and never checks what happened:
In the Strategy Tester, every order fills. In live trading, requotes, margin failures, and trade context busy conditions cause silent failures. The EA's internal state diverges from reality.
I fixed a grid EA where the counter incremented on every OrderSend() call regardless of the result. In live trading, requotes during volatile sessions created phantom grid levels. The average entry price in the EA's memory diverged from the account's actual average.
2. No State Persistence Across Restarts
Most EAs I rescue store all state in runtime variables:
Terminal restarts constantly — VPS reboots, MetaTrader updates, broker disconnects. Every restart fires OnDeinit() then OnInit() , and every static variable resets to its initial value.
A martingale EA I fixed tracked its multiplier this way. After a weekend restart during a drawdown, the multiplier reset to 1. The EA opened a base lot position while the losing chain was still open.
The global variable pool ( GlobalVariableSet , GlobalVariableGet ) also survives restarts and is simpler for single-value persistence.
3. Hardcoded Environment Assumptions
Point * 10 is correct for 5-digit forex pairs. It is wrong for gold, indices, and 4-digit brokers:
Every hardcoded value in the first block has broken an EA I have rescued. Every runtime query in the second block would have prevented it.
4. Ignoring Execution Feedback
Beyond OrderSend() , most EAs never check OrderModify() , OrderClose() , or OrderDelete() return values:
I fixed a trailing stop EA where OrderModify() was rejected every tick with error 130 (invalid stops) because the new SL violated MODE_STOPLEVEL . The EA logged "trailing active" while the stop loss had not moved in hours.
5. No Defensive Guards
The final pattern: no bounds checking, no zero-denominator guards, no validation of indicator return values.
I worked on an EA where this exact scenario produced an infinite lot size during a news spike. NormalizeDouble() silently converted infinity to a very large number. The broker rejected the order on lot limits — the only thing that prevented a catastrophic fill.
The Pattern
All five failures share the same root cause: the EA was tested only in the Strategy Tester — the environment where everything works. Orders fill instantly. Terminals never restart. Symbol properties match the developer's setup. History is complete.
Live trading is the environment where things fail. Production-ready code assumes that every trade request can be rejected, every stored value can be lost, and every assumption about the broker can be wrong.
Five questions to check any EA:
- Does it check return values on every OrderSend , OrderModify , and OrderClose ?
- Does it persist critical state and reconcile on startup?
- Does it query symbol properties at runtime?
- Does it validate execution feedback and log effective values?
- Does it guard against zero denominators and insufficient history?
If any answer is "no," the backtest results are fiction with a delayed fuse.


