Complete .mq5 source code

MQL5 Expert Advisor Free Download: Best Free EA Code & Templates

This page provides free MQL5 Expert Advisor source code and downloadable templates that traders can use as a foundation for building automated trading systems on MetaTrader 5. Whether you are a beginner looking for a working EA skeleton or an experienced developer seeking a clean multi-pair template, the examples here follow MQL5 5.x best practices using trade request structs and indicator handle patterns.

Strategy logic

Entry conditions

The example EA enters a long position when the fast EMA crosses above the slow EMA and the RSI is below the overbought threshold, ensuring momentum confirmation before committing capital. A short position is triggered on the inverse crossover with RSI above the oversold threshold. All signals are evaluated on the close of the current bar to avoid look-ahead bias during live trading.

Exit conditions

Positions are closed when the EMA cross reverses direction, providing a dynamic exit that adapts to changing market conditions without relying on fixed take-profit levels alone. A hard stop-loss expressed in points is placed at order open time via the MqlTradeRequest struct, acting as a safety net against gap-and-go adverse moves. An optional trailing stop can be activated through an input parameter to lock in profits as the trade moves favorably.

MQL5 Expert Advisor Code

//+------------------------------------------------------------------+
//|  FreeEA_MultiPair.mq5                                            |
//|  A free MQL5 Expert Advisor template using EMA cross + RSI       |
//|  For educational purposes only. Not financial advice.            |
//+------------------------------------------------------------------+
#property copyright "Pineify - pineify.app"
#property link      "https://pineify.app"
#property version   "1.00"
#property strict

#include <Trade\Trade.mqh>

//--- Input parameters
input int    FastEmaPeriod   = 10;       // Fast EMA period
input int    SlowEmaPeriod   = 30;       // Slow EMA period
input int    RsiPeriod       = 14;       // RSI period
input double RsiOverbought   = 70.0;     // RSI overbought level
input double RsiOversold     = 30.0;     // RSI oversold level
input double LotSize         = 0.10;     // Trade lot size
input int    StopLossPoints  = 500;      // Stop loss in points
input int    TakeProfitPoints = 1000;    // Take profit in points
input bool   UseTrailingStop = true;     // Enable trailing stop
input int    TrailingPoints  = 300;      // Trailing stop distance in points
input ulong  MagicNumber     = 20240001; // EA magic number

//--- Global handles and objects
int    g_handleFastEma = INVALID_HANDLE;
int    g_handleSlowEma = INVALID_HANDLE;
int    g_handleRsi     = INVALID_HANDLE;
CTrade g_trade;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- Create indicator handles
   g_handleFastEma = iMA(_Symbol, PERIOD_CURRENT, FastEmaPeriod, 0, MODE_EMA, PRICE_CLOSE);
   g_handleSlowEma = iMA(_Symbol, PERIOD_CURRENT, SlowEmaPeriod, 0, MODE_EMA, PRICE_CLOSE);
   g_handleRsi     = iRSI(_Symbol, PERIOD_CURRENT, RsiPeriod, PRICE_CLOSE);

   if(g_handleFastEma == INVALID_HANDLE ||
      g_handleSlowEma == INVALID_HANDLE ||
      g_handleRsi     == INVALID_HANDLE)
     {
      Print("ERROR: Failed to create indicator handles. EA cannot start.");
      return(INIT_FAILED);
     }

   //--- Configure trade object
   g_trade.SetExpertMagicNumber(MagicNumber);
   g_trade.SetDeviationInPoints(10);
   g_trade.SetTypeFilling(ORDER_FILLING_FOK);

   Print("FreeEA_MultiPair initialized on ", _Symbol,
         " | Fast EMA:", FastEmaPeriod,
         " | Slow EMA:", SlowEmaPeriod,
         " | RSI:", RsiPeriod);
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   //--- Release indicator handles to free memory
   if(g_handleFastEma != INVALID_HANDLE) IndicatorRelease(g_handleFastEma);
   if(g_handleSlowEma != INVALID_HANDLE) IndicatorRelease(g_handleSlowEma);
   if(g_handleRsi     != INVALID_HANDLE) IndicatorRelease(g_handleRsi);

   Print("FreeEA_MultiPair deinitialized. Reason code: ", reason);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   //--- Only act on a new bar to avoid multiple signals per candle
   static datetime s_lastBarTime = 0;
   datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
   if(currentBarTime == s_lastBarTime) return;
   s_lastBarTime = currentBarTime;

   //--- Copy indicator buffers (index 1 = previous closed bar)
   double fastEma[2], slowEma[2], rsi[2];
   if(CopyBuffer(g_handleFastEma, 0, 0, 2, fastEma) < 2) return;
   if(CopyBuffer(g_handleSlowEma, 0, 0, 2, slowEma) < 2) return;
   if(CopyBuffer(g_handleRsi,     0, 0, 2, rsi)     < 2) return;

   //--- Determine cross direction on the last completed bar
   bool emaBullishCross = (fastEma[1] > slowEma[1]) && (fastEma[0] <= slowEma[0]);  // prev crossed above
   bool emaBearishCross = (fastEma[1] < slowEma[1]) && (fastEma[0] >= slowEma[0]);  // prev crossed below

   // Note: index 1 is the most recently closed bar
   bool emaBullCurrent  = fastEma[1] > slowEma[1];
   bool emaBearCurrent  = fastEma[1] < slowEma[1];

   double rsiValue = rsi[1];

   //--- Trailing stop management for open positions
   if(UseTrailingStop)
      ManageTrailingStop();

   //--- Check if we already hold a position for this symbol + magic
   bool hasLong  = HasPosition(POSITION_TYPE_BUY);
   bool hasShort = HasPosition(POSITION_TYPE_SELL);

   //--- Entry logic: EMA cross confirmed by RSI filter
   if(!hasLong && !hasShort)
     {
      if(emaBullCurrent && rsiValue < RsiOverbought)
        {
         OpenBuy();
        }
      else if(emaBearCurrent && rsiValue > RsiOversold)
        {
         OpenSell();
        }
     }

   //--- Exit logic: close on opposing cross
   if(hasLong && emaBearishCross)
      ClosePositions(POSITION_TYPE_BUY);

   if(hasShort && emaBullishCross)
      ClosePositions(POSITION_TYPE_SELL);
  }

