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 (F4 in MT5), save in the Experts folder, and compile with F7.
Generate a Custom Multi-pair Resource EA →
Pineify AI generates syntactically validated MQL5 Expert Advisors from plain English descriptions. Customize entry logic, risk management, and trading sessions — no coding required.
Pine Script vs MQL5: Same Strategy, Different Platforms
| Aspect | Pine Script (TradingView) | MQL5 (MetaTrader 5) |
|---|---|---|
| Execution | Bar-based, backtesting only | Tick-based, live trading |
| Deployment | TradingView alerts | Runs 24/5 on VPS/MT5 |
| Broker access | Via TradingView broker integration | Direct broker connectivity |
| Backtesting | Built-in, no data download needed | Strategy Tester, tick data required |
| Code complexity | Simpler, functional syntax | C++-like, more powerful |
Pineify supports both platforms. Prototype your strategy visually in TradingView Pine Script, then generate the equivalent MQL5 EA for live MT5 trading.