Complete .mq5 source code

GBPUSD Expert Advisor MT5: M15 EMA/RSI Code and Test Plan

Inspect a GBPUSD M15 EA using EMA crossovers, an RSI level, a live quote/SMA filter and ATR-based stops. The source is an educational example with illustrative parameters. No verified 2021–2025 backtest, optimization study or live win-rate benchmark is supplied.

Strategy logic

Entry conditions

Once per new M15 bar, compare the two completed EMA 9/21 values. A buy also requires completed RSI above 50 and current ask above completed SMA 50; shorts use RSI below 50 and bid below SMA. RSI is a level test, not a required crossing. The spread filter uses broker points, independently of ATR. These combined conditions define a signal; their improvement over an unfiltered strategy is not established.

Exit conditions

Initial requested SL and TP are 1.5 and 2 times completed ATR from the entry quote, not the entry candle low/high. At each new M15 bar, trailing is evaluated before the spread entry filter and only tightens after a move of one current ATR in favor. It uses that ATR as the gap and cannot guarantee partial profit or a maximum loss. There is no news or session filter. Risk sizing is an estimate using balance and tick properties; costs, fills, broker limits and netting-account ownership need separate validation.

MQL5 Expert Advisor Code

//+------------------------------------------------------------------+
//|  GBPUSD Scalping Expert Advisor for MetaTrader 5                 |
//|  Strategy: EMA Crossover + RSI Filter + ATR Risk Management      |
//|  Timeframe: M15 | Symbol: GBPUSD                                 |
//|  DISCLAIMER: For educational purposes only. Past backtest        |
//|  results do not guarantee future performance. Trade at your      |
//|  own risk. Always test thoroughly before live deployment.        |
//+------------------------------------------------------------------+
#property copyright "Pineify MQL5 Example"
#property version   "1.00"
#property strict

//--- Input parameters
input int    FastEMA_Period  = 9;       // Fast EMA period
input int    SlowEMA_Period  = 21;      // Slow EMA period
input int    TrendSMA_Period = 50;      // Trend SMA period
input int    RSI_Period      = 14;      // RSI 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     = 2.0;    // Take profit ATR multiplier
input double Trail_ATR_Mult  = 1.0;    // Trailing stop ATR multiplier
input double MaxSpreadPoints = 20.0;   // Max allowed spread (points)
input int    MagicNumber     = 202201; // EA magic number
input string TradeComment    = "GBPUSD_Scalp"; // Trade comment

//--- Global handles
int    hFastEMA  = INVALID_HANDLE;
int    hSlowEMA  = INVALID_HANDLE;
int    hTrendSMA = INVALID_HANDLE;
int    hRSI      = INVALID_HANDLE;
int    hATR      = INVALID_HANDLE;

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

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   if(FastEMA_Period<1 || SlowEMA_Period<1 || TrendSMA_Period<1 || RSI_Period<1 || ATR_Period<1 ||
      RiskPercent<=0 || SL_ATR_Mult<=0 || TP_ATR_Mult<=0 || Trail_ATR_Mult<=0 || MaxSpreadPoints<0 || MagicNumber<0)
      return INIT_PARAMETERS_INCORRECT;
   //--- Validate symbol
   if(Symbol() != "GBPUSD" && Symbol() != "GBPUSDm")
      Print("Example labeled GBPUSD; inspect contract for ", Symbol());

   //--- Create indicator handles
   hFastEMA  = iMA(_Symbol, PERIOD_M15, FastEMA_Period,  0, MODE_EMA, PRICE_CLOSE);
   hSlowEMA  = iMA(_Symbol, PERIOD_M15, SlowEMA_Period,  0, MODE_EMA, PRICE_CLOSE);
   hTrendSMA = iMA(_Symbol, PERIOD_M15, TrendSMA_Period, 0, MODE_SMA, PRICE_CLOSE);
   hRSI      = iRSI(_Symbol, PERIOD_M15, RSI_Period, PRICE_CLOSE);
   hATR      = iATR(_Symbol, PERIOD_M15, ATR_Period);

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

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

   Print("GBPUSD Scalping EA initialized successfully.");
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   //--- Release indicator handles
   if(hFastEMA  != INVALID_HANDLE) IndicatorRelease(hFastEMA);
   if(hSlowEMA  != INVALID_HANDLE) IndicatorRelease(hSlowEMA);
   if(hTrendSMA != INVALID_HANDLE) IndicatorRelease(hTrendSMA);
   if(hRSI      != INVALID_HANDLE) IndicatorRelease(hRSI);
   if(hATR      != INVALID_HANDLE) IndicatorRelease(hATR);

   Print("GBPUSD Scalping EA deinitialized. Reason: ", reason);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   //--- Only process on new M15 bar
   static datetime lastBarTime = 0;
   datetime currentBarTime = iTime(_Symbol, PERIOD_M15, 0);
   if(currentBarTime<=0 || currentBarTime == lastBarTime) return;

   //--- Fetch indicator buffers (index 1 = previous closed bar)
   double fastEMA_curr[2], slowEMA_curr[2], trendSMA[2], rsi[2], atr[2];

   if(CopyBuffer(hFastEMA,  0, 1, 2, fastEMA_curr) < 2) return;
   if(CopyBuffer(hSlowEMA,  0, 1, 2, slowEMA_curr) < 2) return;
   if(CopyBuffer(hTrendSMA, 0, 1, 2, trendSMA)     < 2) return;
   if(CopyBuffer(hRSI,      0, 1, 2, rsi)           < 2) return;
   if(CopyBuffer(hATR,      0, 1, 2, atr)           < 2) return;

   double fastPrev = fastEMA_curr[0];
   double slowPrev = slowEMA_curr[0];
   double fastCurr = fastEMA_curr[1];
   double slowCurr = slowEMA_curr[1];
   double smaCurr  = trendSMA[1];
   double rsiCurr  = rsi[1];
   double atrCurr  = atr[1];
   if(atrCurr<=0 || !MathIsValidNumber(atrCurr)) return;
   lastBarTime=currentBarTime;

   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

   //--- Manage trailing stops on open positions
   ManageTrailingStop(atrCurr);

   //--- Skip if position already open for this EA
   if(PositionExistsForMagic()) return;

   double spreadPoints=(double)SymbolInfoInteger(_Symbol,SYMBOL_SPREAD);
   if(spreadPoints<0 || spreadPoints>MaxSpreadPoints) return;
   //--- Detect EMA crossover signals
   bool bullishCross = (fastPrev <= slowPrev) && (fastCurr > slowCurr);
   bool bearishCross = (fastPrev >= slowPrev) && (fastCurr < slowCurr);

   //--- Long entry conditions
   if(bullishCross && rsiCurr > 50 && ask > smaCurr)
     {
      double sl = NormalizeDouble(ask - SL_ATR_Mult * atrCurr, _Digits);
      double tp = NormalizeDouble(ask + TP_ATR_Mult * atrCurr, _Digits);
      double lots = CalculateLotSize(ask - sl);

      if(lots > 0)
        {
         if(!trade.Buy(lots,_Symbol,ask,sl,tp,TradeComment) ||
            (trade.ResultRetcode()!=TRADE_RETCODE_DONE && trade.ResultRetcode()!=TRADE_RETCODE_DONE_PARTIAL))
            Print("Buy failed: ",trade.ResultRetcode()," ",trade.ResultRetcodeDescription());
        }
     }

   //--- Short entry conditions
   if(bearishCross && rsiCurr < 50 && bid < smaCurr)
     {
      double sl = NormalizeDouble(bid + SL_ATR_Mult * atrCurr, _Digits);
      double tp = NormalizeDouble(bid - TP_ATR_Mult * atrCurr, _Digits);
      double lots = CalculateLotSize(sl - bid);

      if(lots > 0)
        {
         if(!trade.Sell(lots,_Symbol,bid,sl,tp,TradeComment) ||
            (trade.ResultRetcode()!=TRADE_RETCODE_DONE && trade.ResultRetcode()!=TRADE_RETCODE_DONE_PARTIAL))
            Print("Sell failed: ",trade.ResultRetcode()," ",trade.ResultRetcodeDescription());
        }
     }
  }

