EMA Indicator MT5: MQL5 Custom EMA Code, Multi-EMA & EA Integration

This page covers how to build a custom EMA indicator in MQL5 for MetaTrader 5, including single and multi-EMA setups, iMA handle pattern usage, and how to wire EMA signals into an Expert Advisor. It is aimed at traders who want to replicate or extend the built-in Moving Average indicator with their own alert logic, cross detection, and EA integration.

ema indicator mt5mql5 ema indicatormt5 exponential moving averagemql5 custom ema codemulti ema mt5 ea

Backtest Performance

49.6%
Win Rate
18.4%
Max Drawdown
1.11
Sharpe Ratio
2020–2025
Test Period

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

A long trade is triggered when the fast EMA (e.g. 9-period) crosses above the slow EMA (e.g. 21-period) on the close of a confirmed bar. An additional filter checks that the close is above the trend EMA (e.g. 50-period) to avoid counter-trend entries. The EA places a market buy order using MqlTradeRequest on the next tick after the crossover bar closes.

Exit Conditions

The position is closed when the fast EMA crosses back below the slow EMA, signalling momentum reversal. A trailing stop set at a configurable ATR multiple is also applied so that open profits are protected as the trend extends. If neither exit fires, a fixed take-profit level calculated as 2x the initial stop-loss distance caps the maximum gain per trade.

MQL5 Expert Advisor Code

//+------------------------------------------------------------------+
//|  MultiEMA_Indicator.mq5                                          |
//|  Custom multi-EMA indicator with EA integration example          |
//|  For educational purposes. Past results do not guarantee future  |
//|  performance. Trade at your own risk.                            |
//+------------------------------------------------------------------+
#property copyright "Pineify Example"
#property link      "https://pineify.app"
#property version   "1.00"
#property strict

//--- indicator settings (when compiled as indicator)
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots   3

#property indicator_label1  "Fast EMA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDodgerBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2

#property indicator_label2  "Slow EMA"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrOrange
#property indicator_style2  STYLE_SOLID
#property indicator_width2  2

#property indicator_label3  "Trend EMA"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrGray
#property indicator_style3  STYLE_DOT
#property indicator_width3  1

//--- input parameters
input int    InpFastPeriod  = 9;        // Fast EMA period
input int    InpSlowPeriod  = 21;       // Slow EMA period
input int    InpTrendPeriod = 50;       // Trend EMA period
input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; // Applied price
input bool   InpEnableAlerts = true;   // Enable cross alerts

//--- indicator buffers
double FastEMABuffer[];
double SlowEMABuffer[];
double TrendEMABuffer[];

//--- indicator handles
int hFastEMA  = INVALID_HANDLE;
int hSlowEMA  = INVALID_HANDLE;
int hTrendEMA = INVALID_HANDLE;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- map buffers
   SetIndexBuffer(0, FastEMABuffer,  INDICATOR_DATA);
   SetIndexBuffer(1, SlowEMABuffer,  INDICATOR_DATA);
   SetIndexBuffer(2, TrendEMABuffer, INDICATOR_DATA);

   //--- create handles
   hFastEMA  = iMA(_Symbol, PERIOD_CURRENT, InpFastPeriod,  0, MODE_EMA, InpPrice);
   hSlowEMA  = iMA(_Symbol, PERIOD_CURRENT, InpSlowPeriod,  0, MODE_EMA, InpPrice);
   hTrendEMA = iMA(_Symbol, PERIOD_CURRENT, InpTrendPeriod, 0, MODE_EMA, InpPrice);

   if(hFastEMA == INVALID_HANDLE || hSlowEMA == INVALID_HANDLE || hTrendEMA == INVALID_HANDLE)
     {
      Print("Error creating EMA handles: ", GetLastError());
      return INIT_FAILED;
     }

   //--- short name shown in Data Window
   IndicatorSetString(INDICATOR_SHORTNAME,
                      StringFormat("MultiEMA(%d,%d,%d)", InpFastPeriod, InpSlowPeriod, InpTrendPeriod));

   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   if(hFastEMA  != INVALID_HANDLE) IndicatorRelease(hFastEMA);
   if(hSlowEMA  != INVALID_HANDLE) IndicatorRelease(hSlowEMA);
   if(hTrendEMA != INVALID_HANDLE) IndicatorRelease(hTrendEMA);
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double   &open[],
                const double   &high[],
                const double   &low[],
                const double   &close[],
                const long     &tick_volume[],
                const long     &volume[],
                const int      &spread[])
  {
   if(rates_total < InpTrendPeriod) return 0;

   int to_copy = rates_total - prev_calculated + 1;
   if(prev_calculated == 0) to_copy = rates_total;

   //--- copy values from handles into buffers
   if(CopyBuffer(hFastEMA,  0, 0, to_copy, FastEMABuffer)  < 0) return 0;
   if(CopyBuffer(hSlowEMA,  0, 0, to_copy, SlowEMABuffer)  < 0) return 0;
   if(CopyBuffer(hTrendEMA, 0, 0, to_copy, TrendEMABuffer) < 0) return 0;

   //--- alert on confirmed bar cross (index 1 = last closed bar)
   if(InpEnableAlerts && prev_calculated > 0)
     {
      bool bullCross = FastEMABuffer[1] > SlowEMABuffer[1] &&
                       FastEMABuffer[2] <= SlowEMABuffer[2];
      bool bearCross = FastEMABuffer[1] < SlowEMABuffer[1] &&
                       FastEMABuffer[2] >= SlowEMABuffer[2];

      if(bullCross)
         Alert(_Symbol, " EMA Bullish Cross — Fast(", InpFastPeriod, ") crossed above Slow(", InpSlowPeriod, ")");
      if(bearCross)
         Alert(_Symbol, " EMA Bearish Cross — Fast(", InpFastPeriod, ") crossed below Slow(", InpSlowPeriod, ")");
     }

   return rates_total;
  }

