EMA Cross Arrow Input for MT5 – Complete Trading Guide

The EMA_Cross_Arrow_Input.mq5 indicator is a custom MetaTrader 5 (MT5) indicator based on one of the most popular concepts in technical analysis: the Exponential Moving Average (EMA) crossover.

EMA Cross Arrow Input for MT5 – Complete Trading Guide


This indicator plots three EMA lines and can optionally display buy and sell arrows when the fast EMA crosses the mid EMA. Although the code is relatively short, it contains several practical features that make it useful for trend identification, momentum analysis, and trade timing.


What Is an Exponential Moving Average (EMA)?

A moving average smooths price data to help traders identify the underlying trend. The Exponential Moving Average (EMA) gives more weight to recent prices, making it more responsive than the Simple Moving Average (SMA).

For example:

  • EMA 8 reacts quickly to price changes.
  • EMA 20 reacts more slowly.
  • EMA 50 reacts even more slowly and often represents the broader trend.

When a faster EMA crosses above a slower EMA, it suggests increasing bullish momentum. When it crosses below, it suggests increasing bearish momentum.


Overview of the Indicator

Default Settings

  • Fast EMA: 8 periods (orange)
  • Mid EMA: 20 periods (green)
  • Slow EMA: 50 periods (blue)
  • ArrowSignal: false by default

The indicator displays:

  • Orange line = fast EMA
  • Green line = mid EMA
  • Blue line = slow EMA
  • Aqua up arrows = buy signals
  • Orange down arrows = sell signals

How the Indicator Works

The indicator is drawn directly on the chart window using:

#property indicator_chart_window

It uses five buffers:

  1. Fast EMA values
  2. Mid EMA values
  3. Slow EMA values
  4. Buy arrow positions
  5. Sell arrow positions

The EMA buffers store the moving average values, while the arrow buffers store the price level where an arrow should appear.


User Inputs

One of the best features is that the EMA periods are fully customizable from the MT5 input window.

input int  FastMAPeriod = 8;
input int  MidMAPeriod  = 20;
input int  SlowMAPeriod = 50;
input bool ArrowSignal  = false;

Common Alternatives

Style Settings
Scalping 5 / 13 / 34
Intraday 8 / 20 / 50
Swing trading 10 / 21 / 55
Position trading 20 / 50 / 200

Initialization Process

During OnInit() the indicator performs three important tasks.

1. Bind Buffers

SetIndexBuffer(0, FastBuffer, INDICATOR_DATA);

2. Set Arrow Symbols

PlotIndexSetInteger(3, PLOT_ARROW, 233);
PlotIndexSetInteger(4, PLOT_ARROW, 234);
  • 233 = upward arrow
  • 234 = downward arrow

3. Create EMA Handles

hFastMA = iMA(_Symbol, _Period, FastMAPeriod, 0, MODE_EMA, PRICE_CLOSE);

The EMAs are calculated from the closing price.


Calculation Logic

Inside OnCalculate() the indicator first checks that enough candles exist.

int minBars = MathMax(MathMax(FastMAPeriod, MidMAPeriod), SlowMAPeriod) + 5;

Then it copies the EMA values into the custom buffers.

CopyBuffer(hFastMA, 0, 0, rates_total, FastBuffer);

Crossover Detection

Bullish Crossover

bool crossUp =
   (FastBuffer[i + 1] <= MidBuffer[i + 1]) &&
   (FastBuffer[i] >  MidBuffer[i]);

This means:

  • Previous closed candle: fast EMA was below or equal to mid EMA.
  • Current closed candle: fast EMA is above mid EMA.

Bearish Crossover

bool crossDown =
   (FastBuffer[i + 1] >= MidBuffer[i + 1]) &&
   (FastBuffer[i] <  MidBuffer[i]);

Why Closed Candles Matter

The indicator checks closed candles only. This is important because EMAs can cross and uncross during a forming candle, creating false signals.

Using closed candles:

  • reduces noise,
  • avoids unstable signals,
  • improves reliability for manual and automated trading.

