Complete .mq5 source code

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

AspectPine Script (TradingView)MQL5 (MetaTrader 5)
ExecutionSeries evaluated on chart updatesEvent handlers with explicit buffers
DeploymentRuns in TradingView with alertsRuns in the MT5 terminal or on a VPS
Broker accessStrategy orders are simulated; live automation needs a separate integrationDirect broker connectivity
BacktestingStrategy Tester for strategy scriptsStrategy Tester for Expert Advisors
Code complexitySimpler, functional syntaxC++-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.