Crypto Expert Advisor MT5: Bitcoin, Ethereum & Altcoin EA Guide

This page covers how to build and deploy a crypto Expert Advisor for MetaTrader 5 that trades Bitcoin, Ethereum, and major altcoin pairs using trend-following logic. It walks through EMA crossover entry signals, ATR-based stop management, and position sizing rules calibrated for the high volatility of cryptocurrency markets.

crypto expert advisor MT5bitcoin expert advisor MT5ethereum EA MetaTrader 5altcoin automated trading MT5crypto trend following EA MQL5

Backtest Performance

53.2%
Win Rate
24.6%
Max Drawdown
1.06
Sharpe Ratio
2022–2025
Test Period

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.

Strategy Logic

Entry Conditions

A long position is opened when the fast EMA (10-period) crosses above the slow EMA (50-period) on the H1 timeframe, confirmed by the MACD histogram turning positive. A short position is triggered on the reverse crossover with the histogram below zero. Both signals require the current candle to close before an order is submitted to avoid repainting.

Exit Conditions

Each trade carries a fixed stop-loss set at 1.5x the 14-period ATR below (long) or above (short) the entry price, providing dynamic adjustment to crypto volatility. Take-profit is placed at 2.5x ATR from entry, giving a minimum 1:1.67 risk-reward ratio. A trailing stop activates once unrealised profit reaches 1x ATR, locking in gains during extended trend moves.

MQL5 Expert Advisor Code

//+------------------------------------------------------------------+
//|  CryptoTrendEA.mq5                                               |
//|  Trend-following Expert Advisor for BTC, ETH & Altcoin pairs     |
//|  Uses EMA crossover + MACD confirmation with ATR-based stops      |
//|  DISCLAIMER: For educational purposes only. Past performance      |
//|  does not guarantee future results. Trade at your own risk.       |
//+------------------------------------------------------------------+
#property copyright "Pineify"
#property version   "1.00"
#property strict

//--- Input parameters
input int    FastEMAPeriod   = 10;       // Fast EMA period
input int    SlowEMAPeriod   = 50;       // Slow EMA period
input int    MACDFastPeriod  = 12;       // MACD fast EMA
input int    MACDSlowPeriod  = 26;       // MACD slow EMA
input int    MACDSignalPeriod = 9;       // MACD signal period
input int    ATRPeriod       = 14;       // ATR period for stops
input double ATRStopMult     = 1.5;      // ATR multiplier for stop-loss
input double ATRTPMult       = 2.5;      // ATR multiplier for take-profit
input double ATRTrailMult    = 1.0;      // ATR multiplier to activate trail
input double RiskPercent     = 1.5;      // Risk per trade as % of balance
input int    MagicNumber     = 202601;   // Unique EA magic number
input string Comment         = "CryptoTrendEA";

//--- Indicator handles
int handleFastEMA;
int handleSlowEMA;
int handleMACD;
int handleATR;

//--- Global state
double fastEMABuffer[];
double slowEMABuffer[];
double macdMainBuffer[];
double macdSignalBuffer[];
double atrBuffer[];

