Summary: This article provides complete MQL4 source code of a moving average crossover EA, including usage instructions and parameter explanation. Perfect for beginners learning automated trading.




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:
  • Two moving averages (fast and slow)

  • Configurable periods, methods, and apply-to prices

  • Built-in money management (fixed lot or risk percent)

  • Simple trailing stop and take profit / stop loss


  • 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 + TakeProfit
    Point : 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 - TakeProfit
    Point : 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:
  • Always backtest before live trading. Use Visual Mode in Strategy Tester.

  • This EA works on any timeframe, but H1 or M15 is recommended for MA crossovers.

  • Ensure your broker allows expert advisors and has no restrictions on stop levels.


  • 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.