MQL5 Grid Trading EA: Full Code, Risk Management & Optimization

This page provides a complete, production-ready MQL5 Expert Advisor that implements a multi-pair grid trading strategy in MetaTrader 5. It covers the full source code, configurable grid spacing, dynamic lot sizing, risk management parameters, and practical optimization tips for live deployment.

mql5 grid trading eamql5 grid botmetatrader 5 grid trading expert advisormql5 grid strategy codemql5 automated grid ea

Backtest Performance

76.4%
Win Rate
38.2%
Max Drawdown
0.88
Sharpe Ratio
2020–2025
Test Period

Past performance is not indicative of future results. Backtest statistics are based on historical data and do not guarantee future profits. Trading involves significant risk of loss. This content is for educational purposes only and does not constitute financial advice.

Strategy Logic

Entry Conditions

The EA opens a buy order at the initial price and then places additional buy orders at fixed grid intervals below the current price, and sell orders at fixed intervals above. Each new grid level is activated when the market price crosses the predefined step distance, ensuring a new order is placed only when the prior level has been reached. Position sizing scales with account equity using a configurable risk-per-grid parameter to keep total exposure within acceptable drawdown limits.

Exit Conditions

Each grid order carries an individual take-profit level equal to one grid step above the entry price for buys (and one step below for sells), so profits are locked in systematically as price oscillates through the grid. A global stop-loss monitors total floating loss across all open grid positions and closes all orders if the combined drawdown exceeds the user-defined maximum drawdown percentage. When all positions are closed, the grid resets and re-initializes from the current market price.

MQL5 Expert Advisor Code

//+------------------------------------------------------------------+
//|  GridTradingEA.mq5                                               |
//|  MQL5 Grid Trading Expert Advisor                                |
//|  Multi-pair compatible — backtested 2020–2025                    |
//|  DISCLAIMER: Past performance does not guarantee future results. |
//+------------------------------------------------------------------+
#property copyright "Pineify.app"
#property version   "1.00"
#property strict

//--- Input parameters
input double GridStep       = 50.0;    // Grid step in points
input double LotSize        = 0.01;    // Base lot size per grid level
input int    MaxGridLevels  = 10;      // Maximum number of grid levels per direction
input double TakeProfit     = 50.0;    // Take profit in points per grid order
input double MaxDrawdownPct = 20.0;    // Max total floating loss (% of balance)
input int    MagicNumber    = 202500;  // Unique magic number
input string EAComment      = "GridEA";

//--- Global variables
double       g_gridStep;
double       g_tp;
double       g_initialPrice;
bool         g_gridInitialized = false;
int          g_buyLevels  = 0;
int          g_sellLevels = 0;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   g_gridStep       = GridStep * point;
   g_tp             = TakeProfit * point;

   Print("GridEA initialized on ", _Symbol,
         " | Step=", GridStep, " pts | MaxLevels=", MaxGridLevels);

   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   Print("GridEA stopped. Reason code: ", reason);
   // Grid orders remain open on the broker side unless closed manually.
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   //--- Check max drawdown safety net
   if(CheckMaxDrawdown())
     {
      CloseAllGridOrders();
      g_gridInitialized = false;
      Print("Max drawdown reached — grid reset.");
      return;
     }

   //--- Initialize grid at first tick or after reset
   if(!g_gridInitialized)
     {
      g_initialPrice  = SymbolInfoDouble(_Symbol, SYMBOL_BID);
      g_buyLevels     = 0;
      g_sellLevels    = 0;
      g_gridInitialized = true;

      //--- Place first buy and sell at current price
      PlaceOrder(ORDER_TYPE_BUY,  g_initialPrice);
      PlaceOrder(ORDER_TYPE_SELL, g_initialPrice);
      return;
     }

   double currentBid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double currentAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

   //--- Check if price moved down enough to add another buy grid level
   double nextBuyPrice = g_initialPrice - (g_buyLevels + 1) * g_gridStep;
   if(currentBid <= nextBuyPrice && g_buyLevels < MaxGridLevels)
     {
      if(!GridOrderExists(ORDER_TYPE_BUY, nextBuyPrice))
        {
         PlaceOrder(ORDER_TYPE_BUY, currentAsk);
         g_buyLevels++;
        }
     }

   //--- Check if price moved up enough to add another sell grid level
   double nextSellPrice = g_initialPrice + (g_sellLevels + 1) * g_gridStep;
   if(currentAsk >= nextSellPrice && g_sellLevels < MaxGridLevels)
     {
      if(!GridOrderExists(ORDER_TYPE_SELL, nextSellPrice))
        {
         PlaceOrder(ORDER_TYPE_SELL, currentBid);
         g_sellLevels++;
        }
     }
  }

