Problem Description
Solution
Here is a complete, robust MQL4 Expert Advisor (EA) that implements a breakout strategy based on the High and Low of the last 20 bars.
Strategy Logic
- Buy Signal: If the current Ask price exceeds the Highest High of the previous 20 bars.
- Sell Signal: If the current Bid price drops below the Lowest Low of the previous 20 bars.
- Risk Management: Includes Stop Loss and Take Profit inputs.
- Order Management: Ensures only one trade is open at a time for this specific strategy to prevent over-trading.
MQL4 Code
//+------------------------------------------------------------------+
//| BreakoutStrategy.mq4 |
//| Copyright 2023, MetaQuotes Software Corp. |
//| 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 int InpPeriod = 20; // Breakout Period (Bars)
input double InpLotSize = 0.1; // Lot Size
input int InpStopLoss = 50; // Stop Loss (in Pips)
input int InpTakeProfit = 100; // Take Profit (in Pips)
input int InpMagicNum = 123456; // Magic Number (Unique ID)
input int InpSlippage = 3; // Max Slippage (in Points)
//--- Global Variables
double pipMultiplier;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Adjust pip multiplier for 3 or 5 digit brokers (Jpy pairs etc)
if(Digits == 3 || Digits == 5)
pipMultiplier = 10;
else
pipMultiplier = 1;
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Clean up if necessary
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 1. Check if we already have an open trade for this symbol and magic number
if(CountOpenTrades() > 0) return;
// 2. Calculate the Highest High and Lowest Low of the last 'InpPeriod' bars
// We start at index 1 (previous bar) to avoid the current forming bar repainting the high/low
int highestIndex = iHighest(NULL, 0, MODE_HIGH, InpPeriod, 1);
int lowestIndex = iLowest(NULL, 0, MODE_LOW, InpPeriod, 1);
if(highestIndex < 0 || lowestIndex < 0) return; // Error check
double resistanceLevel = High[highestIndex];
double supportLevel = Low[lowestIndex];
// 3. Check for Buy Breakout
// If Ask price is higher than the highest high of the last 20 bars
if(Ask > resistanceLevel)
{
double sl = 0, tp = 0;
// Calculate SL/TP prices
if(InpStopLoss > 0)
sl = Ask - (InpStopLoss * pipMultiplier * Point);
if(InpTakeProfit > 0)
tp = Ask + (InpTakeProfit * pipMultiplier * Point);
// Normalize prices to prevent OrderSend errors
sl = NormalizeDouble(sl, Digits);
tp = NormalizeDouble(tp, Digits);
// Send Order
int ticket = OrderSend(Symbol(), OP_BUY, InpLots(), Ask, InpSlippage, sl, tp, "Buy Breakout", InpMagicNum, 0, clrGreen);
if(ticket < 0)
Print("OrderSend failed with error #", GetLastError());
}
// 4. Check for Sell Breakout
// If Bid price is lower than the lowest low of the last 20 bars
if(Bid < supportLevel)
{
double sl = 0, tp = 0;
// Calculate SL/TP prices
if(InpStopLoss > 0)
sl = Bid + (InpStopLoss * pipMultiplier * Point);
if(InpTakeProfit > 0)
tp = Bid - (InpTakeProfit * pipMultiplier * Point);
// Normalize prices
sl = NormalizeDouble(sl, Digits);
tp = NormalizeDouble(tp, Digits);
// Send Order
int ticket = OrderSend(Symbol(), OP_SELL, InpLots(), Bid, InpSlippage, sl, tp, "Sell Breakout", InpMagicNum, 0, clrRed);
if(ticket < 0)
Print("OrderSend failed with error #", GetLastError());
}
}
//+------------------------------------------------------------------+
//| Helper: Count open trades for this EA |
//+------------------------------------------------------------------+
int CountOpenTrades()
{
int count = 0;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
// Check if the order belongs to this Symbol and this Magic Number
if(OrderSymbol() == Symbol() && OrderMagicNumber() == InpMagicNum)
{
count++;
}
}
}
return count;
}
//+------------------------------------------------------------------+
//| Helper: Verify Lot Size |
//+------------------------------------------------------------------+
double InpLots()
{
double minLot = MarketInfo(Symbol(), MODE_MINLOT);
double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
double step = MarketInfo(Symbol(), MODE_LOTSTEP);
double lots = InpLotSize;
// Ensure lot size is within broker limits
if(lots < minLot) lots = minLot;
if(lots > maxLot) lots = maxLot;
// Normalize to lot step
return(MathFloor(lots / step) * step);
}
//+------------------------------------------------------------------+
How to Install and Run
- Open MetaTrader 4.
- Press F4 to open the MetaEditor.
- Click New -> Expert Advisor (template) -> Next.
- Name it
BreakoutStrategyand click Finish. - Delete everything in the new file and paste the code provided above.
- Press F7 or click Compile. Ensure there are no errors in the "Errors" tab at the bottom.
- Return to the main MT4 window.
- Find
BreakoutStrategyin the Navigator panel under Expert Advisors. - Drag it onto a chart (e.g., EURUSD H1).
- Ensure AutoTrading is enabled at the top of the terminal.
Key Features Explained
iHighest/iLowest: These are the core MQL4 functions used to find the index of the highest and lowest bars over theInpPeriod(20).- Shift
1: IniHighest(..., 1), the last parameter is the start index. We use1(the previous closed bar) instead of0(the current moving bar). This prevents the signal from flickering while the current bar is still forming. pipMultiplier: This logic inOnInitautomatically detects if your broker uses 5-digit pricing (e.g., EURUSD 1.12345) or 4-digit pricing. This ensures that if you input a 50 Pip Stop Loss, it remains 50 Pips, not 5 Pips.CountOpenTrades: This function prevents the EA from opening 100 trades instantly if the price stays above the breakout line. It forces the EA to wait until the current trade hits SL or TP before opening a new one.
Q&A
Q: Can I change the period from 20 to 50?
A: Yes. When you attach the EA to the chart, go to the "Inputs" tab and change InpPeriod to 50.
Q: Why does the strategy check Ask > resistance for buying?
A: In MT4, Buy orders are executed at the Ask price. If you used the Bid price, the chart might show a breakout, but the spread might prevent the trade from actually being profitable immediately. Using Ask ensures the actual buy price has broken the level.
Q: Does this work on all timeframes?
A: Yes, it works on the timeframe of the chart you attach it to. If you attach it to M15, it looks for the 20-bar high of the M15 chart.