🚀 AI One-Click Generation of mql4 Strategy Code

Mql4 Money Management: How to Code a Pyramiding (Scaling-In) Strategy EA

mql4 | Published on: 2025/12/15
The following content is generated by EasyQuant .

Problem Description

I want to build a trading robot that adds more lots to a trade when it becomes profitable. How can I do that?

Solution

To build a trading robot that adds to a position when it becomes profitable (often called Pyramiding or Scaling In), you need a strategy that monitors the price distance from your last entry.

Here is a complete, fully commented MQL4 Expert Advisor (EA) that implements this logic.

Strategy Logic

  1. Initial Entry: Enters a trade based on a simple Moving Average crossover (you can replace this with your own entry logic).
  2. Scaling In: If a position exists and the price moves in favor of the trade by a specific number of pips (GridStep), it opens a new order.
  3. Limits: It stops adding trades once MaxOrders is reached.
  4. Risk Management: It applies Stop Loss and Take Profit to every new order.

MQL4 Code

//+------------------------------------------------------------------+
//|                                              PyramidingRobot.mq4 |
//|                        Copyright 2023, Quantitative AI Assistant |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Quantitative AI Assistant"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

//--- Input Parameters
input string   Label1 = "--- Volume Settings ---";
input double   BaseLots       = 0.1;      // Initial trade volume
input double   ScalingLots    = 0.1;      // Volume for subsequent trades
input int      MaxOrders      = 5;        // Maximum number of allowed open orders

input string   Label2 = "--- Grid Settings ---";
input int      GridStepPips   = 20;       // Distance in pips to add new trade (Profit required)
input int      StopLossPips   = 50;       // Stop Loss in pips
input int      TakeProfitPips = 100;      // Take Profit in pips

input string   Label3 = "--- Strategy Settings ---";
input int      FastMA         = 10;       // Fast Moving Average Period
input int      SlowMA         = 20;       // Slow Moving Average Period
input int      MagicNumber    = 123456;   // Unique identifier for this EA
input int      Slippage       = 3;        // Max slippage allowed

//--- Global Variables
double pipPoint;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   // Adjust pip value for 3/5 digit brokers
   if(Digits == 3 || Digits == 5) pipPoint = Point * 10;
   else pipPoint = Point;

   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   // 1. Check if trading is allowed
   if(!IsTradeAllowed()) return;

   // 2. Analyze current market state
   int totalOrders = 0;
   int lastType = -1;
   double lastOpenPrice = 0;
   
   // Loop through orders to find existing positions for this EA
   for(int i = 0; i < OrdersTotal(); i++)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
         {
            totalOrders++;
            
            // We want the price of the most recently opened order (highest ticket usually, 
            // but logic here assumes the one furthest in trend direction for grid calculation)
            // For simplicity, we track the last selected order in the loop.
            lastType = OrderType();
            lastOpenPrice = OrderOpenPrice(); 
            
            // To be precise for pyramiding, we usually want the 'best' price in the trend direction
            // But standard loop usually finds the oldest first. Let's refine logic below.
         }
      }
   }
   
   // Refine Last Open Price: We need the entry price of the LAST added trade to calculate the step
   if(totalOrders > 0)
   {
      FindLastOrderInfo(lastType, lastOpenPrice);
   }

   // 3. Entry Logic (If no orders exist)
   if(totalOrders == 0)
   {
      double maFast = iMA(NULL, 0, FastMA, 0, MODE_SMA, PRICE_CLOSE, 1);
      double maSlow = iMA(NULL, 0, SlowMA, 0, MODE_SMA, PRICE_CLOSE, 1);
      double maFastPrev = iMA(NULL, 0, FastMA, 0, MODE_SMA, PRICE_CLOSE, 2);
      double maSlowPrev = iMA(NULL, 0, SlowMA, 0, MODE_SMA, PRICE_CLOSE, 2);

      // Buy Signal: Fast MA crosses above Slow MA
      if(maFast > maSlow && maFastPrev <= maSlowPrev)
      {
         OpenTrade(OP_BUY, BaseLots);
      }
      // Sell Signal: Fast MA crosses below Slow MA
      else if(maFast < maSlow && maFastPrev >= maSlowPrev)
      {
         OpenTrade(OP_SELL, BaseLots);
      }
   }
   
   // 4. Pyramiding Logic (If orders exist and limit not reached)
   else if(totalOrders < MaxOrders)
   {
      // Check for BUY scaling
      if(lastType == OP_BUY)
      {
         // Current Bid price must be higher than last entry + grid step
         if(Bid >= lastOpenPrice + (GridStepPips * pipPoint))
         {
            OpenTrade(OP_BUY, ScalingLots);
         }
      }
      // Check for SELL scaling
      else if(lastType == OP_SELL)
      {
         // Current Ask price must be lower than last entry - grid step
         if(Ask <= lastOpenPrice - (GridStepPips * pipPoint))
         {
            OpenTrade(OP_SELL, ScalingLots);
         }
      }
   }
}

