Night Scalper EA MT5: MQL5 Asian Session Scalping Code & Guide
This page provides a complete MQL5 expert advisor implementation for night scalping EURUSD and GBPUSD during the Asian session, when spreads are tightest and price action is range-bound. You will find fully documented source code, backtest statistics, parameter tuning guidance, and answers to the most common questions about running a night scalper on MetaTrader 5.
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
The EA enters trades between 22:00 and 02:00 server time, targeting the low-volatility Asian session window. A buy is triggered when price closes above a short-period EMA (8) while the slow EMA (21) is flat within a configurable slope threshold, and the ATR-normalised spread is below the maximum spread filter. A sell is triggered under the mirror condition — price closes below the fast EMA while the slow EMA remains flat — ensuring the EA only participates in gentle mean-reverting moves rather than directional breakouts.
Exit Conditions
Each trade carries a fixed stop loss and take profit expressed in points, defaulting to 150 points SL and 100 points TP to achieve the asymmetric risk profile typical of high-win-rate night scalpers. The EA also implements a time-based exit: any open position is closed at 06:00 server time regardless of profit/loss to avoid the high-volatility London open. An optional trailing stop activates once floating profit exceeds half the take-profit distance, locking in gains on extended moves.
MQL5 Expert Advisor Code
//+------------------------------------------------------------------+
//| NightScalperEA.mq5 |
//| Night scalping EA for EURUSD / GBPUSD — Asian session |
//| For educational purposes only. Not financial advice. |
//+------------------------------------------------------------------+
#property copyright "Pineify"
#property version "1.00"
#property strict
//--- Input parameters
input double InpLotSize = 0.1; // Lot size
input int InpFastEMA = 8; // Fast EMA period
input int InpSlowEMA = 21; // Slow EMA period
input int InpStopLoss = 150; // Stop loss in points
input int InpTakeProfit = 100; // Take profit in points
input int InpTrailStart = 50; // Trailing start in points
input int InpMaxSpreadPts = 15; // Maximum allowed spread in points
input double InpSlopeThreshold = 0.0002; // Max slow EMA slope (price units/bar)
input int InpSessionStart = 22; // Session open hour (server time)
input int InpSessionEnd = 2; // Session close hour (server time)
input int InpExitHour = 6; // Force-exit hour (server time)
input ulong InpMagicNumber = 202401; // Magic number
//--- Global handles and state
int g_fastHandle = INVALID_HANDLE;
int g_slowHandle = INVALID_HANDLE;
double g_point = 0.0;
int g_digits = 5;
//+------------------------------------------------------------------+
//| Expert initialisation |
//+------------------------------------------------------------------+
int OnInit()
{
g_point = _Point;
g_digits = _Digits;
g_fastHandle = iMA(_Symbol, PERIOD_M15, InpFastEMA, 0, MODE_EMA, PRICE_CLOSE);
g_slowHandle = iMA(_Symbol, PERIOD_M15, InpSlowEMA, 0, MODE_EMA, PRICE_CLOSE);
if(g_fastHandle == INVALID_HANDLE || g_slowHandle == INVALID_HANDLE)
{
Print("NightScalperEA: Failed to create MA handles. Error: ", GetLastError());
return INIT_FAILED;
}
Print("NightScalperEA initialised on ", _Symbol,
" | Magic: ", InpMagicNumber,
" | Session: ", InpSessionStart, ":00 – ", InpSessionEnd, ":00");
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Expert deinitialization |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(g_fastHandle != INVALID_HANDLE) IndicatorRelease(g_fastHandle);
if(g_slowHandle != INVALID_HANDLE) IndicatorRelease(g_slowHandle);
Print("NightScalperEA deinitialised. Reason: ", reason);
}
//+------------------------------------------------------------------+
//| Helpers |
//+------------------------------------------------------------------+
bool IsSessionActive()
{
MqlDateTime dt;
TimeToStruct(TimeCurrent(), dt);
int hour = dt.hour;
// Handle session that wraps midnight (e.g. 22 – 02)
if(InpSessionStart > InpSessionEnd)
return (hour >= InpSessionStart || hour < InpSessionEnd);
return (hour >= InpSessionStart && hour < InpSessionEnd);
}
bool IsForcedExitTime()
{
MqlDateTime dt;
TimeToStruct(TimeCurrent(), dt);
return (dt.hour == InpExitHour && dt.min == 0);
}
bool SpreadOk()
{
long spreadPts = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
return (spreadPts <= InpMaxSpreadPts);
}
int CountOpenPositions()
{
int count = 0;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(PositionSelectByTicket(ticket))
if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
PositionGetInteger(POSITION_MAGIC) == (long)InpMagicNumber)
count++;
}
return count;
}
void CloseAllPositions()
{
MqlTradeRequest req;
MqlTradeResult res;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(!PositionSelectByTicket(ticket)) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != (long)InpMagicNumber) continue;
ZeroMemory(req);
ZeroMemory(res);
req.action = TRADE_ACTION_DEAL;
req.symbol = _Symbol;
req.volume = PositionGetDouble(POSITION_VOLUME);
req.type = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
? ORDER_TYPE_SELL : ORDER_TYPE_BUY;
req.price = (req.type == ORDER_TYPE_SELL)
? SymbolInfoDouble(_Symbol, SYMBOL_BID)
: SymbolInfoDouble(_Symbol, SYMBOL_ASK);
req.deviation = 10;
req.magic = InpMagicNumber;
req.position = ticket;
req.comment = "NightScalper forced exit";
if(!OrderSend(req, res))
Print("CloseAllPositions error: ", res.retcode, " ticket: ", ticket);
}
}
void ManageTrailingStop()
{
MqlTradeRequest req;
MqlTradeResult res;
double trailPts = InpTrailStart * g_point;
double slPts = InpStopLoss * g_point;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(!PositionSelectByTicket(ticket)) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if(PositionGetInteger(POSITION_MAGIC) != (long)InpMagicNumber) continue;
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double currentSL = PositionGetDouble(POSITION_SL);
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if(posType == POSITION_TYPE_BUY)
{
double profit = bid - openPrice;
if(profit < trailPts) continue;
double newSL = NormalizeDouble(bid - slPts, g_digits);
if(newSL <= currentSL) continue;
ZeroMemory(req); ZeroMemory(res);
req.action = TRADE_ACTION_SLTP;
req.symbol = _Symbol;
req.sl = newSL;
req.tp = PositionGetDouble(POSITION_TP);
req.position = ticket;
req.magic = InpMagicNumber;
OrderSend(req, res);
}
else // SELL
{
double profit = openPrice - ask;
if(profit < trailPts) continue;
double newSL = NormalizeDouble(ask + slPts, g_digits);
if(currentSL > 0 && newSL >= currentSL) continue;
ZeroMemory(req); ZeroMemory(res);
req.action = TRADE_ACTION_SLTP;
req.symbol = _Symbol;
req.sl = newSL;
req.tp = PositionGetDouble(POSITION_TP);
req.position = ticket;
req.magic = InpMagicNumber;
OrderSend(req, res);
}
}
}
bool OpenTrade(ENUM_ORDER_TYPE orderType)
{
MqlTradeRequest req;
MqlTradeResult res;
ZeroMemory(req);
ZeroMemory(res);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double slDist = InpStopLoss * g_point;
double tpDist = InpTakeProfit * g_point;
req.action = TRADE_ACTION_DEAL;
req.symbol = _Symbol;
req.volume = InpLotSize;
req.type = orderType;
req.deviation = 10;
req.magic = InpMagicNumber;
req.comment = "NightScalper";
req.type_filling = ORDER_FILLING_IOC;
if(orderType == ORDER_TYPE_BUY)
{
req.price = ask;
req.sl = NormalizeDouble(ask - slDist, g_digits);
req.tp = NormalizeDouble(ask + tpDist, g_digits);
}
else
{
req.price = bid;
req.sl = NormalizeDouble(bid + slDist, g_digits);
req.tp = NormalizeDouble(bid - tpDist, g_digits);
}
bool sent = OrderSend(req, res);
if(!sent || res.retcode != TRADE_RETCODE_DONE)
Print("OpenTrade failed. Type: ", EnumToString(orderType),
" Retcode: ", res.retcode);
return (sent && res.retcode == TRADE_RETCODE_DONE);
}
//+------------------------------------------------------------------+
//| Main tick handler |
//+------------------------------------------------------------------+
void OnTick()
{
// Force-exit at London open regardless of session
if(IsForcedExitTime())
{
CloseAllPositions();
return;
}
ManageTrailingStop();
if(!IsSessionActive()) return;
if(!SpreadOk()) return;
if(CountOpenPositions() > 0) return;
// Fetch EMA values — need 3 bars for slope calculation
double fastEMA[3], slowEMA[3];
if(CopyBuffer(g_fastHandle, 0, 0, 3, fastEMA) < 3) return;
if(CopyBuffer(g_slowHandle, 0, 0, 3, slowEMA) < 3) return;
ArraySetAsSeries(fastEMA, true);
ArraySetAsSeries(slowEMA, true);
double slowSlope = MathAbs(slowEMA[0] - slowEMA[2]);
// Only trade when slow EMA is flat (range-bound market)
if(slowSlope > InpSlopeThreshold) return;
double close1 = iClose(_Symbol, PERIOD_M15, 1);
double close2 = iClose(_Symbol, PERIOD_M15, 2);
bool bullCross = (close2 < fastEMA[2]) && (close1 > fastEMA[1]);
bool bearCross = (close2 > fastEMA[2]) && (close1 < fastEMA[1]);
if(bullCross) OpenTrade(ORDER_TYPE_BUY);
else if(bearCross) OpenTrade(ORDER_TYPE_SELL);
}
//+------------------------------------------------------------------+Copy this code into MetaEditor (F4 in MT5), save in the Experts folder, and compile with F7.
Generate a Custom EURUSD/GBPUSD Night-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.