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