MQL5 Automated Trading Strategy: Hub Guide to All EA Types
This hub page covers the full spectrum of MQL5 automated trading strategies, from trend-following and mean-reversion EAs to grid, scalping, and multi-timeframe systems. Whether you are building your first Expert Advisor or scaling a professional trading robot, this guide maps every EA archetype to its core logic and MQL5 implementation pattern.
Strategy Logic
Entry Conditions
Entry logic varies by EA archetype: trend EAs enter on moving average crossovers or breakouts confirmed by momentum indicators such as MACD or ADX; mean-reversion EAs enter when price deviates beyond a Bollinger Band or RSI extreme. Grid and scalping EAs place orders at fixed price intervals or on micro-structure signals like spread compression and tick velocity.
Exit Conditions
Exit logic is equally archetype-specific: trend EAs close on counter-signal or trailing stop breach; mean-reversion EAs target a fixed return-to-mean distance with a hard stop beyond the outer band. Grid systems close the full basket when cumulative profit reaches a threshold, while scalping EAs use tight fixed take-profit and stop-loss levels measured in points.
MQL5 Expert Advisor Code
//+------------------------------------------------------------------+
//| MQL5 Automated Trading Hub — Dual MA Crossover EA |
//| Demonstrates the canonical OnInit / OnTick / OnDeinit pattern |
//| suitable as a starting template for any trend-following EA. |
//| |
//| DISCLAIMER: For educational purposes only. Past performance |
//| does not guarantee future results. Always test on a demo account.|
//+------------------------------------------------------------------+
#property copyright "Pineify.app"
#property version "1.00"
#property strict
//--- Input parameters
input int FastMAPeriod = 20; // Fast MA period
input int SlowMAPeriod = 50; // Slow MA period
input ENUM_MA_METHOD MAMethod = MODE_EMA; // MA smoothing method
input double LotSize = 0.10; // Trade volume in lots
input int StopLossPips = 80; // Stop-loss in pips
input int TakeProfitPips = 160; // Take-profit in pips
input int MagicNumber = 20240001; // Unique EA identifier
input string TradeComment = "HubEA"; // Order comment
//--- Global handles and state
int g_fastHandle = INVALID_HANDLE;
int g_slowHandle = INVALID_HANDLE;
double g_pipSize = 0.0;
bool g_tradeAllowed = false;
//+------------------------------------------------------------------+
//| Expert initialisation |
//+------------------------------------------------------------------+
int OnInit()
{
//--- Validate periods
if(FastMAPeriod >= SlowMAPeriod)
{
Print("ERROR: FastMAPeriod must be less than SlowMAPeriod.");
return(INIT_PARAMETERS_INCORRECT);
}
//--- Create indicator handles
g_fastHandle = iMA(_Symbol, PERIOD_CURRENT, FastMAPeriod, 0, MAMethod, PRICE_CLOSE);
g_slowHandle = iMA(_Symbol, PERIOD_CURRENT, SlowMAPeriod, 0, MAMethod, PRICE_CLOSE);
if(g_fastHandle == INVALID_HANDLE || g_slowHandle == INVALID_HANDLE)
{
Print("ERROR: Failed to create MA handles.");
return(INIT_FAILED);
}
//--- Calculate pip size (handles 3/5-digit brokers)
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
g_pipSize = (digits == 3 || digits == 5)
? SymbolInfoDouble(_Symbol, SYMBOL_POINT) * 10.0
: SymbolInfoDouble(_Symbol, SYMBOL_POINT);
g_tradeAllowed = true;
Print("Hub EA initialised on ", _Symbol, " | FastMA=", FastMAPeriod, " SlowMA=", SlowMAPeriod);
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick handler |
//+------------------------------------------------------------------+
void OnTick()
{
if(!g_tradeAllowed) return;
//--- Only act on the close of a new bar to avoid multiple entries
static datetime s_lastBarTime = 0;
datetime currentBarTime = (datetime)SeriesInfoInteger(_Symbol, PERIOD_CURRENT, SERIES_LASTBAR_DATE);
if(currentBarTime == s_lastBarTime) return;
s_lastBarTime = currentBarTime;
//--- Copy MA buffers (need 2 values to detect crossover)
double fastMA[], slowMA[];
ArraySetAsSeries(fastMA, true);
ArraySetAsSeries(slowMA, true);
if(CopyBuffer(g_fastHandle, 0, 0, 3, fastMA) < 3) return;
if(CopyBuffer(g_slowHandle, 0, 0, 3, slowMA) < 3) return;
//--- Detect crossover
bool bullCross = (fastMA[1] > slowMA[1]) && (fastMA[2] <= slowMA[2]);
bool bearCross = (fastMA[1] < slowMA[1]) && (fastMA[2] >= slowMA[2]);
//--- Count existing positions for this EA
int buyCount = CountPositions(POSITION_TYPE_BUY);
int sellCount = CountPositions(POSITION_TYPE_SELL);
//--- Close opposite positions on crossover before opening new one
if(bullCross && sellCount > 0) CloseAllPositions(POSITION_TYPE_SELL);
if(bearCross && buyCount > 0) CloseAllPositions(POSITION_TYPE_BUY);
//--- Open new position if none exists in signal direction
if(bullCross && buyCount == 0)
OpenPosition(ORDER_TYPE_BUY);
else if(bearCross && sellCount == 0)
OpenPosition(ORDER_TYPE_SELL);
}
//+------------------------------------------------------------------+
//| Expert deinitialization |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(g_fastHandle != INVALID_HANDLE) IndicatorRelease(g_fastHandle);
if(g_slowHandle != INVALID_HANDLE) IndicatorRelease(g_slowHandle);
g_tradeAllowed = false;
PrintFormat("Hub EA removed. Reason code: %d", reason);
}
//+------------------------------------------------------------------+
//| Open a buy or sell position with SL/TP |
//+------------------------------------------------------------------+
void OpenPosition(ENUM_ORDER_TYPE orderType)
{
MqlTradeRequest request = {};
MqlTradeResult result = {};
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double sl, tp;
if(orderType == ORDER_TYPE_BUY)
{
sl = NormalizeDouble(ask - StopLossPips * g_pipSize, _Digits);
tp = NormalizeDouble(ask + TakeProfitPips * g_pipSize, _Digits);
request.price = ask;
}
else
{
sl = NormalizeDouble(bid + StopLossPips * g_pipSize, _Digits);
tp = NormalizeDouble(bid - TakeProfitPips * g_pipSize, _Digits);
request.price = bid;
}
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = LotSize;
request.type = orderType;
request.sl = sl;
request.tp = tp;
request.magic = MagicNumber;
request.comment = TradeComment;
request.type_filling = ORDER_FILLING_IOC;
if(!OrderSend(request, result))
PrintFormat("OrderSend failed. Error: %d | Retcode: %d", GetLastError(), result.retcode);
else
PrintFormat("Position opened: %s | Ticket: %d | Price: %.5f | SL: %.5f | TP: %.5f",
EnumToString(orderType), result.order, result.price, sl, tp);
}
//+------------------------------------------------------------------+
//| Count open positions by direction for this EA |
//+------------------------------------------------------------------+
int CountPositions(ENUM_POSITION_TYPE posType)
{
int count = 0;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if((long)PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == posType)
count++;
}
return count;
}
//+------------------------------------------------------------------+
//| Close all positions of a given direction for this EA |
//+------------------------------------------------------------------+
void CloseAllPositions(ENUM_POSITION_TYPE posType)
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
ulong ticket = PositionGetTicket(i);
if(ticket == 0) continue;
if(PositionGetString(POSITION_SYMBOL) != _Symbol) continue;
if((long)PositionGetInteger(POSITION_MAGIC) != MagicNumber) continue;
if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) != posType) continue;
MqlTradeRequest request = {};
MqlTradeResult result = {};
request.action = TRADE_ACTION_DEAL;
request.symbol = _Symbol;
request.volume = PositionGetDouble(POSITION_VOLUME);
request.type = (posType == POSITION_TYPE_BUY) ? ORDER_TYPE_SELL : ORDER_TYPE_BUY;
request.price = (posType == POSITION_TYPE_BUY)
? SymbolInfoDouble(_Symbol, SYMBOL_BID)
: SymbolInfoDouble(_Symbol, SYMBOL_ASK);
request.position = ticket;
request.magic = MagicNumber;
request.comment = TradeComment + "_close";
request.type_filling = ORDER_FILLING_IOC;
if(!OrderSend(request, result))
PrintFormat("Close failed for ticket %d. Error: %d", ticket, GetLastError());
}
}
//+------------------------------------------------------------------+Copy this code into MetaEditor (F4 in MT5), save in the Experts folder, and compile with F7.
Generate a Custom Multi-pair Hub 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.