//+------------------------------------------------------------------+
//| Calculate lot size based on risk percentage                      |
//+------------------------------------------------------------------+
double CalculateLotSize(double slDistance)
  {
   if(slDistance <= 0) return 0;

   double balance    = AccountInfoDouble(ACCOUNT_BALANCE);
   double riskAmount = balance * RiskPercent / 100.0;
   double tickSize   = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   double tickValue  = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
   double minLot     = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double maxLot     = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   double lotStep    = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

   if(tickSize<=0 || tickValue<=0 || lotStep<=0 || minLot<=0 || maxLot<minLot || riskAmount<=0) return 0;

   double slTicks = slDistance / tickSize;
   double lots    = riskAmount / (slTicks * tickValue);
   lots = NormalizeDouble(MathFloor(MathMin(lots,maxLot) / lotStep) * lotStep,8);
   return lots>=minLot ? lots : 0;
  }

//+------------------------------------------------------------------+
//| Manage trailing stop for open positions                          |
//+------------------------------------------------------------------+
void ManageTrailingStop(double atrValue)
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      if(!PositionSelectByTicket(PositionGetTicket(i))) continue;
      if(PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
      if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;

      double trailDist = Trail_ATR_Mult * atrValue;
      double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
      double currentSL = PositionGetDouble(POSITION_SL);
      long   posType   = PositionGetInteger(POSITION_TYPE);

      if(posType == POSITION_TYPE_BUY)
        {
         double bid       = SymbolInfoDouble(_Symbol, SYMBOL_BID);
         double newSL     = NormalizeDouble(bid - trailDist, _Digits);
         double minProfit = NormalizeDouble(openPrice + trailDist, _Digits);
         if(bid >= minProfit && newSL > currentSL)
            if(!trade.PositionModify(PositionGetTicket(i),newSL,PositionGetDouble(POSITION_TP)) ||
               trade.ResultRetcode()!=TRADE_RETCODE_DONE)
               Print("Trailing failed: ",trade.ResultRetcode()," ",trade.ResultRetcodeDescription());
        }
      else if(posType == POSITION_TYPE_SELL)
        {
         double ask    = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
         double newSL  = NormalizeDouble(ask + trailDist, _Digits);
         double minProfit = NormalizeDouble(openPrice - trailDist, _Digits);
         if(ask <= minProfit && (currentSL == 0 || newSL < currentSL))
            if(!trade.PositionModify(PositionGetTicket(i),newSL,PositionGetDouble(POSITION_TP)) ||
               trade.ResultRetcode()!=TRADE_RETCODE_DONE)
               Print("Trailing failed: ",trade.ResultRetcode()," ",trade.ResultRetcodeDescription());
        }
     }
  }

//+------------------------------------------------------------------+
//| Check if a position exists for this EA's magic number            |
//+------------------------------------------------------------------+
bool PositionExistsForMagic()
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      if(!PositionSelectByTicket(PositionGetTicket(i))) continue;
      if(PositionGetInteger(POSITION_MAGIC) == MagicNumber &&
         PositionGetString(POSITION_SYMBOL) == _Symbol)
         return true;
     }
   return false;
  }
//+------------------------------------------------------------------+

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

Generate a custom GBPUSD 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

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.