Complete .mq5 source code

GBPJPY Expert Advisor MQL5: High-Volatility Scalping Strategy

Study a GBPJPY M5 Expert Advisor using RSI threshold crossings, an EMA quote filter and ATR-based initial and trailing stops. This example provides inspectable rules and risk-sizing mechanics. No verified trade count, backtest, daily range ranking or optimal parameter study supports this page.

Strategy logic

Entry conditions

On a new M5 bar, request a buy when completed RSI 5 moves from below 30 to at least 30 and the current ask exceeds the completed EMA 20. A sell reverses this at 70 with bid below EMA. The optional weekday window is 07:00–22:00 broker-server time, not the London/New York overlap or a GMT/DST conversion. A spread cap of 30 broker points filters entries; it cannot prevent slippage or identify news events. Periods and thresholds are illustrative.

Exit conditions

Initial requested SL and TP are 1.5 and 3 times completed ATR from the entry quote. At each new M5 bar, matching positions are managed before session and spread entry filters: trailing activates at one current ATR in favor and requests a stop one ATR behind price, only tightening. There is no automatic 22:00 close, news calendar, pre-session pause or ATR-spike gate. Position size estimates a balance risk percentage and rounds down; stops, costs and fills can still exceed that estimate. Account-mode ownership and broker grids require testing.

MQL5 Expert Advisor Code

//+------------------------------------------------------------------+
//|  GBPJPY Scalping Expert Advisor for MetaTrader 5                 |
//|  Strategy: RSI (5) Crossover + 20 EMA Trend Filter               |
//|  + ATR (14) Risk Management on M5 Timeframe                      |
//|  DISCLAIMER: For educational purposes only. Past performance      |
//|  does not guarantee future results. Trade at your own risk.       |
//+------------------------------------------------------------------+
#property copyright "Pineify MQL5 Example"
#property version   "1.00"

//--- Input parameters
input int    RSI_Period         = 5;        // RSI period
input double RSI_Overbought     = 70.0;     // RSI overbought threshold
input double RSI_Oversold       = 30.0;     // RSI oversold threshold
input int    EMA_Period         = 20;       // EMA trend filter period
input int    ATR_Period         = 14;       // ATR period
input double RiskPercent        = 1.0;      // Risk per trade (% of balance)
input double SL_ATR_Mult        = 1.5;      // Stop loss ATR multiplier
input double TP_ATR_Mult        = 3.0;      // Take profit ATR multiplier
input double TrailATRMult       = 1.0;      // Trailing stop ATR activation
input double MaxSpreadPoints    = 30.0;     // Max allowed spread (points)
input bool   UseSessionFilter   = true;     // Limit new entries to 07-22 broker hours
input int    MagicNumber        = 20260617; // EA magic number
input string TradeComment       = "GBPJPY_Scalp"; // Trade comment

//--- Global indicator handles
int   hRSI = INVALID_HANDLE;
int   hEMA = INVALID_HANDLE;
int   hATR = INVALID_HANDLE;

//--- Trade object
#include <Trade/Trade.mqh>
CTrade trade;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   if(RSI_Period<1 || EMA_Period<1 || ATR_Period<1 || RSI_Oversold<0 || RSI_Overbought>100 ||
      RSI_Oversold>=RSI_Overbought || RiskPercent<=0 || SL_ATR_Mult<=0 || TP_ATR_Mult<=0 ||
      TrailATRMult<=0 || MaxSpreadPoints<0 || MagicNumber<0) return INIT_PARAMETERS_INCORRECT;
   //--- Validate symbol
   string sym = _Symbol;
   if(StringFind(sym, "GBPJPY") < 0 && StringFind(sym, "GBP/JPY") < 0)
      Print("Example labeled GBPJPY; inspect contract for ", sym);

   //--- Create indicator handles
   hRSI = iRSI(_Symbol, PERIOD_M5, RSI_Period, PRICE_CLOSE);
   hEMA = iMA(_Symbol, PERIOD_M5, EMA_Period, 0, MODE_EMA, PRICE_CLOSE);
   hATR = iATR(_Symbol, PERIOD_M5, ATR_Period);

   if(hRSI == INVALID_HANDLE || hEMA == INVALID_HANDLE || hATR == INVALID_HANDLE)
     {
      Print("Error: Failed to create indicator handles. Code: ", GetLastError());
      return INIT_FAILED;
     }

   //--- Configure trade object
   trade.SetExpertMagicNumber(MagicNumber);
   trade.SetDeviationInPoints(20);
   if(!trade.SetTypeFillingBySymbol(_Symbol)) return INIT_FAILED;

   Print("GBPJPY Scalping EA initialized. Magic: ", MagicNumber);
   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   if(hRSI != INVALID_HANDLE) IndicatorRelease(hRSI);
   if(hEMA != INVALID_HANDLE) IndicatorRelease(hEMA);
   if(hATR != INVALID_HANDLE) IndicatorRelease(hATR);
   Print("GBPJPY Scalping EA deinitialized. Reason: ", reason);
  }