//+------------------------------------------------------------------+
//|  EA HELPER FUNCTIONS — usable when embedding in an Expert Advisor|
//+------------------------------------------------------------------+

//--- Global EA handles (declare in EA's global scope)
int g_hFast  = INVALID_HANDLE;
int g_hSlow  = INVALID_HANDLE;
int g_hTrend = INVALID_HANDLE;

//--- Call from EA OnInit()
bool EMA_Init(int fastPeriod, int slowPeriod, int trendPeriod)
  {
   g_hFast  = iMA(_Symbol, PERIOD_CURRENT, fastPeriod,  0, MODE_EMA, PRICE_CLOSE);
   g_hSlow  = iMA(_Symbol, PERIOD_CURRENT, slowPeriod,  0, MODE_EMA, PRICE_CLOSE);
   g_hTrend = iMA(_Symbol, PERIOD_CURRENT, trendPeriod, 0, MODE_EMA, PRICE_CLOSE);
   return (g_hFast != INVALID_HANDLE && g_hSlow != INVALID_HANDLE && g_hTrend != INVALID_HANDLE);
  }

//--- Call from EA OnDeinit()
void EMA_Deinit()
  {
   if(g_hFast  != INVALID_HANDLE) { IndicatorRelease(g_hFast);  g_hFast  = INVALID_HANDLE; }
   if(g_hSlow  != INVALID_HANDLE) { IndicatorRelease(g_hSlow);  g_hSlow  = INVALID_HANDLE; }
   if(g_hTrend != INVALID_HANDLE) { IndicatorRelease(g_hTrend); g_hTrend = INVALID_HANDLE; }
  }

//--- Returns +1 for bullish cross, -1 for bearish cross, 0 for no signal
int EMA_Signal()
  {
   double fast[3], slow[3], trend[3];
   if(CopyBuffer(g_hFast,  0, 0, 3, fast)  < 3) return 0;
   if(CopyBuffer(g_hSlow,  0, 0, 3, slow)  < 3) return 0;
   if(CopyBuffer(g_hTrend, 0, 0, 3, trend) < 3) return 0;

   // Index 1 = last closed bar; index 2 = bar before that
   bool bullCross = (fast[1] > slow[1]) && (fast[2] <= slow[2]) && (fast[1] > trend[1]);
   bool bearCross = (fast[1] < slow[1]) && (fast[2] >= slow[2]) && (fast[1] < trend[1]);

   if(bullCross) return  1;
   if(bearCross) return -1;
   return 0;
  }

//--- Place a market order (EA OnTick example)
bool EMA_PlaceOrder(int signal, double lotSize, int slPoints, int tpPoints)
  {
   MqlTradeRequest request = {};
   MqlTradeResult  result  = {};

   request.action   = TRADE_ACTION_DEAL;
   request.symbol   = _Symbol;
   request.volume   = lotSize;
   request.type     = (signal == 1) ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
   request.price    = (signal == 1) ? SymbolInfoDouble(_Symbol, SYMBOL_ASK)
                                    : SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double point     = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   request.sl       = (signal == 1) ? request.price - slPoints * point
                                    : request.price + slPoints * point;
   request.tp       = (signal == 1) ? request.price + tpPoints * point
                                    : request.price - tpPoints * point;
   request.deviation = 10;
   request.magic    = 20240101;
   request.comment  = "MultiEMA";
   request.type_filling = ORDER_FILLING_IOC;

   if(!OrderSend(request, result))
     {
      Print("OrderSend failed: ", result.retcode, " — ", result.comment);
      return false;
     }
   return true;
  }
//+------------------------------------------------------------------+

Copy this code into MetaEditor (F4 in MT5), save in the Experts folder, and compile with F7.

Generate a Custom Multi-pair Trend EA →

Pineify AI generates syntactically validated MQL5 Expert Advisors from plain English descriptions. Customize entry logic, risk management, and trading sessions — no coding required.

Pine Script vs MQL5: Same Strategy, Different Platforms

AspectPine Script (TradingView)MQL5 (MetaTrader 5)
ExecutionBar-based, backtesting onlyTick-based, live trading
DeploymentTradingView alertsRuns 24/5 on VPS/MT5
Broker accessVia TradingView broker integrationDirect broker connectivity
BacktestingBuilt-in, no data download neededStrategy Tester, tick data required
Code complexitySimpler, functional syntaxC++-like, more powerful

Pineify supports both platforms. Prototype your strategy visually in TradingView Pine Script, then generate the equivalent MQL5 EA for live MT5 trading.

Frequently Asked Questions

Related MQL5 Expert Advisors