Why Your EA Works on Demo But Not Live — 5 Fixes (MQL4)

You spent hours building your Expert Advisor. You backtested it. You ran it on demo for two weeks and it performed exactly the way you planned — clean entries, proper exits, consistent results.

Then you switched to a live account.

Wrong entries. Missed trades. Rejected orders. The EA that worked perfectly on demo is suddenly broken on live.


Here is the truth: your strategy is not broken. Your EA is not broken. The problem is something much more specific — and once you understand it, the fix takes less than five minutes inside MetaEditor.

This guide covers the five real reasons your EA behaves differently on demo versus live, and the exact code fix for each one.


Why Demo and Live Accounts Behave Differently

Before getting into the fixes, it helps to understand why this happens at all.

Demo accounts are simulations. When your EA sends an order on demo, MetaTrader fills it instantly at whatever price you requested, with a fixed spread and zero execution delay. There are no requotes, no slippage, and no broker involvement in the traditional sense.

Live accounts are real markets. When your EA sends the same order on a live account, it goes to your broker, who then tries to fill it at the best available price. Spreads are variable. Execution takes milliseconds — sometimes longer. Prices move between the moment your EA sends the order and the moment the broker fills it.

That gap between demo and live is where most EA problems live. Here are the five most common ones and how to fix each one inside MQL4.


Fix 1 — Set Your Slippage Tolerance Above Zero

This is the most common reason EAs fail silently on live accounts.

Inside your OrderSend() function, there is a slippage parameter. On most beginner EAs, this is set to zero. On demo, zero works fine because orders fill instantly at any price. On live, zero means you are telling your broker: fill this order at exactly this price or not at all.

If the price moves even slightly between your EA sending the order and the broker processing it, the order gets rejected. No error message in the chart. No alert. The EA simply moves on and the trade never opens.

The fix is straightforward. Open your EA in MetaEditor, use Ctrl+F to search for OrderSend, and find the slippage parameter. Change it from 0 to 3 or 5.

// Before — order gets rejected on live
OrderSend(Symbol(), OP_BUY, lots, Ask, 0, sl, tp);

// After — works on live accounts
OrderSend(Symbol(), OP_BUY, lots, Ask, 3, sl, tp);

A slippage value of 3 tells your broker: fill this order within 3 pips of my requested price. That small window is usually all it needs. Hit F7 to compile and confirm zero errors.


Fix 2 — Add a Stop Loss to Every Order

On demo, running without a stop loss feels harmless. You are not risking real money and the backtest results look fine.

On live, an EA with no stop loss is dangerous. If the StopLoss parameter in your OrderSend() call is set to zero, your live trade has no protection. One bad move against you and the trade keeps running with nothing to close it.

Calculate your stop loss relative to the entry price. For a buy order, your SL sits below Ask. For a sell order, it sits above Bid.

// Buy order with 50 pip stop loss and 100 pip take profit
double sl = Ask - (50 * Point);
double tp = Ask + (100 * Point);

OrderSend(Symbol(), OP_BUY, lots, Ask, 3, sl, tp);

After adding this, run a quick backtest in the Strategy Tester and confirm stop loss lines are appearing on each trade. If they are not visible, the value is not being passed correctly.


Fix 3 — Add a Spread Filter

Demo accounts typically show you a fixed, low spread. On live accounts, spreads are variable. During news events, market open, rollover periods, and low liquidity times, spreads can widen significantly.

If your EA enters a trade during a high-spread moment, the spread alone can push the price past your stop loss immediately after entry. The trade hits SL before it ever had a chance to move in your direction.

A spread filter is a single check at the top of your OnTick() function. If the current spread is wider than your threshold, the EA skips that tick entirely and waits for a better moment.

// Add this at the very top of OnTick() — before any trade logic
int maxSpread = 20; // in points — adjust for your currency pair
int currentSpread = (int)MarketInfo(Symbol(), MODE_SPREAD);

if(currentSpread > maxSpread) return;

// Your trade logic continues below

Adjust the maxSpread value based on your pair. Major pairs like EURUSD can use a tighter value. Exotic pairs with naturally wider spreads need a higher threshold.


Fix 4 — Prevent Duplicate Trades

On demo, your EA may appear to open one trade cleanly and manage it properly. On live, it can stack multiple trades on the same signal.

Here is why this happens. OnTick() fires every time the price changes — which on a live account can be dozens of times per second. If your EA has no check for existing open trades, it will attempt to open a new order on every single tick where your signal conditions are met. That means instead of one trade, you could end up with five, ten, or more stacked positions all opened within seconds.

The fix is a function that checks whether a trade is already open before placing a new one.

// Place this function above OnTick()
bool IsTradeOpen() {
   for(int i = OrdersTotal() - 1; i >= 0; i--) {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
         if(OrderMagicNumber() == MagicNumber) return(true);
   }
   return(false);
}

// Then at the top of your OnTick() logic
if(IsTradeOpen()) return;

The function loops through all open orders and checks if any of them belong to your EA using the magic number. If a trade is already open, the EA returns immediately without placing another. Only when no open trade exists does it continue to check entry conditions.


Fix 5 — Make Lot Size an Input Parameter

On demo you might run the EA at 1.0 lots because the risk feels abstract. The mistake happens when you copy that same EA to a live account and forget to change the lot size.

On a $500 live account, one standard lot trade can exceed your entire balance exposure on a single move. This is one of the most common ways beginner traders wipe their accounts on their first week of live trading.

The fix has two parts. First, expose lot size as an input parameter so you can change it directly from the MT4 chart without touching the code. Second, add a minimum balance check as a safety guard.

// At the top of your EA — declare lot size as an input
input double LotSize = 0.01; // defaults to micro lot for safety

// Optional balance guard inside OnTick() before any trade logic
if(AccountBalance() < 100) return; // requires minimum $100 balance

With LotSize declared as an input, it appears in the EA Properties panel when you attach the EA to a chart. You can change it without opening MetaEditor at all. The default value of 0.01 ensures that if anyone runs the EA without changing the input, the exposure is minimal.


The Underlying Pattern

All five of these fixes share the same root cause: demo accounts are forgiving environments that hide real-world friction. Live accounts expose every assumption your code makes about execution, spread, and market conditions.

This is not a flaw in MetaTrader or your broker. It is the gap between simulation and reality that every EA developer has to cross at some point.

The good news is that once you understand what demo is hiding, the fixes are mechanical. Change a parameter, add a filter, add a guard. None of these require restructuring your strategy or rewriting your EA from scratch.


Before You Go Live — A Quick Checklist

Run through these before switching any EA from demo to live:

  • Slippage parameter set to 3–5 (not zero)
  • Stop loss calculated and passed into every OrderSend() call
  • Spread filter added to the top of OnTick()
  • Duplicate trade prevention function in place
  • Lot size set as an input parameter, defaulting to 0.01
  • Magic number is unique — especially if running multiple EAs
  • AutoTrading button is green in MT4
  • EA shows a smiley face icon on the chart

If every item on that list is checked, your EA is in a much stronger position to perform on live the same way it performed on demo.


Summary

The demo-to-live gap is not a mystery. It is a set of specific, fixable technical differences between a simulated environment and a real one. Slippage, spread, execution delays, duplicate orders, and oversized lot sizes account for the vast majority of cases where a demo EA breaks on live.

Fix the code. Test again. Then go live with confidence.

Post a Comment

Share your thoughts ...

Previous Post Next Post