Generate code in 3 minutes
Enter your idea and AI generates runnable code.
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.
GridStep), it opens a new order.MaxOrders is reached.//+------------------------------------------------------------------+
//| 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());
}
}
//+------------------------------------------------------------------+
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).OnTick: This function runs every time the price changes.
MagicNumber).FindLastOrderInfo helper function. This ensures we calculate the distance from the most recent trade added, not the very first one.BaseLots size.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.Ask price is lower than the LastOpenPrice minus the GridStepPips.MaxOrders to ensure you don't open too many trades and exhaust your margin.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.