🚀 AI One-Click Generation of mql4 Strategy Code

How to Code an Anti-Martingale (Reverse Martingale) Strategy in Mql4

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

Problem Description

How do I build a trading robot that increases its trade size after a winning trade and reduces it after a losing trade?

Solution

To build a trading robot (Expert Advisor) that adjusts trade size based on the result of the previous trade, you need to implement a custom money management function.

This specific logic—increasing size after a win and decreasing after a loss—is often referred to as a Positive Progression or Anti-Martingale strategy. It aims to capitalize on winning streaks while preserving capital during losing streaks.

The Strategy Logic

  1. Entry Signal: For demonstration, we will use a simple Moving Average Crossover.
  2. Money Management:
    • First Trade: Use BaseLot.
    • After a Win: Multiply the previous lot size by WinMultiplier (e.g., 1.5).
    • After a Loss: Multiply the previous lot size by LossMultiplier (e.g., 0.5).
  3. Safety: We will clamp the lot size so it never goes below the broker's minimum or above a defined maximum.

MQL4 Code Implementation

Copy and paste the following code into your MetaEditor (File -> New -> Expert Advisor).

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

//--- Input Parameters
input double BaseLot        = 0.1;    // Starting Lot Size
input double WinMultiplier  = 1.5;    // Multiplier after a WIN (e.g. 1.5 = +50%)
input double LossMultiplier = 0.5;    // Multiplier after a LOSS (e.g. 0.5 = -50%)
input double MaxLot         = 5.0;    // Maximum allowed Lot Size
input int    MagicNumber    = 123456; // Unique ID for this EA
input int    StopLoss       = 50;     // Stop Loss in points
input int    TakeProfit     = 100;    // Take Profit in points
input int    FastMA         = 10;     // Fast Moving Average Period
input int    SlowMA         = 20;     // Slow Moving Average Period

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   // Basic validation
   if(WinMultiplier < 1.0) Print("Warning: WinMultiplier is < 1.0. Lot size will decrease on wins.");
   if(LossMultiplier > 1.0) Print("Warning: LossMultiplier is > 1.0. Lot size will increase on losses.");
   
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   // 1. Check if we are allowed to trade
   if(!IsTradeAllowed()) return;

   // 2. Check for open positions (We only want one trade at a time for this logic)
   if(CountOpenTrades() > 0) return;

   // 3. Define Entry Signals (Simple MA Crossover)
   double fastCurr = iMA(NULL, 0, FastMA, 0, MODE_EMA, PRICE_CLOSE, 0);
   double slowCurr = iMA(NULL, 0, SlowMA, 0, MODE_EMA, PRICE_CLOSE, 0);
   double fastPrev = iMA(NULL, 0, FastMA, 0, MODE_EMA, PRICE_CLOSE, 1);
   double slowPrev = iMA(NULL, 0, SlowMA, 0, MODE_EMA, PRICE_CLOSE, 1);

   // 4. Calculate Dynamic Lot Size
   double tradeLot = CalculateDynamicLot();

   // 5. Execute Trades
   // Buy Signal: Fast MA crosses above Slow MA
   if(fastCurr > slowCurr && fastPrev <= slowPrev)
   {
      double sl = (StopLoss > 0) ? Ask - StopLoss * Point : 0;
      double tp = (TakeProfit > 0) ? Ask + TakeProfit * Point : 0;
      
      int ticket = OrderSend(Symbol(), OP_BUY, tradeLot, Ask, 3, sl, tp, "Dynamic Buy", MagicNumber, 0, clrGreen);
      if(ticket < 0) Print("OrderSend failed with error #", GetLastError());
   }

   // Sell Signal: Fast MA crosses below Slow MA
   if(fastCurr < slowCurr && fastPrev >= slowPrev)
   {
      double sl = (StopLoss > 0) ? Bid + StopLoss * Point : 0;
      double tp = (TakeProfit > 0) ? Bid - TakeProfit * Point : 0;
      
      int ticket = OrderSend(Symbol(), OP_SELL, tradeLot, Bid, 3, sl, tp, "Dynamic Sell", MagicNumber, 0, clrRed);
      if(ticket < 0) Print("OrderSend failed with error #", GetLastError());
   }
}