//+------------------------------------------------------------------+
//| Helper: fetch a single indicator buffer value                     |
//+------------------------------------------------------------------+
double GetIndiValue(int handle, int shift = 0)
  {
   double buf[];
   ArraySetAsSeries(buf, true);
   if(CopyBuffer(handle, 0, shift, 1, buf) != 1) return EMPTY_VALUE;
   return buf[0];
  }

//+------------------------------------------------------------------+
//| Helper: count open positions for this EA's magic number          |
//+------------------------------------------------------------------+
int CountPositions()
  {
   int count = 0;
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0) continue;
      if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
         PositionGetInteger(POSITION_MAGIC) == (long)MagicNumber)
         count++;
     }
   return count;
  }

//+------------------------------------------------------------------+
//| Helper: calculate lot size from risk percentage                  |
//+------------------------------------------------------------------+
double CalcLotSize(double slPoints)
  {
   if(slPoints <= 0) return 0;

   double tickVal  = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
   double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   double balance  = AccountInfoDouble(ACCOUNT_BALANCE);
   double riskAmt  = balance * RiskPercent / 100.0;
   double stepLot  = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   double minLot   = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double maxLot   = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);

   if(tickSize<=0 || tickVal<=0 || stepLot<=0 || minLot<=0 || maxLot<minLot || riskAmt<=0) return 0;

   double lots = riskAmt / ((slPoints / tickSize) * tickVal);
   lots = NormalizeDouble(MathFloor(MathMin(lots,maxLot) / stepLot) * stepLot,8);
   return lots>=minLot ? lots : 0;
  }

//+------------------------------------------------------------------+
//| Helper: check if current server time is in active session        |
//+------------------------------------------------------------------+
bool IsSessionActive()
  {
   if(!UseSessionFilter) return true;

   MqlDateTime dt;
   if(!TimeToStruct(TimeCurrent(), dt)) return false;

   // Skip weekends
   if(dt.day_of_week == 0 || dt.day_of_week == 6) return false;

   int hour = dt.hour;
   // Illustrative server-time window; no timezone or DST conversion
   return (hour >= 7 && hour < 22);
  }

//+------------------------------------------------------------------+
//| Helper: check spread is within acceptable range                  |
//+------------------------------------------------------------------+
bool IsSpreadOK()
  {
   double spread = (double)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
   return (spread <= MaxSpreadPoints);
  }

//+------------------------------------------------------------------+
//| Helper: manage trailing stop on open positions                   |
//+------------------------------------------------------------------+
void ManageTrailingStop(double atrValue)
  {
   double trailDist = TrailATRMult * atrValue;

   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      ulong ticket = PositionGetTicket(i);
      if(ticket == 0) continue;
      if(!PositionSelectByTicket(ticket)) continue;
      if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
      if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;

      double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
      double currentSL = PositionGetDouble(POSITION_SL);
      double currentTP = PositionGetDouble(POSITION_TP);
      long   posType   = PositionGetInteger(POSITION_TYPE);

      if(posType == POSITION_TYPE_BUY)
        {
         double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
         if(bid < openPrice + trailDist) continue;
         double newSL = NormalizeDouble(bid - trailDist, _Digits);
         if(newSL > currentSL)
            if(!trade.PositionModify(ticket,newSL,currentTP) || trade.ResultRetcode()!=TRADE_RETCODE_DONE)
               Print("Trailing failed: ",trade.ResultRetcode()," ",trade.ResultRetcodeDescription());
        }
      else if(posType == POSITION_TYPE_SELL)
        {
         double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
         if(ask > openPrice - trailDist) continue;
         double newSL = NormalizeDouble(ask + trailDist, _Digits);
         if(currentSL == 0.0 || newSL < currentSL)
            if(!trade.PositionModify(ticket,newSL,currentTP) || trade.ResultRetcode()!=TRADE_RETCODE_DONE)
               Print("Trailing failed: ",trade.ResultRetcode()," ",trade.ResultRetcodeDescription());
        }
     }
  }