//+------------------------------------------------------------------+
//| Open a BUY position                                              |
//+------------------------------------------------------------------+
void OpenBuy()
  {
   double ask        = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double point      = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   double sl         = ask - StopLossPoints   * point;
   double tp         = ask + TakeProfitPoints * point;

   sl = NormalizeDouble(sl, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
   tp = NormalizeDouble(tp, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));

   if(!g_trade.Buy(LotSize, _Symbol, ask, sl, tp, "FreeEA Buy"))
      Print("Buy order failed. Error: ", GetLastError());
   else
      Print("Buy opened at ", ask, " SL:", sl, " TP:", tp);
  }

//+------------------------------------------------------------------+
//| Open a SELL position                                             |
//+------------------------------------------------------------------+
void OpenSell()
  {
   double bid        = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double point      = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   double sl         = bid + StopLossPoints   * point;
   double tp         = bid - TakeProfitPoints * point;

   sl = NormalizeDouble(sl, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));
   tp = NormalizeDouble(tp, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS));

   if(!g_trade.Sell(LotSize, _Symbol, bid, sl, tp, "FreeEA Sell"))
      Print("Sell order failed. Error: ", GetLastError());
   else
      Print("Sell opened at ", bid, " SL:", sl, " TP:", tp);
  }

//+------------------------------------------------------------------+
//| Close all positions of given type for this symbol               |
//+------------------------------------------------------------------+
void ClosePositions(ENUM_POSITION_TYPE posType)
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      ulong ticket = PositionGetTicket(i);
      if(PositionSelectByTicket(ticket))
        {
         if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
            PositionGetInteger(POSITION_MAGIC)  == (long)MagicNumber &&
            (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == posType)
           {
            g_trade.PositionClose(ticket);
           }
        }
     }
  }

//+------------------------------------------------------------------+
//| Check if a position of given type exists                        |
//+------------------------------------------------------------------+
bool HasPosition(ENUM_POSITION_TYPE posType)
  {
   for(int i = 0; i < PositionsTotal(); i++)
     {
      ulong ticket = PositionGetTicket(i);
      if(PositionSelectByTicket(ticket))
        {
         if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
            PositionGetInteger(POSITION_MAGIC)  == (long)MagicNumber &&
            (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == posType)
            return true;
        }
     }
   return false;
  }

//+------------------------------------------------------------------+
//| Manage trailing stop for open positions                         |
//+------------------------------------------------------------------+
void ManageTrailingStop()
  {
   double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   int    digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);

   for(int i = 0; i < PositionsTotal(); i++)
     {
      ulong ticket = PositionGetTicket(i);
      if(!PositionSelectByTicket(ticket)) continue;
      if(PositionGetString(POSITION_SYMBOL) != _Symbol)      continue;
      if(PositionGetInteger(POSITION_MAGIC) != (long)MagicNumber) continue;

      ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
      double currentSL = PositionGetDouble(POSITION_SL);
      double newSL     = 0.0;

      if(type == POSITION_TYPE_BUY)
        {
         double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
         newSL = NormalizeDouble(bid - TrailingPoints * point, digits);
         if(newSL > currentSL + point)
            g_trade.PositionModify(ticket, newSL, PositionGetDouble(POSITION_TP));
        }
      else if(type == POSITION_TYPE_SELL)
        {
         double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
         newSL = NormalizeDouble(ask + TrailingPoints * point, digits);
         if(newSL < currentSL - point || currentSL == 0.0)
            g_trade.PositionModify(ticket, newSL, PositionGetDouble(POSITION_TP));
        }
     }
  }
//+------------------------------------------------------------------+

Copy this code into MetaEditor, save it in the MQL5/Experts folder, and compile with F7.

Generate a custom Multi-pair resource EA

Describe the ATR inputs, alert rules, visual style, or confirmation filter you want. Pineify generates editable MQL5 source code that you can inspect and compile in MetaEditor.

Pine Script vs MQL5: Same Strategy, Different Platforms

AspectPine Script (TradingView)MQL5 (MetaTrader 5)
ExecutionSeries evaluated on chart updatesEvent handlers with explicit buffers
DeploymentRuns in TradingView with alertsRuns in the MT5 terminal or on a VPS
Broker accessVia TradingView broker integrationDirect broker connectivity
BacktestingStrategy Tester for strategy scriptsStrategy Tester for Expert Advisors
Code complexitySimpler, functional syntaxC++-like, more powerful

The calculation can be implemented on either platform, but the runtime model and buffer APIs differ. Read the Pine Script Supertrend reference before porting logic between them.

Frequently Asked Questions

Related MQL5 pages

Risk and testing note

Past performance is not indicative of future results. Backtest statistics are based on historical data and do not guarantee future profits. Trading involves significant risk of loss. This content is for educational purposes only and does not constitute financial advice.