Night Scalper EA MT5: MQL5 Asian Session Scalping Code & Guide
Inspect a server-time night-session EA that compares completed M15 closes with a fast EMA and limits the slow EMA change. Fixed point-based exits and a scheduled closure make the mechanics explicit. The example does not prove a quiet session, a favorable spread, or a profitable scalping edge.
Strategy logic
Entry conditions
During the configured hour window, a completed close crossing the fast EMA permits an entry if the slow EMA change across two completed bars is below the price-unit threshold. The spread filter uses broker points, not ATR. One signal decision is processed per M15 bar after data is ready, with no matching position already open. Server time is not automatically GMT, Tokyo or London time.
Exit conditions
The default requested stop is 150 points and target 100 points. Trailing activates at 50 points of favorable movement but stays 150 points behind the quote, so activation does not lock in profit. Each position is scheduled for the next occurrence of ExitHour after its opening time; expired matching positions are retried for closure on later ticks. A missed tick, disconnect or rejected request can delay execution.
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 absolute EMA change across two bars
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()
{
if(InpLotSize<=0 || InpFastEMA<=0 || InpSlowEMA<=0 || InpStopLoss<=0
|| InpTakeProfit<=0 || InpTrailStart<0 || InpMaxSpreadPts<0 || InpSlopeThreshold<0
|| InpSessionStart<0 || InpSessionStart>23 || InpSessionEnd<0 || InpSessionEnd>23
|| InpSessionStart==InpSessionEnd || InpExitHour<0 || InpExitHour>23 || InpMagicNumber==0)
return INIT_PARAMETERS_INCORRECT;
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()
{
datetime now=TimeCurrent();
for(int i=PositionsTotal()-1;i>=0;i--)
{
if(PositionGetTicket(i)==0 || PositionGetString(POSITION_SYMBOL)!=_Symbol
|| PositionGetInteger(POSITION_MAGIC)!=(long)InpMagicNumber) continue;
datetime opened=(datetime)PositionGetInteger(POSITION_TIME);
datetime day=StringToTime(TimeToString(opened,TIME_DATE));
datetime deadline=day+(long)InpExitHour*3600;
if(deadline<=opened) deadline+=86400;
if(now>=deadline) return true;
}
return false;
}
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) || res.retcode!=TRADE_RETCODE_DONE)
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;
if(!OrderSend(req,res) || res.retcode!=TRADE_RETCODE_DONE)
Print("Trailing modification failed: ",res.retcode);
}
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;
if(!OrderSend(req,res) || res.retcode!=TRADE_RETCODE_DONE)
Print("Trailing modification failed: ",res.retcode);
}
}
}
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()
{
// Position-specific next server-time deadline; no London timezone conversion.
if(IsForcedExitTime())
{
CloseAllPositions();
return;
}
ManageTrailingStop();
if(!IsSessionActive()) return;
if(!SpreadOk()) return;
if(CountOpenPositions() > 0) return;
static datetime lastBar=0;
datetime current=iTime(_Symbol,PERIOD_M15,0);
if(current<=0 || current==lastBar) return;
double fastEMA[], slowEMA[];
ArraySetAsSeries(fastEMA,true); ArraySetAsSeries(slowEMA,true);
if(CopyBuffer(g_fastHandle,0,1,2,fastEMA)!=2) return;
if(CopyBuffer(g_slowHandle,0,1,3,slowEMA)!=3) return;
double close1=iClose(_Symbol,PERIOD_M15,1),close2=iClose(_Symbol,PERIOD_M15,2);
if(close1<=0 || close2<=0) return;
lastBar=current;
double slowChange=MathAbs(slowEMA[0]-slowEMA[2]);
if(slowChange>InpSlopeThreshold) return;
bool bullCross=close2<fastEMA[1] && close1>fastEMA[0];
bool bearCross=close2>fastEMA[1] && close1<fastEMA[0];
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 entry, exit, position, order, and risk rules 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 | Strategy orders are simulated; live automation needs a separate 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.
Frequently Asked Questions
Related MQL5 pages
Risk and testing note
These educational examples require independent compilation and testing. A compile pass or an illustrative setting does not establish execution correctness or profitability. Any reported performance must be supported by reproducible data and test settings; past results do not predict future returns. Trading involves significant risk of loss. This content is not financial advice.