# EA Parameter Optimization: A Practical Guide to Genetic Algorithms and Overfitting Avoidance
The Combinatorial Explosion Problem
When optimizing an EA with multiple parameters, brute-force testing becomes mathematically impossible. Consider a typical scenario: 20 binary switches and 20 input variables with 10 possible values each. The total combination count equals 20²⁰ ≈ 1.048 × 10²⁶ possibilities .
To put this number in perspective:
This is why brute-force enumeration fails. The solution is genetic algorithm (GA) optimization, which MT4 and MT5 already implement natively.
How Genetic Algorithm Optimization Works
GA simulates biological evolution to find near-optimal parameter sets without exhaustive search . The process follows five steps:
1. Initialization (Population Generation)
Instead of testing all combinations, GA randomly generates hundreds or thousands of parameter sets. Each set represents an "individual" in the population.
2. Fitness Evaluation (Performance Testing)
Each parameter set runs through your backtest data. The terminal calculates a fitness score based on your chosen criterion:
3. Selection (Survival of the Fittest)
Higher-fitness individuals have greater probability of being selected for reproduction. Lower-fitness individuals get淘汰.
4. Crossover (Reproduction)
Selected individuals exchange "genetic material" (parameter values) to create offspring. For example, the stop-loss setting from Parent A combines with the take-profit setting from Parent B.
5. Mutation (Random Variation)
Random parameters flip to new values with low probability, introducing diversity and preventing premature convergence to local optima.
This cycle repeats for dozens or hundreds of generations. Population average fitness improves over time, eventually converging on a high-performing parameter set .
Practical Optimization Strategy: The Layered Approach
Step 1: Fix What Shouldn't Be Optimized
Before running GA, identify parameters that represent strategy logic rather than tunable values.
For a grid trading EA:
This reduces your search space dramatically .
Step 2: Set Realistic Optimization Ranges
In MT4 Tester, configure your optimization boundaries :
| Parameter | Start | Step | Stop |
|-----------|-------|------|------|
| TakeProfit | 20 | 10 | 100 |
| StopLoss | 15 | 5 | 80 |
| LotSize | 0.01 | 0.01 | 0.10 |
Never include more than 5-7 parameters in a single optimization run.
Step 3: Use Forward Testing for Validation
GA finds parameters that excel on historical data. This may indicate overfitting, not robustness. The solution is out-of-sample validation:
1. Split your data: 70% in-sample (optimization), 30% out-of-sample (validation)
2. Run GA on in-sample data only
3. Test the "champion" parameters on out-of-sample data
4. If performance degrades significantly (>30% drop), your EA is overfit
Detecting Future Functions in Custom Indicators
Before converting any indicator into an EA for optimization, verify it contains no future functions — calculations that repaint historical signals based on current price .
Two Detection Methods:
Method 1 — Source Code Review (White Box)
Scan for loops that modify historical array values. Any assignment to `shift` values other than 0 indicates repainting.
Method 2 — Visual Observation (Black Box)
Load the indicator on a 1-minute chart. Watch for historical signal changes as new candles form. If past buy/sell arrows disappear or relocate, the indicator has future functions.
> Indicators with future functions produce excellent backtest results but fail in live trading. Never optimize an EA based on repainting indicators.
Loading Custom Indicators via iCustom()
Once you confirm an indicator has no future functions, integrate it into your EA using `iCustom()` :
```cpp
// Function signature
double iCustom(
string symbol, // Symbol (NULL = current)
int timeframe, // Period (0 = current chart)
string name, // Indicator filename (without .ex4)
... , // Indicator parameters (if any)
int mode, // Line index (0-based, from SetIndexBuffer)
int shift // Shift (0 = current candle, 1 = previous)
);
```
Practical Example: RSI Divergence Indicator
```cpp
// Assuming a custom divergence indicator:
// Line 0 = bullish divergence price level
// Line 1 = bearish divergence price level
// (EMPTY_VALUE indicates no signal)
double bullishDiv = iCustom(NULL, 0, "Divergence_Indicator", 0, 1);
double bearishDiv = iCustom(NULL, 0, "Divergence_Indicator", 1, 1);
if (bullishDiv != EMPTY_VALUE && OrdersTotal() == 0) {
// Bullish divergence detected on previous candle
OrderSend(Symbol(), OP_BUY, lotSize, Ask, 3, 0, 0, "Divergence Buy", magic);
}
```
Critical Consideration: Current vs. Previous Candle
Using `shift=0` (current candle) causes signals to appear/disappear as price moves, leading to phantom signals during backtesting. For robust optimization, use `shift=1` (completed candle) .
OrderSend() Fundamentals for EA Development
The `OrderSend()` function executes trade operations :
```cpp
int OrderSend(
string symbol, // Currency pair (Symbol() for current)
int cmd, // OP_BUY, OP_SELL, or pending orders
double volume, // Lot size
double price, // Open price (Ask for BUY, Bid for SELL)
int slippage, // Maximum slippage in points (typically 2-3)
double stoploss, // Stop loss price (0 if none)
double takeprofit, // Take profit price (0 if none)
string comment, // Order comment (e.g., "MyEA_v1")
int magic, // Unique EA identifier
datetime expiration, // Pending order expiry (0 for market orders)
color arrow_color // Arrow color on chart
);
```
Simple Market Order Example
```cpp
int start() {
double lotSize = 0.1;
int slippage = 3;
int magicNumber = 20240601;
// BUY order
int ticket = OrderSend(
Symbol(), // Current symbol
OP_BUY, // Buy order
lotSize, // 0.1 lots
Ask, // Current ask price
slippage, // 3 points slippage allowed
Bid - 50 * Point, // Stop loss 50 points below Bid
Bid + 100 * Point, // Take profit 100 points above Bid
"GA_Optimized_EA", // Comment
magicNumber, // Unique ID
0, // No expiration
clrGreen // Green arrow
);
if (ticket < 0) {
Print("Order failed. Error: ", GetLastError());
}
return 0;
}
```
The OnTester() Custom Optimization Criterion
For advanced optimization, implement `OnTester()` in your EA to define custom fitness metrics :
```cpp
double OnTester() {
// Retrieve backtest statistics
double profitFactor = TesterStatistics(STAT_PROFIT_FACTOR);
double maxDrawdown = TesterStatistics(STAT_EQUITY_DD_PERCENT);
double sharpeRatio = TesterStatistics(STAT_SHARPE_RATIO);
// Custom scoring: prioritize Sharpe ratio with drawdown penalty
double fitness = sharpeRatio * 100;
if (maxDrawdown > 20.0) fitness *= 0.5; // Penalty for excessive drawdown
if (profitFactor < 1.3) fitness *= 0.8; // Penalty for low profit factor
return fitness;
}
```
Optimization Pitfalls to Avoid
| Pitfall | Consequence | Prevention |
|---------|-------------|------------|
| Overfitting | Great backtest, live failure | Use out-of-sample validation |
| Curve-fitting | Performance collapses in new markets | Test across multiple market regimes |
| Ignoring transaction costs | Real trading loses despite backtest profit | Include spread + commission in backtest |
| Optimizing too many parameters | Spurious correlations found | Limit to 5-7 parameters per run |
| Survivorship bias | Backtest on dead pairs only | Include delisted symbols in testing |
Recommended Workflow for Robust EA Optimization
1. Write clean, modular EA code with external input parameters
2. Verify no future functions in any custom indicators used
3. Set realistic parameter ranges (don't let GA hunt extremes)
4. Run GA optimization with population size 500-1000, generations 50-100
5. Select top 10 parameter sets from GA results
6. Forward test each set on out-of-sample data (30% reserved)
7. Choose the set with best consistency, not highest backtest profit
8. Monte Carlo simulation to assess robustness under random trade order
---
References:
1. Eabang. "MT4MT5优化参数的遗传算法." August 2025.
2. MetaTrader 4 Help. "Setup — Expert Optimization."
3. FxGecko. "MT4编程:如何把指标应用到外汇EA上?" March 2023.
4. MQL4 Book. "Opening and Placing Orders — OrderSend()."
5. MQL4 Book. "Common Functions — Comment(), MessageBox(), PlaySound()."
6. MQL4 Book. "Program Execution — EA Lifecycle."