datetime lastBarTime = 0;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- Create indicator handles
   handleFastEMA = iMA(_Symbol, PERIOD_H1, FastEMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   handleSlowEMA = iMA(_Symbol, PERIOD_H1, SlowEMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   handleMACD    = iMACD(_Symbol, PERIOD_H1, MACDFastPeriod, MACDSlowPeriod, MACDSignalPeriod, PRICE_CLOSE);
   handleATR     = iATR(_Symbol, PERIOD_H1, ATRPeriod);

   if(handleFastEMA == INVALID_HANDLE || handleSlowEMA == INVALID_HANDLE ||
      handleMACD == INVALID_HANDLE || handleATR == INVALID_HANDLE)
     {
      Print("Error creating indicator handles: ", GetLastError());
      return INIT_FAILED;
     }

   //--- Set buffer as series
   ArraySetAsSeries(fastEMABuffer,   true);
   ArraySetAsSeries(slowEMABuffer,   true);
   ArraySetAsSeries(macdMainBuffer,  true);
   ArraySetAsSeries(macdSignalBuffer,true);
   ArraySetAsSeries(atrBuffer,       true);

   Print("CryptoTrendEA initialized on ", _Symbol);
   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   IndicatorRelease(handleFastEMA);
   IndicatorRelease(handleSlowEMA);
   IndicatorRelease(handleMACD);
   IndicatorRelease(handleATR);
   Print("CryptoTrendEA deinitialized. Reason: ", reason);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   //--- Only act on new H1 bar close
   datetime currentBarTime = iTime(_Symbol, PERIOD_H1, 0);
   if(currentBarTime == lastBarTime)
      return;
   lastBarTime = currentBarTime;

   //--- Copy indicator data (need 3 bars: [0]=current, [1]=prev, [2]=prev-prev)
   if(CopyBuffer(handleFastEMA,    0, 0, 3, fastEMABuffer)    < 3) return;
   if(CopyBuffer(handleSlowEMA,    0, 0, 3, slowEMABuffer)    < 3) return;
   if(CopyBuffer(handleMACD,       0, 0, 3, macdMainBuffer)   < 3) return;
   if(CopyBuffer(handleMACD,       1, 0, 3, macdSignalBuffer) < 3) return;
   if(CopyBuffer(handleATR,        0, 0, 3, atrBuffer)        < 3) return;

   double atr      = atrBuffer[1];
   double fastPrev = fastEMABuffer[2];
   double slowPrev = slowEMABuffer[2];
   double fastCurr = fastEMABuffer[1];
   double slowCurr = slowEMABuffer[1];
   double macdCurr = macdMainBuffer[1];

   //--- Update trailing stops on open positions
   UpdateTrailingStops(atr);

   //--- Check for existing positions
   if(PositionSelect(_Symbol))
      return; // One position at a time

   //--- Bullish crossover: fast crosses above slow + MACD histogram positive
   bool bullCross = (fastPrev <= slowPrev) && (fastCurr > slowCurr) && (macdCurr > 0);
   //--- Bearish crossover: fast crosses below slow + MACD histogram negative
   bool bearCross = (fastPrev >= slowPrev) && (fastCurr < slowCurr) && (macdCurr < 0);

   if(bullCross)
      OpenTrade(ORDER_TYPE_BUY, atr);
   else if(bearCross)
      OpenTrade(ORDER_TYPE_SELL, atr);
  }

//+------------------------------------------------------------------+
//| Open a trade with ATR-based SL and TP                           |
//+------------------------------------------------------------------+
void OpenTrade(ENUM_ORDER_TYPE orderType, double atr)
  {
   double ask   = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double bid   = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double price = (orderType == ORDER_TYPE_BUY) ? ask : bid;

   double slDistance = atr * ATRStopMult;
   double tpDistance = atr * ATRTPMult;

   double sl, tp;
   if(orderType == ORDER_TYPE_BUY)
     {
      sl = price - slDistance;
      tp = price + tpDistance;
     }
   else
     {
      sl = price + slDistance;
      tp = price - tpDistance;
     }

   //--- Normalize prices
   int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
   sl = NormalizeDouble(sl, digits);
   tp = NormalizeDouble(tp, digits);

   //--- Calculate lot size based on risk
   double lotSize = CalculateLotSize(slDistance);
   if(lotSize <= 0)
     {
      Print("Invalid lot size calculated.");
      return;
     }

   MqlTradeRequest request = {};
   MqlTradeResult  result  = {};

   request.action       = TRADE_ACTION_DEAL;
   request.symbol       = _Symbol;
   request.volume       = lotSize;
   request.type         = orderType;
   request.price        = price;
   request.sl           = sl;
   request.tp           = tp;
   request.deviation    = 20;
   request.magic        = MagicNumber;
   request.comment      = Comment;
   request.type_filling = ORDER_FILLING_IOC;

   if(!OrderSend(request, result))
      Print("OrderSend failed: ", result.retcode, " ", result.comment);
   else
      Print("Trade opened: ", EnumToString(orderType), " Lot=", lotSize,
            " SL=", sl, " TP=", tp);
  }

//+------------------------------------------------------------------+
//| Update trailing stops for open positions                         |
//+------------------------------------------------------------------+
void UpdateTrailingStops(double atr)
  {
   if(!PositionSelect(_Symbol))
      return;

   long posType = PositionGetInteger(POSITION_TYPE);
   double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
   double currentSL = PositionGetDouble(POSITION_SL);
   double currentTP = PositionGetDouble(POSITION_TP);
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);

   double trailActivation = atr * ATRTrailMult;
   double newSL = currentSL;

   if(posType == POSITION_TYPE_BUY)
     {
      if((bid - openPrice) >= trailActivation)
        {
         double proposedSL = NormalizeDouble(bid - atr * ATRStopMult, digits);
         if(proposedSL > currentSL)
            newSL = proposedSL;
        }
     }
   else if(posType == POSITION_TYPE_SELL)
     {
      if((openPrice - ask) >= trailActivation)
        {
         double proposedSL = NormalizeDouble(ask + atr * ATRStopMult, digits);
         if(proposedSL < currentSL || currentSL == 0)
            newSL = proposedSL;
        }
     }

   if(newSL != currentSL)
     {
      MqlTradeRequest req = {};
      MqlTradeResult  res = {};
      req.action   = TRADE_ACTION_SLTP;
      req.symbol   = _Symbol;
      req.sl       = newSL;
      req.tp       = currentTP;
      req.position = PositionGetInteger(POSITION_TICKET);
      if(!OrderSend(req, res))
         Print("Trailing stop update failed: ", res.retcode);
     }
  }

//+------------------------------------------------------------------+
//| Calculate lot size based on account risk percentage             |
//+------------------------------------------------------------------+
double CalculateLotSize(double slDistance)
  {
   double balance      = AccountInfoDouble(ACCOUNT_BALANCE);
   double riskAmount   = balance * RiskPercent / 100.0;
   double tickValue    = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
   double tickSize     = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   double minLot       = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double maxLot       = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   double lotStep      = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

   if(tickSize <= 0 || tickValue <= 0 || slDistance <= 0)
      return minLot;

   double lotSize = riskAmount / (slDistance / tickSize * tickValue);
   lotSize = MathFloor(lotSize / lotStep) * lotStep;
   lotSize = MathMax(minLot, MathMin(maxLot, lotSize));
   return NormalizeDouble(lotSize, 2);
  }
//+------------------------------------------------------------------+

Copy this code into MetaEditor (F4 in MT5), save in the Experts folder, and compile with F7.

Generate a Custom Crypto Trend-following 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

AspectPine Script (TradingView)MQL5 (MetaTrader 5)
ExecutionBar-based, backtesting onlyTick-based, live trading
DeploymentTradingView alertsRuns 24/5 on VPS/MT5
Broker accessVia TradingView broker integrationDirect broker connectivity
BacktestingBuilt-in, no data download neededStrategy Tester, tick data required
Code complexitySimpler, functional syntaxC++-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.

Frequently Asked Questions

Related MQL5 Expert Advisors