Summary: This article explains core EA strategy principles including Martingale mechanisms, grid systems, and quantitative frameworks. Provides actual code structure, forced risk control logic, and anti-overfitting backtesting methods.




EA strategy principles are the foundation separating automated trading from random gambling. Many traders blindly use Martingale or grid EAs without understanding their mathematical mechanics. This leads to catastrophic account blow-ups during trend markets. This article explains three core EA strategy principles, provides actual code structure, and teaches risk control logic that must be hardcoded.

Martingale is the most dangerous yet most tempting EA principle. The concept is simple: after a loss, double the position size to recover previous losses with a small profit. The mathematics appear compelling. Starting with 0.01 lots, a losing sequence of 0.01, 0.02, 0.04, 0.08, 0.16, 0.32, 0.64 totals only 1.27 lots. A single win recovers all losses plus the base profit. However, the problem is that markets can produce extremely long losing streaks. After 10 consecutive losses, the position size grows from 0.01 to 5.12 lots. After 15 losses, it reaches 163.84 lots. A standard account cannot survive this. As Robert Carver notes in “Systematic Trading”, Martingale only works with infinite capital.

The forced recovery logic creates psychological traps. Traders believe “the next trade must win” and increase risk at the worst possible time. If you choose to use Martingale, implement three mandatory limits. First, cap the maximum multiplier at 4x or 5x the base size. Second, set a hard loss limit that stops the EA completely. Third, use reverse Martingale on winning sequences instead of losing ones. Below is a safety Martingale code structure in MQL4.

cpp
double baseLot = 0.01;
double maxLot = 0.05;
double currentLot = baseLot;
int consecutiveLosses = 0;
if(consecutiveLosses > 0 && consecutiveLosses <= 3) {
currentLot = baseLot * MathPow(2, consecutiveLosses);
if(currentLot > maxLot) currentLot = maxLot;
}
if(consecutiveLosses >= 4) {
CloseAllPositions();
DisableTrading();
}
Grid trading is another common EA principle. The strategy places buy and sell orders at fixed price intervals, profiting from price oscillations. The problem is directional bias. When a strong trend occurs, all grid orders go underwater simultaneously. A grid EA without trend filtering acts as a reverse Martingale. The solution is adding a trend filter based on the 200-period moving average. Only place long grid orders above the 200MA. Only place short grid orders below the 200MA. This simple filter reduces maximum drawdown significantly.

Quantitative trading requires anti-overfitting validation. The most common EA mistake is curve fitting parameters to historical data. David Aronson emphasizes in “Evidence-Based Technical Analysis” that robust systems must pass out-of-sample tests. Split data into three periods: training for parameter discovery, validation for single-parameter tuning, and testing for final verification. Never re-optimize after seeing test results. Use walk-forward analysis. Optimize on six months of data, then trade the next month without changes. Record the out-of-sample performance. Repeat this process monthly. If performance consistently drops out-of-sample, your EA lacks robustness.

Position sizing logic must be part of every EA. Never hardcode fixed lot sizes. Use the following position sizing function that calculates lots based on account risk percentage.

cpp
double CalculateLotSize(double riskPercent, double stopLossPips) {
double accountEquity = AccountEquity();
double riskAmount = accountEquity * riskPercent / 100.0;
double pipValue = MarketInfo(Symbol(), MODE_TICKSIZE) * 10.0;
double lotSize = riskAmount / (stopLossPips * pipValue);
lotSize = MathMin(lotSize, MarketInfo(Symbol(), MODE_MAXLOT));
lotSize = MathMax(lotSize, MarketInfo(Symbol(), MODE_MINLOT));
return NormalizeDouble(lotSize, 2);
}
Maximum drawdown control must be inside the EA, not external. Many traders place stop-loss on each trade but no global drawdown limit. This is insufficient. Code a global equity check into every tick function.

cpp
double peakEquity = AccountEquity();
if(AccountEquity() > peakEquity) peakEquity = AccountEquity();
double drawdownPercent = (peakEquity - AccountEquity()) / peakEquity * 100;
if(drawdownPercent >= 15) {
CloseAllOrders();
ExpertRemove();
}
Black swan defense requires volatility filters inside EA code. The Swiss franc event in 2015 killed EAs that lacked ATR filters. Implement an ATR-based trading suspension.

cpp
double atrCurrent = iATR(Symbol(), PERIOD_D1, 20, 1);
double atrAverage = iATR(Symbol(), PERIOD_D1, 100, 0);
if(atrCurrent > atrAverage * 2.5) {
if(CountOpenOrders() > 0) CloseAllOrders();
return;
}
Backtesting cannot rely solely on default settings. Avoid the common trap of running a single backtest with default spread and perfect execution. Use variable spread models. Add random slippage of 1-2 pips per trade. Model commission costs accurately. Test across multiple time periods including 2008, 2015, and 2020. An EA that only works on EUR/USD from 2023 to 2024 will fail in live markets. Test on at least 6 to 8 non-correlated pairs.

Forward testing is the final validation step. After backtesting, run the EA on a demo account for three months. Do not adjust parameters during this period. Compare forward results with backtest expectations. A robust EA shows forward results within 80% of backtest performance. If forward results drop below 50% of backtest, the system is overfitted and must be redesigned.

References:

Carver, R. (2015). Systematic Trading. Harriman House.

Aronson, D. (2006). Evidence-Based Technical Analysis. Wiley.

Pardo, R. (2008). The Evaluation and Optimization of Trading Strategies. Wiley.