Arrow Placement

Buy arrows are placed slightly below the candle:

BuyBuffer[i] = low[i] - 10 * _Point;

Sell arrows are placed slightly above the candle:

SellBuffer[i] = high[i] + 10 * _Point;

The Role of the 50 EMA

The 50 EMA is not used for generating arrows. It acts as a trend filter.

  • EMA 8 = short-term momentum
  • EMA 20 = signal line
  • EMA 50 = higher-timeframe trend context

Trading with the Indicator

Bullish Setup

Conditions:

  • Price above 50 EMA
  • EMA 8 crosses above EMA 20
  • Buy arrow appears

Entry: Buy at the next candle open.

Stop loss:

  • below the signal candle,
  • below EMA 20,
  • or below the recent swing low.

Take profit:

  • 1:2 or 1:3 risk-reward,
  • next resistance,
  • or trail below EMA 20.

Bearish Setup

Conditions:

  • Price below 50 EMA
  • EMA 8 crosses below EMA 20
  • Sell arrow appears

Entry: Sell at the next candle open.

Stop loss:

  • above the signal candle,
  • above EMA 20,
  • or above the recent swing high.

Take profit:

  • support level,
  • fixed RR target,
  • or trail above EMA 20.

Best Timeframes

Timeframe Quality
M1 Poor
M5 Fair
M15 Good
H1 Very good
H4 Excellent
D1 Excellent

Market Conditions

Trending Markets

The indicator performs best when:

  • EMAs are clearly separated,
  • price respects EMA 20,
  • crossovers occur after pullbacks.

Ranging Markets

It performs poorly when:

  • EMAs are intertwined,
  • price moves sideways,
  • crossovers happen frequently.

Improving the Strategy

Use the 50 EMA Filter

  • Buy signals above EMA 50
  • Sell signals below EMA 50

Add Higher Timeframe Confirmation

Example:

  • H4 trend bullish
  • H1 buy crossover

Combine with Support and Resistance

Signals near strong support or resistance are usually higher probability.


Risk Management

  • Risk 0.5% to 1% per trade
  • Avoid major news events
  • Do not take every arrow blindly
  • Wait for trend alignment

Advantages

  • Simple and easy to understand
  • Customizable EMA periods
  • Works on any MT5 symbol
  • Uses closed-candle confirmation
  • Visual arrows for quick scanning
  • Suitable for manual or automated trading

Limitations

  • Lagging indicator
  • Whipsaws in sideways markets
  • No built-in stop loss or take profit
  • No volatility filter
  • No multi-timeframe confirmation

Example Workflow (XAUUSD H1)

  1. Check H4 trend using EMA 50.
  2. Wait for a pullback to EMA 20 on H1.
  3. Wait for EMA 8 to cross above EMA 20.
  4. Confirm with a bullish candle close.
  5. Enter at the next candle.
  6. Place stop below the pullback low.
  7. Target 2R or trail behind EMA 20.

Conclusion

The EMA_Cross_Arrow_Input.mq5 indicator is a practical MT5 tool for trend-following and momentum trading.

Its three-EMA structure provides:

  • EMA 8: fast momentum
  • EMA 20: signal confirmation
  • EMA 50: trend context

The optional arrows make chart scanning easier, while the use of closed candles improves signal stability.

However, no moving-average system is perfect. The indicator works best when combined with market structure, support and resistance, higher-timeframe analysis, and disciplined risk management.

Used correctly, this indicator can become a solid foundation for intraday trading, swing trading, and MT5 algorithmic trading strategies.

Full Source Code


//+------------------------------------------------------------------+
//|                    EMA_Cross_Arrow_Input.mq5                     |
//|           EMA periods can be changed from indicator inputs       |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 5
#property indicator_plots   5

//--- Fast MA
#property indicator_label1  "Fast MA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrOrange
#property indicator_width1  1

//--- Mid MA
#property indicator_label2  "Mid MA"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrGreen
#property indicator_width2  1

