Forex Scalping EA MT5: Best MQL5 Strategies, Code & 2026 Guide
This page covers how to build and deploy a high-frequency forex scalping Expert Advisor in MQL5 for MetaTrader 5, targeting short-term momentum bursts on M1 and M5 timeframes. You will find complete, runnable MQL5 code, backtested performance stats across 2022–2025, strategy logic breakdowns, and answers to the most common questions traders ask when automating a scalping EA.
Backtest Performance
Past performance is not indicative of future results. Backtest statistics are based on historical data and do not guarantee future profits. Trading involves significant risk of loss. This content is for educational purposes only and does not constitute financial advice.
Strategy Logic
Entry Conditions
A long trade is triggered when the fast EMA (9-period) crosses above the slow EMA (21-period) on the M5 chart and the current candle close is above the 50-period EMA, confirming the short-term trend. An additional RSI filter (14-period, threshold 55) ensures the EA only enters longs in momentum conditions, avoiding choppy sideways markets. Short entries mirror these conditions in reverse, requiring the fast EMA to cross below the slow EMA with RSI below 45.
Exit Conditions
Each trade is protected by a fixed stop-loss set at 1.5x the 14-period ATR value measured at entry, dynamically sized to current volatility rather than a static pip count. The take-profit target is placed at 2x ATR from entry, yielding an approximate 1:1.33 reward-to-risk ratio per trade. If price moves 1x ATR in favour before the TP is reached, a trailing stop activates and locks in half the open profit, letting winners run during extended moves.
MQL5 Expert Advisor Code
//+------------------------------------------------------------------+
//| ForexScalpingEA.mq5 |
//| Forex Scalping Expert Advisor — EMA Cross + RSI + ATR |
//| Compatible with MetaTrader 5 (MQL5 5.x) |
//| For educational and research purposes only. Past performance |
//| does not guarantee future results. Trade at your own risk. |
//+------------------------------------------------------------------+
#property copyright "Pineify — pineify.app"
#property version "1.00"
#property strict
//--- Input parameters
input int FastEMA_Period = 9; // Fast EMA period
input int SlowEMA_Period = 21; // Slow EMA period
input int TrendEMA_Period = 50; // Trend filter EMA period
input int RSI_Period = 14; // RSI period
input double RSI_LongMin = 55.0; // RSI minimum for longs
input double RSI_ShortMax = 45.0; // RSI maximum for shorts
input int ATR_Period = 14; // ATR period
input double SL_ATR_Mult = 1.5; // Stop-loss ATR multiplier
input double TP_ATR_Mult = 2.0; // Take-profit ATR multiplier
input double Trail_ATR_Mult = 1.0; // Trailing stop activation (ATR mult)
input double LotSize = 0.1; // Fixed lot size
input int MagicNumber = 20260001;// EA magic number
input string TradeComment = "ScalpEA";
//--- Indicator handles
int hFastEMA, hSlowEMA, hTrendEMA, hRSI, hATR;
//--- Previous bar values for cross detection
double prevFast, prevSlow;
//+------------------------------------------------------------------+
//| Expert initialisation |
//+------------------------------------------------------------------+
int OnInit()
{
hFastEMA = iMA(_Symbol, PERIOD_M5, FastEMA_Period, 0, MODE_EMA, PRICE_CLOSE);
hSlowEMA = iMA(_Symbol, PERIOD_M5, SlowEMA_Period, 0, MODE_EMA, PRICE_CLOSE);
hTrendEMA = iMA(_Symbol, PERIOD_M5, TrendEMA_Period, 0, MODE_EMA, PRICE_CLOSE);
hRSI = iRSI(_Symbol, PERIOD_M5, RSI_Period, PRICE_CLOSE);
hATR = iATR(_Symbol, PERIOD_M5, ATR_Period);
if(hFastEMA == INVALID_HANDLE || hSlowEMA == INVALID_HANDLE ||
hTrendEMA == INVALID_HANDLE || hRSI == INVALID_HANDLE || hATR == INVALID_HANDLE)
{
Print("Error creating indicator handles: ", GetLastError());
return INIT_FAILED;
}
Print("ForexScalpingEA initialised on ", _Symbol, " M5");
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Expert deinitialization |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
IndicatorRelease(hFastEMA);
IndicatorRelease(hSlowEMA);
IndicatorRelease(hTrendEMA);
IndicatorRelease(hRSI);
IndicatorRelease(hATR);
Print("ForexScalpingEA removed. Reason code: ", reason);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- Only act on a new M5 bar
static datetime lastBar = 0;
datetime currentBar = iTime(_Symbol, PERIOD_M5, 0);
if(currentBar == lastBar) return;
lastBar = currentBar;
//--- Read indicator buffers (index 1 = previous closed bar, 2 = bar before that)
double bufFast[3], bufSlow[3], bufTrend[2], bufRSI[2], bufATR[2];
if(CopyBuffer(hFastEMA, 0, 0, 3, bufFast) < 3) return;
if(CopyBuffer(hSlowEMA, 0, 0, 3, bufSlow) < 3) return;
if(CopyBuffer(hTrendEMA, 0, 0, 2, bufTrend) < 2) return;
if(CopyBuffer(hRSI, 0, 0, 2, bufRSI) < 2) return;
if(CopyBuffer(hATR, 0, 0, 2, bufATR) < 2) return;
double fastCurr = bufFast[1], fastPrev = bufFast[2];
double slowCurr = bufSlow[1], slowPrev = bufSlow[2];
double trendEMA = bufTrend[1];
double rsi = bufRSI[1];
double atr = bufATR[1];
double closeBar = iClose(_Symbol, PERIOD_M5, 1);
//--- Detect EMA crossovers on the just-closed bar
bool bullCross = (fastPrev <= slowPrev) && (fastCurr > slowCurr);
bool bearCross = (fastPrev >= slowPrev) && (fastCurr < slowCurr);
//--- Manage existing positions (trailing stop)
ManageTrailingStop(atr);
//--- Skip if a position already exists for this symbol+magic
if(PositionExists()) return;
//--- Entry signals
if(bullCross && closeBar > trendEMA && rsi >= RSI_LongMin)
{
double sl = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID) - SL_ATR_Mult * atr,
(int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
double tp = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID) + TP_ATR_Mult * atr,
(int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
OpenMarketOrder(ORDER_TYPE_BUY, LotSize, sl, tp);
}
else if(bearCross && closeBar < trendEMA && rsi <= RSI_ShortMax)
{
double sl = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK) + SL_ATR_Mult * atr,
(int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
double tp = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK) - TP_ATR_Mult * atr,
(int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
OpenMarketOrder(ORDER_TYPE_SELL, LotSize, sl, tp);
}
}
//+------------------------------------------------------------------+
//| Send a market order |
//+------------------------------------------------------------------+
bool OpenMarketOrder(ENUM_ORDER_TYPE type, double lots, double sl, double tp)
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = lots;
request.type = type;
request.price = (type == ORDER_TYPE_BUY)
? SymbolInfoDouble(_Symbol, SYMBOL_ASK)
: SymbolInfoDouble(_Symbol, SYMBOL_BID);
request.sl = sl;
request.tp = tp;
request.deviation= 10;
request.magic = MagicNumber;
request.comment = TradeComment;
request.type_filling = ORDER_FILLING_FOK;
if(!OrderSend(request, result))
{
Print("OrderSend failed: ", result.retcode, " — ", result.comment);
return false;
}
Print("Order opened: ticket=", result.order, " type=", EnumToString(type),
" price=", result.price, " sl=", sl, " tp=", tp);
return true;
}
//+------------------------------------------------------------------+
//| Check if a position exists for this EA |
//+------------------------------------------------------------------+
bool PositionExists()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(PositionGetSymbol(i) == _Symbol &&
PositionGetInteger(POSITION_MAGIC) == MagicNumber)
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Apply ATR-based trailing stop to open positions |
//+------------------------------------------------------------------+
void ManageTrailingStop(double atr)
{
double trailDist = Trail_ATR_Mult * atr;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double currentSL = PositionGetDouble(POSITION_SL);
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
if(posType == POSITION_TYPE_BUY)
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double newSL = NormalizeDouble(bid - trailDist, digits);
//--- Activate trail only after price moved Trail_ATR_Mult in favour
if(bid >= openPrice + trailDist && newSL > currentSL)
ModifySL(ticket, newSL);
}
else if(posType == POSITION_TYPE_SELL)
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double newSL = NormalizeDouble(ask + trailDist, digits);
if(ask <= openPrice - trailDist && (currentSL == 0 || newSL < currentSL))
ModifySL(ticket, newSL);
}
}
}
//+------------------------------------------------------------------+
//| Modify stop-loss of an existing position |
//+------------------------------------------------------------------+
void ModifySL(ulong ticket, double newSL)
{
MqlTradeRequest req = {};
MqlTradeResult res = {};
req.action = TRADE_ACTION_SLTP;
req.position = ticket;
req.symbol = _Symbol;
req.sl = newSL;
req.tp = PositionGetDouble(POSITION_TP);
if(!OrderSend(req, res))
Print("ModifySL failed: ", res.retcode);
}
//+------------------------------------------------------------------+Copy this code into MetaEditor (F4 in MT5), save in the Experts folder, and compile with F7.
Generate a Custom Forex Scalping EA →
Pineify AI generates syntactically validated MQL5 Expert Advisors from plain English descriptions. Customize entry logic, risk management, and trading sessions — no coding required.
Pine Script vs MQL5: Same Strategy, Different Platforms
| Aspect | Pine Script (TradingView) | MQL5 (MetaTrader 5) |
|---|---|---|
| Execution | Bar-based, backtesting only | Tick-based, live trading |
| Deployment | TradingView alerts | Runs 24/5 on VPS/MT5 |
| Broker access | Via TradingView broker integration | Direct broker connectivity |
| Backtesting | Built-in, no data download needed | Strategy Tester, tick data required |
| Code complexity | Simpler, functional syntax | C++-like, more powerful |
Pineify supports both platforms. Prototype your strategy visually in TradingView Pine Script, then generate the equivalent MQL5 EA for live MT5 trading.