This article shares a complete Moving Average Crossover Expert Advisor (EA) for MetaTrader 4 (MT4). The EA generates buy/sell signals when a fast moving average crosses above or below a slow moving average. It is ideal for learning EA programming basics and can be compiled directly in MetaEditor.
Key Features:
Complete MQL4 Source Code:
``
cpp
//+------------------------------------------------------------------+
//| MACrossoverEA.mq4 |
//| Copyright 2025, AutoTrader |
//| https://www.example.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, AutoTrader"
#property link "https://www.example.com"
#property version "1.00"
#property strict
//--- input parameters
input double LotSize = 0.1; // Fixed lot size
input bool UseRiskPercent = false; // Use risk percent instead of fixed lot
input double RiskPercent = 2.0; // Risk % of balance per trade
input int FastMAPeriod = 5; // Fast MA period
input int SlowMAPeriod = 20; // Slow MA period
input int MAMethod = MODE_SMA; // MA method: 0=SMA,1=EMA,2=SMMA,3=LWMA
input int MAPrice = PRICE_CLOSE; // Apply to price
input int MagicNumber = 12345; // EA identifier
input int Slippage = 3; // Slippage in points
input int StopLoss = 300; // Stop loss in points (0 = disabled)
input int TakeProfit = 600; // Take profit in points (0 = disabled)
input int TrailingStop = 200; // Trailing stop points (0 = disabled)
//--- global variables
double fastMA, slowMA;
int ticket;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
if(FastMAPeriod >= SlowMAPeriod)
{
Print("Error: Fast MA period must be less than Slow MA period");
return(INIT_PARAMETERS_INCORRECT);
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Calculate MA values
fastMA = iMA(Symbol(), PERIOD_CURRENT, FastMAPeriod, 0, MAMethod, MAPrice, 1);
slowMA = iMA(Symbol(), PERIOD_CURRENT, SlowMAPeriod, 0, MAMethod, MAPrice, 1);
double fastMA_prev = iMA(Symbol(), PERIOD_CURRENT, FastMAPeriod, 0, MAMethod, MAPrice, 2);
double slowMA_prev = iMA(Symbol(), PERIOD_CURRENT, SlowMAPeriod, 0, MAMethod, MAPrice, 2);
// Check for existing position
if(CountPositions() == 0)
{
// Buy signal: fast crosses above slow
if(fastMA_prev <= slowMA_prev && fastMA > slowMA)
{
double lot = CalculateLotSize();
ticket = OrderSend(Symbol(), OP_BUY, lot, Ask, Slippage,
StopLoss>0 ? Ask - StopLossPoint : 0,
TakeProfit>0 ? Ask + TakeProfitPoint : 0,
"MA Cross Buy", MagicNumber, 0, clrGreen);
if(ticket < 0) Print("Buy order failed: ", GetLastError());
}
// Sell signal: fast crosses below slow
else if(fastMA_prev >= slowMA_prev && fastMA < slowMA)
{
double lot = CalculateLotSize();
ticket = OrderSend(Symbol(), OP_SELL, lot, Bid, Slippage,
StopLoss>0 ? Bid + StopLossPoint : 0,
TakeProfit>0 ? Bid - TakeProfitPoint : 0,
"MA Cross Sell", MagicNumber, 0, clrRed);
if(ticket < 0) Print("Sell order failed: ", GetLastError());
}
}
else
{
// Trailing stop management
if(TrailingStop > 0) TrailingStopLoss();
}
}
//+------------------------------------------------------------------+
//| Count open positions with MagicNumber |
//+------------------------------------------------------------------+
int CountPositions()
{
int count = 0;
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
count++;
}
}
return count;
}
//+------------------------------------------------------------------+
//| Calculate lot size based on risk percent |
//+------------------------------------------------------------------+
double CalculateLotSize()
{
if(!UseRiskPercent) return LotSize;
double balance = AccountBalance();
double riskMoney = balance RiskPercent / 100.0;
double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
double stopPoints = StopLoss;
if(stopPoints <= 0) return LotSize;
double lot = riskMoney / (stopPoints 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;
return lot;
}
//+------------------------------------------------------------------+
//| Trailing stop loss function |
//+------------------------------------------------------------------+
void TrailingStopLoss()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
if(OrderType() == OP_BUY)
{
double newSL = Bid - TrailingStop Point;
if(OrderStopLoss() < newSL - Point)
if(!OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrBlue))
Print("Trailing stop modify failed: ", GetLastError());
}
else if(OrderType() == OP_SELL)
{
double newSL = Ask + TrailingStop Point;
if(OrderStopLoss() > newSL + Point || OrderStopLoss() == 0)
if(!OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrBlue))
Print("Trailing stop modify failed: ", GetLastError());
}
}
}
}
}
//+------------------------------------------------------------------+
`
Usage Instructions:
Copy the code into MetaEditor (MT4: Tools → MetaQuotes Language Editor).
Save the file as MACrossoverEA.mq4.
Compile (F7) and fix any errors if present.
Attach the EA to a chart in MT4 (Navigator → Expert Advisors → drag onto chart).
Adjust input parameters according to your risk preference.
Parameter Explanation:
LotSize: Base lot size when risk management is off.
UseRiskPercent: If true, calculates lot based on RiskPercent and StopLoss.
RiskPercent: Percentage of balance to risk per trade.
FastMAPeriod & SlowMAPeriod: Lengths of two moving averages. Fast must be smaller.
MAMethod: 0=SMA,1=EMA,2=SMMA,3=LWMA.
MAPrice: Price constant (0=close,1=open,2=high,3=low,4=median,5=typical,6=weighted).
StopLoss/TakeProfit: Distance in points from entry.
TrailingStop`: Activates trailing stop if >0.Important Notes:
Reference: Autocompiled by ForexEA Studio, 2025. Original design based on classic moving average crossover strategy.
For more advanced EA strategies, premium indicators, and professional automation tools, kindly check our Premium EA Collection – updated monthly with verified source code and dedicated support. Click "Subscribe" in the sidebar to access the latest releases.