//--- Slow MA
#property indicator_label3  "Slow MA"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrBlue
#property indicator_width3  1

//--- Buy arrows
#property indicator_label4  "Buy"
#property indicator_type4   DRAW_ARROW
#property indicator_color4  clrAqua
#property indicator_width4  2

//--- Sell arrows
#property indicator_label5  "Sell"
#property indicator_type5   DRAW_ARROW
#property indicator_color5  clrOrange
#property indicator_width5  2

//--- Inputs
input int  FastMAPeriod = 8;
input int  MidMAPeriod  = 20;
input int  SlowMAPeriod = 50;
input bool ArrowSignal  = false;

//--- Buffers
double FastBuffer[];
double MidBuffer[];
double SlowBuffer[];
double BuyBuffer[];
double SellBuffer[];

//--- Handles
int hFastMA, hMidMA, hSlowMA;

//+------------------------------------------------------------------+
//| Initialization                                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   //--- Bind buffers
   SetIndexBuffer(0, FastBuffer, INDICATOR_DATA);
   SetIndexBuffer(1, MidBuffer,  INDICATOR_DATA);
   SetIndexBuffer(2, SlowBuffer, INDICATOR_DATA);
   SetIndexBuffer(3, BuyBuffer,  INDICATOR_DATA);
   SetIndexBuffer(4, SellBuffer, INDICATOR_DATA);

   //--- Arrow symbols
   PlotIndexSetInteger(3, PLOT_ARROW, 233);
   PlotIndexSetInteger(4, PLOT_ARROW, 234);

   //--- Create EMA handles
   hFastMA = iMA(_Symbol, _Period, FastMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   hMidMA  = iMA(_Symbol, _Period, MidMAPeriod,  0, MODE_EMA, PRICE_CLOSE);
   hSlowMA = iMA(_Symbol, _Period, SlowMAPeriod, 0, MODE_EMA, PRICE_CLOSE);

   if(hFastMA == INVALID_HANDLE || hMidMA == INVALID_HANDLE || hSlowMA == INVALID_HANDLE)
      return(INIT_FAILED);

   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Calculation                                                      |
//+------------------------------------------------------------------+
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[])
{
   int minBars = MathMax(MathMax(FastMAPeriod, MidMAPeriod), SlowMAPeriod) + 5;

   if(rates_total < minBars)
      return(0);

   //--- Copy EMA values
   CopyBuffer(hFastMA, 0, 0, rates_total, FastBuffer);
   CopyBuffer(hMidMA,  0, 0, rates_total, MidBuffer);
   CopyBuffer(hSlowMA, 0, 0, rates_total, SlowBuffer);

   //--- Start point
   int start = (prev_calculated > 1) ? prev_calculated - 1 : 1;

   for(int i = start; i < rates_total - 1; i++)
   {
      BuyBuffer[i]  = EMPTY_VALUE;
      SellBuffer[i] = EMPTY_VALUE;

      if(!ArrowSignal)
         continue;

      //--- Closed candle crossover
      bool crossUp =
         (FastBuffer[i + 1] <= MidBuffer[i + 1]) &&
         (FastBuffer[i] >  MidBuffer[i]);

      bool crossDown =
         (FastBuffer[i + 1] >= MidBuffer[i + 1]) &&
         (FastBuffer[i] <  MidBuffer[i]);

      //--- Buy signal
      if(crossUp)
         BuyBuffer[i] = low[i] - 10 * _Point;

      //--- Sell signal
      if(crossDown)
         SellBuffer[i] = high[i] + 10 * _Point;
   }

   return(rates_total);
}

//+------------------------------------------------------------------+
//| Deinitialization                                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   if(hFastMA != INVALID_HANDLE) IndicatorRelease(hFastMA);
   if(hMidMA  != INVALID_HANDLE) IndicatorRelease(hMidMA);
   if(hSlowMA != INVALID_HANDLE) IndicatorRelease(hSlowMA);
}
//+------------------------------------------------------------------+