

Building a Martingale Grid Trading Strategy in MQL5
Summary: This article presents a complete implementation of a Martingale-based grid trading strategy in MQL5. We'll examine the code structure, risk management features, and potential enhancements for this controversial but powerful trading approach.
1. Introduction to Martingale Grid Trading
The Martingale strategy is a well-known (and often controversial) trading approach where position sizes are increased after losses, with the expectation that eventual wins will recover previous losses. When applied as a grid strategy, it involves placing orders at progressively better prices as the market moves against your initial position.
How Grid Martingale Works:
- An initial position is opened at the current market price
- Additional positions are added at predetermined intervals as price moves against you
- Each subsequent position is larger than the previous (typically 1.5-2x)
- All positions are closed when the average break-even price is reached
Key Risks to Consider:
- Margin depletion: Exponential position growth can quickly consume available margin
- No guaranteed recovery: Strong trends can continue beyond your grid levels
- Psychological stress: Requires discipline to manage growing losses
2. The MQL5 Implementation
Let's examine the complete code structure with detailed explanations for each component.
2.1. Includes and Initial Setup
#include <Trade/Trade.mqh> CTrade trade; #include <Trade\AccountInfo.mqh> static CAccountInfo accountInfo;
Explanation:
- CTrade class provides simplified trade execution methods (market orders, position management)
- CAccountInfo gives access to account-related functions (margin checks, balance information)
2.2. Grid Trading Parameters
// Grid parameters double initialLotSize = 0.01; double lotMultiplier = 1.5; int gridStepPoints = 300; double gridStep = gridStepPoints * _Point; int breakEvenTPPoints = 100; double breakEvenTP = breakEvenTPPoints * _Point; int digits_number; // Grid tracking variable double currentBuyGridStep = 0;
Parameter Breakdown:
Parameter | Description | Default Value |
---|---|---|
initialLotSize | Starting position size | 0.01 lots |
lotMultiplier | Position size multiplier for each new grid level | 1.5x |
gridStepPoints | Distance between grid levels in points | 300 points |
breakEvenTPPoints | Take-profit distance in points for break-even exit | 100 points |
2.3. Initialization Function
void InitializeVariables() { digits_number = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS); if (currentBuyGridStep == 0) { currentBuyGridStep = gridStep; } }
Key Functions:
- SymbolInfoInteger(_Symbol, SYMBOL_DIGITS) - Gets the number of decimal places for the current symbol
- Initializes currentBuyGridStep if not already set
3. Core Trading Logic
3.1. Main Execution Flow
void OnTick() { InitializeVariables(); RunTradingStrategy(); } void RunTradingStrategy() { int nr_buy_positions = CountBuyPositions(); double askPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK); // Open initial buy position if no buy positions exist if (nr_buy_positions == 0) { OpenInitialBuyPosition(); } CheckBuyGridLevels(); SetBreakEvenTP(); }
Process Flow:
- Initialize necessary variables on each tick
- Count existing buy positions
- Open initial position if none exists
- Check if new grid levels should be triggered
- Monitor for break-even exit conditions
3.2. Position Counting Function
int CountBuyPositions() { int count = 0; for (int i = 0; i < PositionsTotal(); i++) { ulong ticket = PositionGetTicket(i); if (PositionSelectByTicket(ticket) && PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { count++; } } return count; }
Key Points:
- Iterates through all open positions
- Filters positions for current symbol and buy type
- Returns count of matching positions
4. Grid Position Management
4.1. Opening the Initial Position
void OpenInitialBuyPosition() { double askPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK); // Get current ask price double lotSize = NormalizeLotSize(initialLotSize); double requiredMargin = accountInfo.MarginCheck(_Symbol, ORDER_TYPE_BUY, lotSize, askPrice); if(requiredMargin > accountInfo.FreeMargin()) { Print("Not enough margin for initial buy! Required: ", requiredMargin, " Free: ", accountInfo.FreeMargin()); return; } if (!trade.Buy(lotSize, _Symbol, askPrice, 0, 0, "Initial Buy")) { Print("Initial buy error: ", GetLastError()); } else { Print("Initial buy position opened at ", askPrice, " with lot size ", lotSize); } }
Safety Features:
- Lot size normalization to comply with broker restrictions
- Margin check before opening position
- Error handling and logging
4.2. Grid Level Monitoring
void CheckBuyGridLevels() { double minBuyPrice = DBL_MAX; int nr_buy_positions = 0; for (int i = 0; i < PositionsTotal(); i++) { ulong ticket = PositionGetTicket(i); if (PositionSelectByTicket(ticket) && PositionGetString(POSITION_SYMBOL) == _Symbol) { if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { double entryPrice = PositionGetDouble(POSITION_PRICE_OPEN); if (entryPrice < minBuyPrice) { minBuyPrice = entryPrice; } nr_buy_positions++; } } } if (nr_buy_positions > 0) { double nextGridBuyPrice = NormalizeDouble(minBuyPrice - currentBuyGridStep, digits_number); double currentAsk = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), digits_number); if (currentAsk <= nextGridBuyPrice) { double newLotSize = NormalizeLotSize(initialLotSize * MathPow(lotMultiplier, nr_buy_positions)); double requiredMargin = accountInfo.MarginCheck(_Symbol, ORDER_TYPE_BUY, newLotSize, currentAsk); if(requiredMargin > accountInfo.FreeMargin()) { Print("Not enough margin for grid buy!"); return; } if (!trade.Buy(newLotSize, _Symbol, currentAsk, 0, 0, "Grid Buy")) { Print("Grid buy error: ", GetLastError()); } } } }
Grid Logic Explained:
- Finds the lowest existing buy position price
- Calculates next grid level price (current lowest - grid step)
- Checks if current ask price has reached the next grid level
- Calculates new position size using exponential growth
- Performs margin check before opening new position
5. Break-Even Exit Strategy
void SetBreakEvenTP() { double totalBuyVolume = 0; double totalBuyCost = 0; for (int i = 0; i < PositionsTotal(); i++) { ulong ticket = PositionGetTicket(i); if (PositionSelectByTicket(ticket) && PositionGetString(POSITION_SYMBOL) == _Symbol) { if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { double volume = PositionGetDouble(POSITION_VOLUME); double entryPrice = PositionGetDouble(POSITION_PRICE_OPEN); totalBuyVolume += volume; totalBuyCost += entryPrice * volume; } } } if (totalBuyVolume > 0) { double breakEvenBuyPrice = NormalizeDouble((totalBuyCost / totalBuyVolume) + breakEvenTP, digits_number); double currentBid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), digits_number); if (currentBid >= breakEvenBuyPrice) { CloseAllBuyPositions(); } } }
Exit Logic:
- Calculates volume-weighted average entry price
- Adds the break-even TP distance to determine exit price
- Monitors current bid price against target exit price
- Closes all positions when target is reached
6. Risk Management and Enhancements
6.1. Current Safety Features
- Margin checks before each trade
- Lot size normalization
- Break-even exit mechanism
6.2. Potential Improvements
Enhancement | Description | Implementation Difficulty |
---|---|---|
Dynamic Grid Spacing | Adjust step size based on ATR or volatility | Medium |
Max Drawdown Limit | Stop trading after certain loss threshold | Easy |
Trailing Stop | Protect profits during favorable moves | Medium |
Time-Based Exit | Close positions after certain time period | Easy |
7. Conclusion
This Martingale grid strategy implementation provides a solid foundation for automated grid trading in MQL5. While the approach can be profitable in ranging markets, it carries significant risk during strong trends. Always:
- Thoroughly backtest with historical data
- Implement strict risk management rules
- Monitor performance in demo accounts before live trading
In future articles, we'll explore enhancements like:
- Sell-side grid implementation
- Multi-currency support
- Advanced risk controls
Note: The complete source code for this EA is available in the attached .mq5 file. Always test thoroughly in a demo environment before considering live trading.