Generate code in 3 minutes
Enter your idea and AI generates runnable code.
Here is a complete, fully functional Expert Advisor (EA) for MetaTrader 4 that implements a trend-following strategy using the Parabolic SAR indicator.
//+------------------------------------------------------------------+
//| ParabolicSAR_EA.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 InpLots = 0.1; // Lot Size
input double InpSarStep = 0.02; // SAR Step
input double InpSarMax = 0.2; // SAR Maximum
input int InpMagicNumber = 123456; // Magic Number
input int InpSlippage = 3; // Slippage (pips)
input bool InpUseTrailing = true; // Use SAR as Trailing Stop
//--- Global Variables
int g_ticket = 0;
double g_point;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Adjust point for 3/5 digit brokers
if(Digits == 3 || Digits == 5) g_point = Point * 10;
else g_point = Point;
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 1. Get SAR values for previous closed candles (Shift 1 and 2)
// We use closed candles to confirm the "flip" and avoid repainting
double sar1 = iSAR(NULL, 0, InpSarStep, InpSarMax, 1); // Previous candle
double sar2 = iSAR(NULL, 0, InpSarStep, InpSarMax, 2); // Candle before previous
double close1 = iClose(NULL, 0, 1);
double close2 = iClose(NULL, 0, 2);
// 2. Determine Signals
// Buy: SAR was above price (bearish), now below price (bullish)
bool buySignal = (sar2 > close2) && (sar1 < close1);
// Sell: SAR was below price (bullish), now above price (bearish)
bool sellSignal = (sar2 < close2) && (sar1 > close1);
// 3. Manage Open Positions
if(CountOrders() == 0)
{
if(buySignal) OpenOrder(OP_BUY);
if(sellSignal) OpenOrder(OP_SELL);
}
else
{
// Check for reversals
if(buySignal && IsOrderType(OP_SELL))
{
CloseAll();
OpenOrder(OP_BUY);
}
else if(sellSignal && IsOrderType(OP_BUY))
{
CloseAll();
OpenOrder(OP_SELL);
}
// 4. Trailing Stop Logic
if(InpUseTrailing) TrailingStopSAR();
}
}
//+------------------------------------------------------------------+
//| Helper: Open Order |
//+------------------------------------------------------------------+
void OpenOrder(int type)
{
double price, sl = 0, tp = 0;
color clr;
// Initial Stop Loss is set to the current SAR value
double currentSar = iSAR(NULL, 0, InpSarStep, InpSarMax, 0);
if(type == OP_BUY)
{
price = Ask;
clr = clrBlue;
sl = currentSar;
// Ensure SL is below price
if(sl >= price) sl = price - (100 * Point);
}
else
{
price = Bid;
clr = clrRed;
sl = currentSar;
// Ensure SL is above price
if(sl <= price) sl = price + (100 * Point);
}
int ticket = OrderSend(Symbol(), type, InpLots, price, InpSlippage, sl, tp, "SAR Trend", InpMagicNumber, 0, clr);
if(ticket < 0)
Print("OrderSend failed with error #", GetLastError());
}
//+------------------------------------------------------------------+
//| Helper: Close All Orders for this EA |
//+------------------------------------------------------------------+
void CloseAll()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == InpMagicNumber)
{
bool res = false;
if(OrderType() == OP_BUY)
res = OrderClose(OrderTicket(), OrderLots(), Bid, InpSlippage, clrGray);
if(OrderType() == OP_SELL)
res = OrderClose(OrderTicket(), OrderLots(), Ask, InpSlippage, clrGray);
if(!res) Print("OrderClose failed: ", GetLastError());
}
}
}
}
//+------------------------------------------------------------------+
//| Helper: Count Open Orders |
//+------------------------------------------------------------------+
int CountOrders()
{
int count = 0;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == InpMagicNumber)
count++;
}
}
return count;
}
//+------------------------------------------------------------------+
//| Helper: Check Order Type |
//+------------------------------------------------------------------+
bool IsOrderType(int type)
{
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == InpMagicNumber)
{
if(OrderType() == type) return true;
}
}
}
return false;
}
//+------------------------------------------------------------------+
//| Logic: Trailing Stop based on SAR |
//+------------------------------------------------------------------+
void TrailingStopSAR()
{
double currentSar = iSAR(NULL, 0, InpSarStep, InpSarMax, 0);
double stoplevel = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == InpMagicNumber)
{
// Modify Buy Order
if(OrderType() == OP_BUY)
{
// Only modify if SAR is above current SL and below current price (minus stoplevel)
if(currentSar > OrderStopLoss() && currentSar < (Bid - stoplevel))
{
if(!OrderModify(OrderTicket(), OrderOpenPrice(), currentSar, OrderTakeProfit(), 0, clrGreen))
Print("Error modifying Buy SL: ", GetLastError());
}
}
// Modify Sell Order
if(OrderType() == OP_SELL)
{
// Only modify if SAR is below current SL (0 means no SL) and above current price
if((OrderStopLoss() == 0 || currentSar < OrderStopLoss()) && currentSar > (Ask + stoplevel))
{
if(!OrderModify(OrderTicket(), OrderOpenPrice(), currentSar, OrderTakeProfit(), 0, clrGreen))
Print("Error modifying Sell SL: ", GetLastError());
}
}
}
}
}
}
F4 to open the MetaEditor.F7 to Compile. Ensure there are no errors.shift 1) against the candle before that (shift 2). This ensures the EA only acts when the dot physically moves from one side of the price to the other.TrailingStopSAR function updates the Stop Loss on every tick to the current SAR value. This is the classic way to trade this indicator, allowing profits to run until the trend reverses.MODE_STOPLEVEL to prevent "Invalid Stops" errors (Error 130) if the SAR dot is too close to the current price.Q: Why does the EA use shift 1 and shift 2 instead of shift 0?
A: Shift 0 represents the current forming candle. The Parabolic SAR value can change (repaint) while the candle is still forming. By using shift 1 (the last closed candle), we ensure the signal is confirmed and will not disappear.
Q: Can I use this on any timeframe?
A: Yes. However, Parabolic SAR works best on trending timeframes (typically H1, H4, or Daily). On lower timeframes (M1, M5), it may generate false signals during choppy (sideways) markets.
Q: How does the Trailing Stop work?
A: The Parabolic SAR indicator naturally moves closer to the price as the trend accelerates. The EA reads the value of the SAR dot on the current bar and moves the Stop Loss to that price, effectively locking in profit as the trade moves in your favor.