//+------------------------------------------------------------------+
//| Main tick handler                                                |
//+------------------------------------------------------------------+
void OnTick()
  {
   //--- New bar detection on M5 (only process once per bar)
   static datetime lastBarTime = 0;
   datetime currentBarTime = iTime(_Symbol, PERIOD_M5, 0);
   if(currentBarTime<=0 || currentBarTime == lastBarTime) return;

   //--- Fetch indicator values from the last completed bar (shift 1)
   double rsiCurr = GetIndiValue(hRSI, 1);
   double rsiPrev = GetIndiValue(hRSI, 2);
   double emaCurr = GetIndiValue(hEMA, 1);
   double atrCurr = GetIndiValue(hATR, 1);

   if(rsiCurr==EMPTY_VALUE || rsiPrev==EMPTY_VALUE || emaCurr==EMPTY_VALUE || atrCurr==EMPTY_VALUE || atrCurr<=0) return;
   lastBarTime=currentBarTime;

   //--- Manage trailing stops for existing positions
   if(CountPositions() > 0)
     {
      ManageTrailingStop(atrCurr);
      return;  // One trade at a time for this EA
     }

   if(!IsSessionActive() || !IsSpreadOK()) return;
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

   //--- LONG entry: RSI crosses above 30 from below, price above EMA
   if(rsiPrev < RSI_Oversold && rsiCurr >= RSI_Oversold && ask > emaCurr)
     {
      double sl  = NormalizeDouble(ask - SL_ATR_Mult * atrCurr, _Digits);
      double tp  = NormalizeDouble(ask + TP_ATR_Mult * atrCurr, _Digits);
      double lots = CalcLotSize(ask - sl);

      if(lots > 0.0)
        {
         if(trade.Buy(lots, _Symbol, ask, sl, tp, TradeComment) &&
            (trade.ResultRetcode()==TRADE_RETCODE_DONE || trade.ResultRetcode()==TRADE_RETCODE_DONE_PARTIAL))
            Print("BUY placed | Lots: ", lots, " | SL: ", sl, " | TP: ", tp);
         else
            Print("BUY failed | Retcode: ", trade.ResultRetcode());
        }
     }

   //--- SHORT entry: RSI crosses below 70 from above, price below EMA
   if(rsiPrev > RSI_Overbought && rsiCurr <= RSI_Overbought && bid < emaCurr)
     {
      double sl  = NormalizeDouble(bid + SL_ATR_Mult * atrCurr, _Digits);
      double tp  = NormalizeDouble(bid - TP_ATR_Mult * atrCurr, _Digits);
      double lots = CalcLotSize(sl - bid);

      if(lots > 0.0)
        {
         if(trade.Sell(lots, _Symbol, bid, sl, tp, TradeComment) &&
            (trade.ResultRetcode()==TRADE_RETCODE_DONE || trade.ResultRetcode()==TRADE_RETCODE_DONE_PARTIAL))
            Print("SELL placed | Lots: ", lots, " | SL: ", sl, " | TP: ", tp);
         else
            Print("SELL failed | Retcode: ", trade.ResultRetcode());
        }
     }
  }
//+------------------------------------------------------------------+

Copy this code into MetaEditor, save it in the MQL5/Experts folder, and compile with F7.

Generate a custom GBPJPY 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.

Frequently Asked Questions

Related MQL5 pages

Technical references

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.