This article delivers a complete, compilable MQL4 Expert Advisor source code based on a multi-timeframe Moving Average Crossover strategy. The moving average crossover is one of the most classic and widely used trend-following strategies in forex trading. This EA enhances the traditional approach by adding a higher-timeframe trend filter to reduce false signals and improve trade accuracy.
The EA operates by calculating two moving averages (fast and slow) on the current chart timeframe and optionally verifying the trend direction using a third moving average on a higher timeframe. When the fast MA crosses above the slow MA and the higher timeframe trend is bullish, a buy order is triggered. Conversely, a sell signal is generated when the fast MA crosses below the slow MA with bearish higher-timeframe confirmation. This multi-timeframe confluence approach significantly improves the robustness of the strategy.
Key Features:
Below is the complete EA source code. Copy it into MetaEditor, compile, and attach it to your chart. Please ensure the "Allow DLL imports" option is enabled if needed (this EA does not require DLLs).
```mql4
//+------------------------------------------------------------------+
//| MA_Crossover_MTF_EA.mq4 |
//| Copyright 2025, ForexSourceLab |
//| https://www.example.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, ForexSourceLab"
#property link "https://www.example.com"
#property version "1.00"
#property strict
//+------------------------------------------------------------------+
//| Input Parameters |
//+------------------------------------------------------------------+
input int FastMAPeriod = 10; // Fast MA Period
input int SlowMAPeriod = 30; // Slow MA Period
input int SignalMAPeriod = 50; // Signal MA Period (for filter)
input int MA_Shift = 0; // MA Shift
input int MA_Method = MODE_SMA; // MA Method (0=SMA,1=EMA,2=SMMA,3=LWMA)
input int AppliedPrice = PRICE_CLOSE; // Applied Price
input bool UseHigherTF = true; // Enable Higher TF Filter
input ENUM_TIMEFRAMES HigherTF = PERIOD_H1; // Higher Timeframe
input double LotSize = 0.1; // Fixed Lot Size
input bool UseRiskManagement = false; // Use Risk % Management
input double RiskPercent = 2.0; // Risk % per Trade
input int StopLoss = 60; // Stop Loss in pips
input int TakeProfit = 120; // Take Profit in pips
input int BreakevenTrigger = 30; // Breakeven trigger in pips
input int BreakevenPips = 5; // Breakeven offset pips
input int MagicNumber = 202507; // EA Magic Number
input bool AllowBuy = true; // Allow Buy Trades
input bool AllowSell = true; // Allow Sell Trades
input int MaxOrders = 1; // Maximum concurrent orders
//+------------------------------------------------------------------+
//| Global Variables |
//+------------------------------------------------------------------+
datetime lastBarTime = 0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
if(FastMAPeriod <= 0 || SlowMAPeriod <= 0 || FastMAPeriod >= SlowMAPeriod)
return(INIT_PARAMETERS_INCORRECT);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Comment("");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- Check for new bar to avoid multiple signals per bar
if(Time[0] == lastBarTime) return;
lastBarTime = Time[0];
//--- Count current open orders
int totalOrders = CountTotalOrders(MagicNumber);
if(totalOrders >= MaxOrders) return;
//--- Calculate MA values on current timeframe
double fastMA_0 = iMA(NULL, 0, FastMAPeriod, MA_Shift, MA_Method, AppliedPrice, 0);
double fastMA_1 = iMA(NULL, 0, FastMAPeriod, MA_Shift, MA_Method, AppliedPrice, 1);
double slowMA_0 = iMA(NULL, 0, SlowMAPeriod, MA_Shift, MA_Method, AppliedPrice, 0);
double slowMA_1 = iMA(NULL, 0, SlowMAPeriod, MA_Shift, MA_Method, AppliedPrice, 1);
//--- Calculate signal MA on higher timeframe (if enabled)
bool higherTrendBull = true;
bool higherTrendBear = true;
if(UseHigherTF)
{
double signalMA_0 = iMA(NULL, HigherTF, SignalMAPeriod, MA_Shift, MA_Method, AppliedPrice, 0);
double signalMA_1 = iMA(NULL, HigherTF, SignalMAPeriod, MA_Shift, MA_Method, AppliedPrice, 1);
double signalMA_2 = iMA(NULL, HigherTF, SignalMAPeriod, MA_Shift, MA_Method, AppliedPrice, 2);
//--- Trend defined by slope of the signal MA
higherTrendBull = (signalMA_0 > signalMA_1 && signalMA_1 > signalMA_2);
higherTrendBear = (signalMA_0 < signalMA_1 && signalMA_1 < signalMA_2);
}
//--- Crossover detection: Bullish crossover
if(AllowBuy && higherTrendBull && fastMA_1 <= slowMA_1 && fastMA_0 > slowMA_0)
{
if(CountOrdersByType(MagicNumber, OP_BUY) == 0)
{
OpenOrder(OP_BUY);
}
}
//--- Crossover detection: Bearish crossover
if(AllowSell && higherTrendBear && fastMA_1 >= slowMA_1 && fastMA_0 < slowMA_0)
{
if(CountOrdersByType(MagicNumber, OP_SELL) == 0)
{
OpenOrder(OP_SELL);
}
}
//--- Trailing stop and breakeven management
ManageOrders();
}
//+------------------------------------------------------------------+
//| Open Order Function |
//+------------------------------------------------------------------+
void OpenOrder(int cmd)
{
double price = (cmd == OP_BUY) ? Ask : Bid;
double sl = 0, tp = 0;
//--- Calculate dynamic lot size if risk management is enabled
double tradeLot = LotSize;
if(UseRiskManagement)
{
double riskAmount = AccountBalance() * RiskPercent / 100.0;
double pipValue = MarketInfo(Symbol(), MODE_TICKVALUE);
double riskPips = StopLoss;
tradeLot = riskAmount / (riskPips * pipValue * 10);
tradeLot = MathMax(tradeLot, MarketInfo(Symbol(), MODE_MINLOT));
tradeLot = MathMin(tradeLot, MarketInfo(Symbol(), MODE_MAXLOT));
tradeLot = NormalizeDouble(tradeLot, 2);
}
if(StopLoss > 0)
{
sl = (cmd == OP_BUY) ? price - StopLoss * Point * 10 : price + StopLoss * Point * 10;
}
if(TakeProfit > 0)
{
tp = (cmd == OP_BUY) ? price + TakeProfit * Point * 10 : price - TakeProfit * Point * 10;
}
int ticket = OrderSend(Symbol(), cmd, tradeLot, price, 5, sl, tp, "MA Crossover EA", MagicNumber, 0, clrNONE);
if(ticket < 0)
{
Print("OrderSend failed with error #", GetLastError());
}
}
//+------------------------------------------------------------------+
//| Count Total Orders Function |
//+------------------------------------------------------------------+
int CountTotalOrders(int magic)
{
int count = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == magic)
{
count++;
}
}
}
return count;
}
//+------------------------------------------------------------------+
//| Count Orders By Type Function |
//+------------------------------------------------------------------+
int CountOrdersByType(int magic, int type)
{
int count = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == magic && OrderType() == type)
{
count++;
}
}
}
return count;
}
//+------------------------------------------------------------------+
//| Manage Orders (Breakeven & Trailing) |
//+------------------------------------------------------------------+
void ManageOrders()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
double openPrice = OrderOpenPrice();
double currentSL = OrderStopLoss();
if(OrderType() == OP_BUY)
{
//--- Breakeven logic
if(BreakevenTrigger > 0 && currentSL < openPrice)
{
if(Bid - openPrice >= BreakevenTrigger * Point * 10)
{
double newSL = openPrice + BreakevenPips * Point * 10;
if(newSL > currentSL)
{
if(!OrderModify(OrderTicket(), openPrice, newSL, OrderTakeProfit(), 0, clrNONE))
Print("Breakeven modify error: ", GetLastError());
}
}
}
}
else if(OrderType() == OP_SELL)
{
//--- Breakeven logic
if(BreakevenTrigger > 0 && (currentSL > openPrice || currentSL == 0))
{
if(openPrice - Ask >= BreakevenTrigger * Point * 10)
{
double newSL = openPrice - BreakevenPips * Point * 10;
if(newSL < currentSL || currentSL == 0)
{
if(!OrderModify(OrderTicket(), openPrice, newSL, OrderTakeProfit(), 0, clrNONE))
Print("Breakeven modify error: ", GetLastError());
}
}
}
}
}
}
}
}
//+------------------------------------------------------------------+
//| Expert tick function end |
//+------------------------------------------------------------------+
```
Usage Instructions:
1. Open MetaEditor (F4) in MetaTrader 4.
2. Create a new Expert Advisor and paste the entire code.
3. Compile the code (F7) and check for any compilation errors.
4. Attach the EA to a currency pair chart of your choice.
5. Configure the input parameters in the "Inputs" tab according to your trading preferences.
6. Enable "Allow live trading" and ensure the AutoTrading button on the MT4 toolbar is active.
Parameter Explanation:
Enhancement Ideas:
To customize this EA further, consider adding:
This EA serves as an excellent foundation for understanding how to build a multi-timeframe strategy in MQL4. Always conduct thorough backtesting and forward testing on a demo account before applying it to live funds.
If you need more sophisticated EAs with advanced features such as AI-based entry filtering, multi-currency portfolio management, and dedicated support, we invite you to explore our premium EA collection, designed to meet the needs of serious traders.
Reference: Self-compiled based on standard MQL4 moving average crossover logic and multi-timeframe filtering techniques.