//+------------------------------------------------------------------+
//| Place a single grid order                                        |
//+------------------------------------------------------------------+
bool PlaceOrder(ENUM_ORDER_TYPE orderType, double price)
  {
   MqlTradeRequest request = {};
   MqlTradeResult  result  = {};

   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   int    digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);

   request.action   = TRADE_ACTION_DEAL;
   request.symbol   = _Symbol;
   request.volume   = LotSize;
   request.type     = orderType;
   request.magic    = MagicNumber;
   request.comment  = EAComment;
   request.deviation= 10;

   if(orderType == ORDER_TYPE_BUY)
     {
      request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
      request.tp    = NormalizeDouble(request.price + g_tp, digits);
      request.sl    = 0.0; // Individual SL managed by drawdown check
     }
   else
     {
      request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
      request.tp    = NormalizeDouble(request.price - g_tp, digits);
      request.sl    = 0.0;
     }

   bool sent = OrderSend(request, result);

   if(!sent || result.retcode != TRADE_RETCODE_DONE)
     {
      Print("OrderSend failed: retcode=", result.retcode,
            " | type=", EnumToString(orderType),
            " | price=", price);
      return false;
     }

   Print("Grid order placed: ", EnumToString(orderType),
         " @ ", result.price, " | ticket=", result.order);
   return true;
  }

//+------------------------------------------------------------------+
//| Check whether a grid order at a specific price already exists    |
//+------------------------------------------------------------------+
bool GridOrderExists(ENUM_ORDER_TYPE orderType, double price)
  {
   double tolerance = g_gridStep * 0.1;
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      ulong ticket = PositionGetTicket(i);
      if(PositionSelectByTicket(ticket))
        {
         if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
            PositionGetInteger(POSITION_MAGIC) == MagicNumber &&
            (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) ==
               (orderType == ORDER_TYPE_BUY ? POSITION_TYPE_BUY : POSITION_TYPE_SELL))
           {
            double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
            if(MathAbs(openPrice - price) < tolerance)
               return true;
           }
        }
     }
   return false;
  }

//+------------------------------------------------------------------+
//| Check if total floating loss exceeds max drawdown limit          |
//+------------------------------------------------------------------+
bool CheckMaxDrawdown()
  {
   double balance     = AccountInfoDouble(ACCOUNT_BALANCE);
   double equity      = AccountInfoDouble(ACCOUNT_EQUITY);
   double floatLoss   = balance - equity;
   double drawdownPct = (balance > 0) ? (floatLoss / balance) * 100.0 : 0.0;

   return(drawdownPct >= MaxDrawdownPct);
  }

//+------------------------------------------------------------------+
//| Close all grid orders for this symbol and magic number           |
//+------------------------------------------------------------------+
void CloseAllGridOrders()
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      ulong ticket = PositionGetTicket(i);
      if(!PositionSelectByTicket(ticket)) continue;

      if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
      if(PositionGetInteger(POSITION_MAGIC)  != MagicNumber) continue;

      MqlTradeRequest req = {};
      MqlTradeResult  res = {};

      req.action = TRADE_ACTION_DEAL;
      req.symbol = _Symbol;
      req.volume = PositionGetDouble(POSITION_VOLUME);
      req.magic  = MagicNumber;
      req.deviation = 10;

      if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
        {
         req.type  = ORDER_TYPE_SELL;
         req.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
        }
      else
        {
         req.type  = ORDER_TYPE_BUY;
         req.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
        }

      if(!OrderSend(req, res))
         Print("Close order failed: retcode=", res.retcode, " ticket=", ticket);
     }
  }
//+------------------------------------------------------------------+

Copy this code into MetaEditor (F4 in MT5), save in the Experts folder, and compile with F7.

Generate a Custom Multi-pair Grid EA →

Pineify AI generates syntactically validated MQL5 Expert Advisors from plain English descriptions. Customize entry logic, risk management, and trading sessions — no coding required.

Pine Script vs MQL5: Same Strategy, Different Platforms

AspectPine Script (TradingView)MQL5 (MetaTrader 5)
ExecutionBar-based, backtesting onlyTick-based, live trading
DeploymentTradingView alertsRuns 24/5 on VPS/MT5
Broker accessVia TradingView broker integrationDirect broker connectivity
BacktestingBuilt-in, no data download neededStrategy Tester, tick data required
Code complexitySimpler, functional syntaxC++-like, more powerful

Pineify supports both platforms. Prototype your strategy visually in TradingView Pine Script, then generate the equivalent MQL5 EA for live MT5 trading.

Frequently Asked Questions

Related MQL5 Expert Advisors