Summary: Practical GA implementation for MT4 Expert Advisor optimization. Covers encoding, selection, crossover, mutation, and fitness landscape analysis. Code included.




Grid search in MT4 optimization wastes time. Genetic algorithms (GA) converge faster for high-dimensional parameter spaces. This guide implements a GA framework directly within MQL4 for EA parameter optimization, bypassing the built-in optimizer's limitations.

1. Problem Formulation
We optimize a vector θ = (p1, p2, ..., pn) where each pi ∈ [min_i, max_i]. Fitness function F(θ) = profit factor * sqrt(trades count) - max drawdown percentage.

2. Population Encoding
Binary encoding for each parameter. For parameter i with range [Li, Ui] and precision 10^-d, bits needed: b_i = ceil(log2((Ui - Li) * 10^d + 1)).

Decoding formula:
```
value = Li + (Ui - Li) * (decimal_value / (2^b_i - 1))
```

3. GA Operators Implementation in MQL4
Chromosome structure:
```cpp
struct Chromosome {
double genes[10]; // decoded parameter values
double fitness;
int bits[10][16]; // binary representation (max 16 bits per param)
};
```
Population initialization with uniform random:
```cpp
void InitPopulation(Chromosome &pop[], int size, int nParams) {
for(int i = 0; i < size; i++) {
for(int p = 0; p < nParams; p++) {
pop[i].genes[p] = minParam[p] + (maxParam[p] - minParam[p]) * MathRand()/32767.0;
}
}
}
```
Fitness evaluation requires running backtest for each chromosome - use `OnTester()` return value.

4. Selection: Tournament Selection
Tournament of size k = 3 selects parent:
```cpp
int TournamentSelect(Chromosome &pop[], int popSize, int tournamentSize) {
int bestIdx = MathRand() % popSize;
for(int i = 1; i < tournamentSize; i++) {
int idx = MathRand() % popSize;
if(pop[idx].fitness > pop[bestIdx].fitness) bestIdx = idx;
}
return bestIdx;
}
```

5. Crossover: Single-Point
Single-point crossover probability Pc = 0.75:
```cpp
void Crossover(Chromosome &parent1, Chromosome &parent2, Chromosome &child1, Chromosome &child2, int nParams) {
if(MathRand()/32767.0 > 0.75) {
int point = MathRand() % (totalBits);
// copy bits before/after crossover point
return;
}
// no crossover: children are copies of parents
}
```

6. Mutation: Bit Flip
Mutation rate Pm = 1 / totalBits per gene. Adaptive mutation formula: Pm(t) = Pm0 * (1 + cos(pi * t / T)) / 2 where t is generation, T max generations.

```cpp
void Mutate(Chromosome &ch, double pm) {
for(int p = 0; p < nParams; p++) {
if(MathRand()/32767.0 < pm) {
// flip random bit of parameter p
int bitPos = MathRand() % bitsPerParam[p];
ch.bits[p][bitPos] = 1 - ch.bits[p][bitPos];
}
}
DecodeChromosome(ch);
}
```

7. Fitness Landscape & Elitism
Elitism preserves top N_e = 2 best chromosomes unchanged each generation to prevent regression.

Elitism implementation:
```cpp
void Elitism(Chromosome &oldPop[], Chromosome &newPop[], int eliteSize) {
// sort oldPop by fitness descending
for(int i = 0; i < eliteSize; i++) {
newPop[i] = oldPop[i];
}
}
```

8. Convergence Criteria
Stop when standard deviation of fitness σ_F < ε or after maxGenerations. Diversity metric: D = (1/n) * Σ|μ - xi| / range.

Reference
  • Mitchell, M. (1998). "An Introduction to Genetic Algorithms." MIT Press. Chapter 4-5.

  • MQL4 Documentation: "OnTester" and "Optimization" (docs.mql4.com)