Generate code in 3 minutes
Enter your idea and AI generates runnable code.
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.
BaseLot.WinMultiplier (e.g., 1.5).LossMultiplier (e.g., 0.5).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;
}
CalculateDynamicLot() Function:
MODE_HISTORY) to find the most recently closed trade that matches the EA's MagicNumber.OrderProfit().WinMultiplier.LossMultiplier.Normalization:
MathFloor(newLot / step) * step to ensure the calculated lot size is valid for your broker.Safety Clamps:
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.CountOpenTrades():
WinMultiplier to 1.5 and LossMultiplier to 0.5 (or your preferred settings).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.