The moving average crossover is one of the most classic and widely used trading strategies. This MQL4 EA source code implements a fully functional forex robot that enters long when a fast MA crosses above a slow MA, and short when it crosses below. With built-in money management, time filters, and trailing stops, this EA is production-ready for live trading or backtesting.
Strategy Logic
Complete MQL4 Source Code
```cpp
//+------------------------------------------------------------------+
//| MovingAverage_Crossover_EA.mq4 |
//| Generated by AutoCompile AI |
//| |
//+------------------------------------------------------------------+
#property copyright "AutoCompile AI"
#property link ""
#property version "1.00"
#property strict
//--- Input Parameters: Moving Averages
input int FastMAPeriod = 10; // Fast MA Period
input int SlowMAPeriod = 30; // Slow MA Period
input int MAShift = 0; // MA Shift
input ENUM_MA_METHOD MAMethod = MODE_SMA; // MA Method: SMA, EMA, etc.
input ENUM_APPLIED_PRICE MAPrice = PRICE_CLOSE; // Applied Price
//--- Input Parameters: Money Management
input double FixedLotSize = 0.1; // Fixed Lot Size (if UseMoneyManagement=false)
input bool UseMoneyManagement = true; // Use Auto Lot Size based on risk
input double RiskPercent = 2.0; // Risk % of account per trade
input int StopLossPips = 50; // Stop Loss in pips
input int TakeProfitPips = 150; // Take Profit in pips
//--- Input Parameters: Trade Filters
input bool UseTimeFilter = false; // Only trade during specific hours
input int StartHour = 8; // Trading start hour (server time)
input int EndHour = 17; // Trading end hour
input int MaxSpread = 30; // Maximum allowed spread in points
input int Slippage = 20; // Slippage for order execution
//--- Input Parameters: Trailing Stop
input bool UseTrailingStop = true; // Enable trailing stop
input int TrailStartPips = 20; // Trailing activates after this profit (pips)
input int TrailStepPips = 10; // Trail distance in pips
//--- Global variables
double fastMA[], slowMA[];
int magicNumber = 202510;
string comment = "MA_Crossover";
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
if(FastMAPeriod >= SlowMAPeriod)
{
Print("Error: Fast MA period must be less than Slow MA period");
return(INIT_FAILED);
}
Print("Moving Average Crossover EA initialized successfully");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Print("EA removed from chart. Reason code: ", reason);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//--- Check if market is open and spread condition
if(!IsTradeAllowed()) return;
if(MarketInfo(Symbol(), MODE_SPREAD) > MaxSpread * Point) return;
//--- Time filter
if(UseTimeFilter)
{
datetime now = TimeCurrent();
int currentHour = TimeHour(now);
if(currentHour < StartHour || currentHour >= EndHour) return;
}
//--- Get MA values
int barsToCopy = SlowMAPeriod + 5;
ArraySetAsSeries(fastMA, true);
ArraySetAsSeries(slowMA, true);
if(CopyBuffer(iMA(Symbol(), 0, FastMAPeriod, MAShift, MAMethod, MAPrice), 0, 0, barsToCopy, fastMA) < barsToCopy) return;
if(CopyBuffer(iMA(Symbol(), 0, SlowMAPeriod, MAShift, MAMethod, MAPrice), 0, 0, barsToCopy, slowMA) < barsToCopy) return;
//--- Check for existing positions
int buyCount = 0, sellCount = 0;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == magicNumber)
{
if(OrderType() == OP_BUY) buyCount++;
if(OrderType() == OP_SELL) sellCount++;
}
}
}
//--- Crossover detection
bool fastAboveSlow = (fastMA[1] > slowMA[1]);
bool fastBelowSlow = (fastMA[1] < slowMA[1]);
bool prevFastAboveSlow = (fastMA[2] > slowMA[2]);
bool prevFastBelowSlow = (fastMA[2] < slowMA[2]);
bool buySignal = (prevFastBelowSlow && fastAboveSlow);
bool sellSignal = (prevFastAboveSlow && fastBelowSlow);
//--- Calculate lot size
double lot = FixedLotSize;
if(UseMoneyManagement)
{
double riskMoney = AccountBalance() * RiskPercent / 100.0;
double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
double stopLossPoints = StopLossPips * 10;
lot = riskMoney / (stopLossPoints * tickValue);
lot = NormalizeDouble(lot, 2);
double minLot = MarketInfo(Symbol(), MODE_MINLOT);
double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
if(lot < minLot) lot = minLot;
if(lot > maxLot) lot = maxLot;
}
//--- Entry logic
if(buySignal && buyCount == 0)
{
double entryPrice = Ask;
double sl = entryPrice - StopLossPips * 10 * Point;
double tp = entryPrice + TakeProfitPips * 10 * Point;
int ticket = OrderSend(Symbol(), OP_BUY, lot, entryPrice, Slippage, sl, tp, comment, magicNumber, 0, clrGreen);
if(ticket > 0)
Print("Buy order opened. Ticket: ", ticket);
else
Print("Buy order failed. Error: ", GetLastError());
}
else if(sellSignal && sellCount == 0)
{
double entryPrice = Bid;
double sl = entryPrice + StopLossPips * 10 * Point;
double tp = entryPrice - TakeProfitPips * 10 * Point;
int ticket = OrderSend(Symbol(), OP_SELL, lot, entryPrice, Slippage, sl, tp, comment, magicNumber, 0, clrRed);
if(ticket > 0)
Print("Sell order opened. Ticket: ", ticket);
else
Print("Sell order failed. Error: ", GetLastError());
}
//--- Trailing stop management
if(UseTrailingStop)
{
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == magicNumber)
{
if(OrderType() == OP_BUY)
{
double profitPips = (Bid - OrderOpenPrice()) / Point;
if(profitPips > TrailStartPips * 10)
{
double newSL = Bid - TrailStepPips * 10 * Point;
if(newSL > OrderStopLoss())
OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrBlue);
}
}
else if(OrderType() == OP_SELL)
{
double profitPips = (OrderOpenPrice() - Ask) / Point;
if(profitPips > TrailStartPips * 10)
{
double newSL = Ask + TrailStepPips * 10 * Point;
if(newSL < OrderStopLoss() || OrderStopLoss() == 0)
OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrBlue);
}
}
}
}
}
}
}
//+------------------------------------------------------------------+
```
How to Compile and Test
1. Save as `MovingAverage_Crossover_EA.mq4` in `Experts` folder.
2. Compile in MetaEditor (F7) – no errors expected.
3. Run backtest in Strategy Tester (Ctrl+R) with EURUSD, H1 timeframe.
4. Optimize MA periods and risk settings for different pairs.
Parameter Explanation
| Parameter | Description |
|-----------|-------------|
| FastMAPeriod / SlowMAPeriod | Crossover speed. Typical values: 10 and 30, 5 and 20, 20 and 50 |
| UseMoneyManagement / RiskPercent | Auto lot sizing based on account percentage risk |
| StopLossPips / TakeProfitPips | Fixed SL/TP in pips |
| UseTrailingStop / TrailStartPips | Trailing activates after defined profit |
| MaxSpread | Prevents trading during high spread conditions |
| UseTimeFilter | Restrict trading to specific server hours |
Backtest Recommendations
This free EA download serves as an excellent starting point for EA programming entry. Modify the MQL4 code to add RSI filters, news filters, or multi-timeframe confirmation. For a complete automated trading suite with AI optimization, check our premium Forex AI EA – subscribe for weekly advanced strategies.
Reference: AutoCompile AI - Original MQL4 EA implementation based on classic crossover strategy, 2025.