Summary: This article provides a complete MQL4 EA source code based on double moving average crossover strategy. Includes trade filters, trailing stop, risk management, and detailed parameter explanations for beginners to learn EA programming.




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


  • Buy Signal: Fast MA (e.g., 10) crosses above Slow MA (e.g., 30)

  • Sell Signal: Fast MA crosses below Slow MA

  • Exit: Opposite crossover or trailing stop


  • 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


  • Best Timeframe: H1 or H4 (reduces false signals)

  • Recommended Pairs: EURUSD, GBPUSD, AUDUSD (trending pairs)

  • Minimum Testing Period: 6 months


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