[1TF] MT5 Trend-Following EA with EMA + ADX: Code & Real Backtest Results
🚀 Trend-Following EA for MT5: Code, Logic, and Real Backtest Results
Building profitable EAs isn’t just about complex logic — sometimes, a clean and focused strategy gives you the insights you need to evolve your trading system. In this post, I’m sharing a trend-following EA I wrote for MetaTrader 5 using MQL5. I’ll explain the strategy logic, share the full code, and show you the backtest results on USDJPY (H1 timeframe).
🎯 Strategy Overview: Trend-Following with EMA + ADX Filter
- Buy Signal: EMA(20) crosses above EMA(50), ADX(14) > 20
- Sell Signal: EMA(20) crosses below EMA(50), ADX(14) > 20
- Stop Loss: 300 points
- Take Profit: 500 points
- Lot Size: 0.1 lots
🧠 The MQL5 EA Code
Here’s the full source code for the EA. You can compile and run it directly in MetaEditor:
#include <Trade\\Trade.mqh>
CTrade trade;
input int fastMAPeriod = 20;
input int slowMAPeriod = 50;
input int adxPeriod = 14;
input double minAdxLevel = 20.0;
input double lotSize = 0.1;
input int slippage = 5;
input double stopLoss = 300;
input double takeProfit = 500;
int fastMAHandle, slowMAHandle, adxHandle;
int OnInit()
{
fastMAHandle = iMA(_Symbol, _Period, fastMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
slowMAHandle = iMA(_Symbol, _Period, slowMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
adxHandle = iADX(_Symbol, _Period, adxPeriod);
if (fastMAHandle == INVALID_HANDLE || slowMAHandle == INVALID_HANDLE || adxHandle == INVALID_HANDLE)
{
Print("Indicator initialization failed");
return INIT_FAILED;
}
return INIT_SUCCEEDED;
}
void OnTick()
{
if (PositionSelect(_Symbol)) return;
double fastMA[], slowMA[], adxVal[];
if (CopyBuffer(fastMAHandle, 0, 0, 3, fastMA) <= 0) return;
if (CopyBuffer(slowMAHandle, 0, 0, 3, slowMA) <= 0) return;
if (CopyBuffer(adxHandle, 0, 0, 1, adxVal) <= 0) return;
bool crossUp = fastMA[1] < slowMA[1] && fastMA[0] > slowMA[0];
bool crossDown = fastMA[1] > slowMA[1] && fastMA[0] < slowMA[0];
if (adxVal[0] < minAdxLevel) return;
if (crossUp) tradeBuy();
else if (crossDown) tradeSell();
}
void tradeBuy()
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double sl = ask - stopLoss * _Point;
double tp = ask + takeProfit * _Point;
tradeClose();
trade.Buy(lotSize, _Symbol, ask, sl, tp, "Trend Buy");
}
void tradeSell()
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double sl = bid + stopLoss * _Point;
double tp = bid - takeProfit * _Point;
tradeClose();
trade.Sell(lotSize, _Symbol, bid, sl, tp, "Trend Sell");
}
void tradeClose()
{
if (PositionSelect(_Symbol))
trade.PositionClose(_Symbol);
}
📊 Backtest Result (USDJPY, H1, 2025/01/01–2025/07/10)
I ran this EA on USDJPY (H1) using historical data from a demo OANDA account. Here's the performance summary:
| Metric | Value |
|---|---|
| Total Net Profit | ¥-19.12 |
| Gross Profit | ¥632.46 |
| Gross Loss | ¥-651.58 |
| Profit Factor | < 1.00 |
| Absolute Drawdown | ¥37.27 |
| Equity Drawdown | ¥42.26 |
| Total Trades | 29 |
| AHPR / GHPR | 0.999 |
⚖️ My Thoughts
This version of the EA is a starting point — and not yet profitable. But the foundation is clear, and here’s what I learned:
- The entry logic catches trends, but exits may need smarter trailing logic
- Adding time filters (e.g., only trading during London open) could reduce false signals
- A better risk-reward tuning or adaptive SL/TP might bring this into profitability
🚧 Next Steps
I'm now working on:
- Optimizing the moving average periods
- Integrating higher timeframe confirmation
- Building a portfolio of multiple uncorrelated EAs
💬 Want to Try It?
You can run this EA on your demo account and tweak the parameters. If you're using MetaTrader 5, just paste the code into MetaEditor and compile. Let me know if you'd like a version with:
- Session filters (e.g., only trade Tokyo or London)
- Adjustable trailing stops
- AI-enhanced entry filters
Let’s keep evolving and improving — this is how we go from simple logic to real results.