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.
Historical test results
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, save it in the MQL5/Experts folder, and compile with F7.
Generate a custom EURUSD/GBPUSD night-scalping EA
Describe the ATR inputs, alert rules, visual style, or confirmation filter you want. Pineify generates editable MQL5 source code that you can inspect and compile in MetaEditor.
Pine Script vs MQL5: Same Strategy, Different Platforms
| Aspect | Pine Script (TradingView) | MQL5 (MetaTrader 5) |
|---|---|---|
| Execution | Series evaluated on chart updates | Event handlers with explicit buffers |
| Deployment | Runs in TradingView with alerts | Runs in the MT5 terminal or on a VPS |
| Broker access | Via TradingView broker integration | Direct broker connectivity |
| Backtesting | Strategy Tester for strategy scripts | Strategy Tester for Expert Advisors |
| Code complexity | Simpler, functional syntax | C++-like, more powerful |
The calculation can be implemented on either platform, but the runtime model and buffer APIs differ. Read the Pine Script Supertrend reference before porting logic between them.
Frequently Asked Questions
Related MQL5 pages
Risk and testing note
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.