Generate code in 3 minutes
Enter your idea and AI generates runnable code.
Here is a complete, fully functional Expert Advisor (trading robot) written in MQL4.
This robot implements a "Breakout" strategy. It calculates the highest high and lowest low of the previous 20 closed bars. It then places a Buy Stop order above the high and a Sell Stop order below the low. It includes logic to cancel the opposite pending order once a trade is triggered (One-Cancels-Other logic).
//+------------------------------------------------------------------+
//| 20BarBreakout_EA.mq4 |
//| Copyright 2023, Quantitative|
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Quantitative"
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
//--- Input Parameters
input int LookbackPeriod = 20; // Number of bars to check for High/Low
input double LotSize = 0.1; // Fixed Lot Size
input int BufferPoints = 10; // Distance from High/Low to place order (in points)
input int StopLoss = 500; // Stop Loss in points (0 = no SL)
input int TakeProfit = 1000; // Take Profit in points (0 = no TP)
input int MagicNumber = 123456; // Unique Identifier for this EA
input int ExpirationBars = 1; // Expiration of pending orders in bars (0 = no expiration)
//--- Global Variables
double pPoint; // Adjusted point value for 3/5 digit brokers
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Adjust point for 5-digit brokers (0.00001) vs 4-digit (0.0001)
if(Digits == 3 || Digits == 5) pPoint = Point * 10;
else pPoint = Point;
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Optional: Clean up all pending orders on removal
DeleteAllPendingOrders();
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 1. Check if we have open positions or pending orders managed by this EA
int buyOrders = 0;
int sellOrders = 0;
int buyStops = 0;
int sellStops = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
if(OrderType() == OP_BUY) buyOrders++;
if(OrderType() == OP_SELL) sellOrders++;
if(OrderType() == OP_BUYSTOP) buyStops++;
if(OrderType() == OP_SELLSTOP) sellStops++;
}
}
}
// 2. OCO Logic (One Cancels Other)
// If a market order is active, delete remaining pending orders
if(buyOrders > 0 || sellOrders > 0)
{
if(buyStops > 0 || sellStops > 0) DeleteAllPendingOrders();
return; // Exit OnTick, do not place new orders while in a trade
}
// 3. If pending orders already exist, do nothing (wait for expiration or trigger)
if(buyStops > 0 || sellStops > 0) return;
// 4. Calculate High and Low of the last 'LookbackPeriod' bars
// We start at index 1 to look at closed bars, ignoring the currently forming bar (index 0)
int highestIndex = iHighest(NULL, 0, MODE_HIGH, LookbackPeriod, 1);
int lowestIndex = iLowest(NULL, 0, MODE_LOW, LookbackPeriod, 1);
double highPrice = iHigh(NULL, 0, highestIndex);
double lowPrice = iLow(NULL, 0, lowestIndex);
// 5. Calculate Entry Prices
double buyStopPrice = NormalizeDouble(highPrice + BufferPoints * Point, Digits);
double sellStopPrice = NormalizeDouble(lowPrice - BufferPoints * Point, Digits);
// 6. Calculate Expiration Time
datetime expirationTime = 0;
if(ExpirationBars > 0)
{
expirationTime = TimeCurrent() + (PeriodSeconds() * ExpirationBars);
}
// 7. Check Minimum Stop Level (Distance from current price)
double stopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point;
// Ensure Buy Stop is above Ask + Stoplevel
if(buyStopPrice > Ask + stopLevel)
{
double sl = (StopLoss > 0) ? buyStopPrice - StopLoss * Point : 0;
double tp = (TakeProfit > 0) ? buyStopPrice + TakeProfit * Point : 0;
// Normalize SL/TP
if(sl > 0) sl = NormalizeDouble(sl, Digits);
if(tp > 0) tp = NormalizeDouble(tp, Digits);
int ticket = OrderSend(Symbol(), OP_BUYSTOP, LotSize, buyStopPrice, 3, sl, tp, "Buy Breakout", MagicNumber, expirationTime, clrGreen);
if(ticket < 0) Print("Error sending Buy Stop: ", GetLastError());
}
// Ensure Sell Stop is below Bid - Stoplevel
if(sellStopPrice < Bid - stopLevel)
{
double sl = (StopLoss > 0) ? sellStopPrice + StopLoss * Point : 0;
double tp = (TakeProfit > 0) ? sellStopPrice - TakeProfit * Point : 0;
// Normalize SL/TP
if(sl > 0) sl = NormalizeDouble(sl, Digits);
if(tp > 0) tp = NormalizeDouble(tp, Digits);
int ticket = OrderSend(Symbol(), OP_SELLSTOP, LotSize, sellStopPrice, 3, sl, tp, "Sell Breakout", MagicNumber, expirationTime, clrRed);
if(ticket < 0) Print("Error sending Sell Stop: ", GetLastError());
}
}
//+------------------------------------------------------------------+
//| Helper: Delete all pending orders for this EA |
//+------------------------------------------------------------------+
void DeleteAllPendingOrders()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
if(OrderType() == OP_BUYSTOP || OrderType() == OP_SELLSTOP)
{
bool res = OrderDelete(OrderTicket());
if(!res) Print("Failed to delete order: ", GetLastError());
}
}
}
}
}
//+------------------------------------------------------------------+
iHighest and iLowest starting from index 1.BufferPoints value to the High and subtracts it from the Low. This ensures you don't buy exactly at the high, but slightly above it (filtering out false breakouts).ExpirationBars input allows the pending orders to expire automatically if price does not break out within a certain time (default is 1 bar). This ensures the orders follow the moving 20-bar window dynamically.StopLoss and TakeProfit in points.MagicNumber to ensure the EA only manages its own trades and doesn't interfere with other manual trades or robots.20BarBreakout and click Finish.20BarBreakout in the Navigator panel (under Expert Advisors).LotSize, StopLoss, or LookbackPeriod if desired.Q: Why are my orders not being placed?
A: Check the "Journal" tab in the Terminal window. Common errors include:
LotSize selected.BufferPoints might place the order too close to the current market price (inside the broker's freeze level).Q: Does this work on 5-digit brokers?
A: Yes. The code includes a pPoint calculation in OnInit (though standard Point is used for the OrderSend math for simplicity, the inputs are treated as raw points). If you input StopLoss = 500, on a 5-digit broker, this is 50.0 pips.
Q: Why do the pending orders disappear after one bar?
A: This is due to the ExpirationBars setting (default 1). This is intentional. As the 20-bar window moves forward, the High/Low changes. The old order expires, and a new one is placed at the new High/Low. If you want them to stay forever, set ExpirationBars = 0.