How to avoid over-optimization (curve fitting) when tuning an EA
Over-optimisation is the simplest way to build a strategy that looks brilliant in the Strategy Tester and fails the moment it meets live money. The optimiser does not know what a market is — it only knows how to minimise a number you gave it. Ask it to maximise profit on one year of one symbol and it will find the noise, every time. Below is a checklist for keeping it honest.
Count parameters against trades
A rough rule that has served me well:
- Under 100 trades in the test period — you have nothing. Any conclusion is noise.
- Aim for at least 10–20 trades per tunable parameter. Five parameters, 60 trades: you are already fitting.
- Prefer parameters that mean something economically. A 47-period MA has no story; a session filter or a volatility threshold does.
- If two parameters always move together in your optimal sets, you have one parameter pretending to be two.
Hold back data, always
Split the history before you start, not after you see the result.
- In-sample: optimise here. Out-of-sample: look once.
- If the out-of-sample curve collapses, do not "extend the sample slightly" and re-optimise. That is the same data again with extra steps.
- Walk-forward is better than a single split: rolling optimisation windows, each tested on the period immediately after it. You get a distribution of results, not one number.
- Keep a final period untouched entirely. Genuinely untouched.
Test the neighbourhood, not the peak
The single best indicator of curve fitting is a spiky optimisation surface.
- Take your best set and nudge each parameter by ±10–20%. If profit halves, you found a spike, not an edge.
- A robust parameter set sits on a plateau: neighbouring values all produce similar, positive results.
- Run the optimiser again on a shifted date range. If the optimal parameters move wildly, they are fitting the calendar, not the market.
Change the conditions
An edge should survive a bit of reality:
- Re-run with double your broker's typical spread and a few points of slippage.
- Repeat on a correlated symbol, or a different broker's data.
- Test on M1 modelling with real ticks if your live account will use real ticks.
- Check the trade distribution across hours, days and months. If 80% of profit comes from three weeks in 2020, say so out loud.
A 359-trade GBPUSD H1 run that ends at −$3,953 with a 46% win rate is not a winning EA — but it is an honest one, tested over a sample large enough to be believed: [see a real backtest](https://mql.ranartech.com/r/EBjGC6HYYxvE). That is the sort of result you want from your own testing before you start tuning. If your optimised EA cannot survive being looked at this plainly, the parameters are doing the work, not the logic.
Give the optimiser a criterion that punishes complexity
Do not let the tester rank candidates on raw profit. It rewards luck, drawdown and parameter count equally. MQL5 lets you define your own criterion in OnTester():
//--- custom optimisation criterion: return per unit of drawdown,
//--- penalised for complexity and for thin samples
double OnTester()
{
double profit = TesterStatistics(STAT_PROFIT);
double trades = TesterStatistics(STAT_TRADES);
double ddrel = TesterStatistics(STAT_EQUITY_DDREL_PERCENT);
// Reject anything we cannot judge: thin samples and zero drawdown
if(trades < 100.0 || ddrel <= 0.0)
return(0.0);
// Count your own tunable inputs and keep this honest
int params = 4;
// Each parameter beyond the first costs ~3% of the score
double complexity = MathPow(0.97, (double)MathMax(0, params - 1));
// Reward return per unit of drawdown, not raw profit
double score = (profit / ddrel) * complexity;
return(score);
}
This will not find your edge for you. It simply stops the optimiser from handing you a 12-parameter monster with 40 trades and a beautiful equity curve. Note that OnTester() is only meaningful in the tester, and params is a number you maintain by hand — no API will count them for you.
Red flags checklist
- Win rate above 90% with a small average win.
- Optimal values that land on round numbers (exactly 50, exactly 1.0) — suggests you searched until something looked nice.
- Profit concentrated in one symbol, one quarter, one news event.
- A parameter that improves results monotonically as you push it to the edge of the tested range. You have not found a boundary; you have found a trend in the sample.
- Any change to one input that flips the strategy from profitable to ruinous.
The honest test
Before you go live, write down what you expect: trades per month, average win, worst drawdown, maximum losing streak. Then run the EA on a demo account and compare. If the live distribution looks nothing like the backtest, no amount of re-optimisation will fix it — the original fit was the problem. Fewer parameters, more trades, held-back data, and a score that rewards consistency over peak profit will keep you out of most of the trouble.
Build & backtest your own EA free →