EMA Cross Arrow Input for MT5 – Complete Trading Guide
Wednesday, August 12, 2026The 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.
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:
- Fast EMA values
- Mid EMA values
- Slow EMA values
- Buy arrow positions
- 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)
- Check H4 trend using EMA 50.
- Wait for a pullback to EMA 20 on H1.
- Wait for EMA 8 to cross above EMA 20.
- Confirm with a bullish candle close.
- Enter at the next candle.
- Place stop below the pullback low.
- 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);
}
//+------------------------------------------------------------------+