//+------------------------------------------------------------------+
//| Helper: Find the Open Price of the most recent order             |
//+------------------------------------------------------------------+
void FindLastOrderInfo(int &type, double &price)
{
   datetime lastTime = 0;
   
   for(int i = 0; i < OrdersTotal(); i++)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
         {
            // We look for the order with the most recent Open Time
            if(OrderOpenTime() > lastTime)
            {
               lastTime = OrderOpenTime();
               type = OrderType();
               price = OrderOpenPrice();
            }
         }
      }
   }
}

//+------------------------------------------------------------------+
//| Helper: Open a trade                                             |
//+------------------------------------------------------------------+
void OpenTrade(int type, double volume)
{
   double price, sl, tp;
   color arrowColor;

   if(type == OP_BUY)
   {
      price = Ask;
      sl = (StopLossPips > 0) ? price - StopLossPips * pipPoint : 0;
      tp = (TakeProfitPips > 0) ? price + TakeProfitPips * pipPoint : 0;
      arrowColor = clrBlue;
   }
   else
   {
      price = Bid;
      sl = (StopLossPips > 0) ? price + StopLossPips * pipPoint : 0;
      tp = (TakeProfitPips > 0) ? price - TakeProfitPips * pipPoint : 0;
      arrowColor = clrRed;
   }

   int ticket = OrderSend(Symbol(), type, volume, price, Slippage, sl, tp, "Pyramiding EA", MagicNumber, 0, arrowColor);
   
   if(ticket < 0)
   {
      Print("OrderSend failed with error #", GetLastError());
   }
}
//+------------------------------------------------------------------+

How It Works

  1. OnInit: It calculates the value of a "pip" depending on whether your broker uses 4 or 5 digits (e.g., 0.0001 vs 0.00001).
  2. OnTick: This function runs every time the price changes.
    • It counts how many orders are currently open for this specific strategy (MagicNumber).
    • It finds the Last Open Price using the FindLastOrderInfo helper function. This ensures we calculate the distance from the most recent trade added, not the very first one.
  3. Entry Logic: If there are 0 orders, it checks for a Moving Average crossover. If a cross happens, it opens the BaseLots size.
  4. Scaling Logic:
    • If we have a BUY position: It checks if the current Bid price is higher than the LastOpenPrice plus the GridStepPips. If yes, it means the trade is profitable by the required amount, so it opens a new Buy order with ScalingLots.
    • If we have a SELL position: It checks if the current Ask price is lower than the LastOpenPrice minus the GridStepPips.
  5. Safety: It checks MaxOrders to ensure you don't open too many trades and exhaust your margin.

How to Use This

  1. Open MetaEditor in MT4 (Press F4).
  2. Click New -> Expert Advisor (template) -> Name it "PyramidingRobot".
  3. Paste the code above into the file, replacing everything.
  4. Click Compile.
  5. Go back to the MT4 terminal, find the EA in the Navigator, and drag it onto a chart.

Important Considerations for Pyramiding

  • Break Even: When pyramiding, it is highly recommended to implement a "Break Even" or "Trailing Stop" logic. As you add more lots, a sudden reversal can turn a large profit into a large loss very quickly.
  • Margin: Ensure your account has enough leverage and balance. Adding lots increases margin requirements.
  • Trend: This strategy works best in strong trending markets. In ranging markets, it may trigger the first trade but fail to trigger scaling trades, or trigger them just before the price reverses.

Q&A

Q: How can I change the entry signal?
A: Look for the section // 3. Entry Logic in the OnTick function. Replace the Moving Average logic with your own indicator calls (e.g., RSI, MACD).

Q: Does this robot close trades automatically?
A: Yes, individual trades will close when they hit their specific TakeProfit or StopLoss. It does not currently have a "Close All" function based on total equity.

Q: What happens if the terminal restarts?
A: The EA uses MagicNumber to identify its trades. If you restart the terminal, it will find the existing trades and continue managing the scaling logic correctly.