//+------------------------------------------------------------------+
//| Function to calculate lot size based on history                  |
//+------------------------------------------------------------------+
double CalculateDynamicLot()
{
   // Get Broker limitations
   double minLot = MarketInfo(Symbol(), MODE_MINLOT);
   double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
   double step   = MarketInfo(Symbol(), MODE_LOTSTEP);
   
   // Find the last closed trade for this EA
   int lastTicket = -1;
   datetime lastCloseTime = 0;

   for(int i = OrdersHistoryTotal() - 1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
         {
            if(OrderCloseTime() > lastCloseTime)
            {
               lastCloseTime = OrderCloseTime();
               lastTicket = OrderTicket();
            }
         }
      }
   }

   // If no history exists, return BaseLot
   if(lastTicket == -1) return BaseLot;

   // Select the last ticket to analyze profit
   if(OrderSelect(lastTicket, SELECT_BY_TICKET))
   {
      double lastLot = OrderLots();
      double profit  = OrderProfit(); // Profit in currency
      double newLot  = lastLot;

      // LOGIC: Increase on Win, Decrease on Loss
      if(profit > 0)
      {
         newLot = lastLot * WinMultiplier;
      }
      else
      {
         newLot = lastLot * LossMultiplier;
      }

      // Safety: If the calculation makes the lot smaller than base, 
      // you might want to reset to BaseLot. 
      // Uncomment the line below to enforce BaseLot as a floor.
      // if(newLot < BaseLot) newLot = BaseLot;

      // Normalize Lot Size to Broker Steps
      newLot = MathFloor(newLot / step) * step;

      // Clamp between Min and Max
      if(newLot < minLot) newLot = minLot;
      if(newLot > maxLot) newLot = maxLot;
      if(newLot > MaxLot) newLot = MaxLot; // User defined max

      return newLot;
   }

   return BaseLot;
}

//+------------------------------------------------------------------+
//| Helper to count open trades                                      |
//+------------------------------------------------------------------+
int CountOpenTrades()
{
   int count = 0;
   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
            count++;
      }
   }
   return count;
}

Key Components Explained

  1. CalculateDynamicLot() Function:

    • This is the core of your request. It scans the account history (MODE_HISTORY) to find the most recently closed trade that matches the EA's MagicNumber.
    • It checks OrderProfit().
    • If profit is positive, it applies WinMultiplier.
    • If profit is negative, it applies LossMultiplier.
  2. Normalization:

    • Brokers have specific lot steps (e.g., 0.01 or 0.1). The code uses MathFloor(newLot / step) * step to ensure the calculated lot size is valid for your broker.
  3. Safety Clamps:

    • The code checks MODE_MINLOT and MODE_MAXLOT (broker limits) and the MaxLot input (your personal risk limit) to prevent the robot from opening invalid or excessively large trades.
  4. CountOpenTrades():

    • This ensures the robot only manages one trade at a time. This is crucial for this specific money management strategy because "increasing after a win" requires the previous trade to be fully closed to determine the outcome.

How to Test This

  1. Compile the code (F7 in MetaEditor).
  2. Open the Strategy Tester in MT4 (Ctrl+R).
  3. Select "DynamicPositionSizingEA".
  4. Important: Set WinMultiplier to 1.5 and LossMultiplier to 0.5 (or your preferred settings).
  5. Run the test and switch to the "Results" tab. You will see the "Size" column changing based on the profit of the previous trade.

Q&A: Quantitative Trading & MQL4

Q: What is the risk of using a Positive Progression strategy?
A: While it capitalizes on winning streaks, a single loss after a long winning streak can wipe out a significant portion of profits if the WinMultiplier is too aggressive. It is mathematically safer than Martingale (doubling on loss), but still increases drawdown volatility.

Q: Can I use this logic with pending orders?
A: Yes, but the logic provided calculates the lot size at the moment the order is sent. If you place a pending order, the lot size is fixed at placement. If another trade closes after you place the pending order but before it triggers, the pending order will not update its lot size automatically.

Q: How does OrderProfit() handle commissions and swaps?
A: OrderProfit() usually returns the gross profit/loss. To be precise, you should calculate OrderProfit() + OrderCommission() + OrderSwap(). If your strategy relies on small scalping wins, ignoring commissions might cause the robot to think a trade was a "win" when it was actually a net loss.

Q: Why do we use MagicNumber?
A: The MagicNumber allows the EA to distinguish its own trades from manual trades or trades opened by other robots running on the same account. Without it, the money management logic might calculate lot sizes based on trades it didn't execute.