Why your EA works in the backtest but not live
When an EA’s live results drift away from its backtest, the cause is almost always one of nine things. Here is how to find yours by comparing the two trade by trade.
The backtest made money. The live account does not. Before changing a single parameter, find out which of the usual causes you are dealing with, because each one has a different fix and some of them mean the strategy itself is fine.
Start with a fair comparison
Run the Strategy Tester over exactly the period the EA has been live: same broker, same symbol, same inputs, same starting balance, real ticks. Then put the tester’s trade list next to the live trade list. The first trade that differs points to the cause:
- A trade the tester took and live did not: usually a rejected order, a filter, or a restart.
- The same trade at a worse price: costs and execution.
- A trade live took and the tester did not: usually look-ahead in the code, or different data.
The nine usual causes
1. The backtest was modelled optimistically
Open-prices or minute-bar modes, or a fixed spread, make tight stops and scalps look better than they are. Fix: retest on real ticks. If the edge disappears, it was never there. See how to backtest with real tick data.
2. Costs were missing or understated
Spread widening at the rollover and around news, commission, and swaps on held positions. Fix: make sure every cost appears in the backtest. A strategy whose average trade is close to its average cost will not survive live.
3. Execution: slippage, requotes and delay
Market orders fill at the next available price, and a slow connection makes that price worse. Fix: host the EA on a VPS close to the broker’s servers, add a slippage limit, and test with simulated delay.
4. The code looks into the future
Reading the current, unfinished bar as if it were closed, or using an indicator that repaints, produces signals in the backtest that could not have existed live. Fix: make decisions on closed bars, and check every indicator the EA reads for repainting.
5. The settings were fitted to the past
Heavily optimised parameters describe history, not the market. Fix: re-optimise with an out-of-sample period and fewer parameters, and prefer settings whose neighbours also work.
6. Broker differences rejected or resized orders
Minimum stop distances, filling modes, symbol suffixes, lot steps and digits differ between brokers and break order placement silently. Fix: read the Experts and Journal logs, and make the EA log every rejected order with its full context:
1// Log every rejected order with the context you need to diagnose it2if(!trade.Buy(lots, _Symbol, 0.0, sl, tp))3 PrintFormat("BUY failed: retcode=%u (%s) ask=%.5f sl=%.5f tp=%.5f spread=%d lots=%.2f",4 trade.ResultRetcode(), trade.ResultRetcodeDescription(),5 SymbolInfoDouble(_Symbol, SYMBOL_ASK), sl, tp,6 (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD), lots);7. Server time and sessions shifted
A session filter written for one broker’s server time trades the wrong hours at another, and daylight-saving changes move it twice a year. Fix: define sessions relative to a known timezone, and handle the clock changes.
8. Restarts made the EA forget
After a terminal or VPS restart, an EA that keeps its state only in memory can lose track of open trades, open duplicates, or reset its risk limits. Fix: rebuild state from the terminal’s positions on every start, and save anything the rules depend on.
9. The account is different
Netting instead of hedging, different leverage, or a different account currency changes how positions combine and how lots are sized. Fix: test on the same account type you trade, and make the EA detect the account mode.
When the strategy really is the problem
If the trade lists match and the difference is fully explained by costs, the code is doing its job: the edge is simply smaller than the original backtest suggested. The honest options are to trade less often and target larger moves, to reduce costs, or to stop. That is not a pleasant answer, but it is cheaper than finding out with more live losses.
Checklist
- Tester run over the live period, on the same broker and account type, with real ticks
- First differing trade identified
- Logs checked for rejected orders
- Costs, delay and swaps included in the test
- Closed-bar logic and non-repainting indicators confirmed
- State rebuilt after restarts