Back to Blog

How to Build a Profitable MT5 Expert Advisor in MQL5

Most traders who approach us about EA development have already tried one of two things: bought a commercial EA that stopped working after three months, or hired a cheap developer on Fiverr who delivered something that passed the backtest but blew up

Viprasol Tech Team
March 1, 2026
9 min read

How to Build a Profitable MT5 Expert Advisor in MQL5 | Viprasol Tech

How to Build a Profitable MT5 Expert Advisor in MQL5

By Viprasol Tech Team | Trading Software Development


Most traders who approach us about EA development have already tried one of two things: bought a commercial EA that stopped working after three months, or hired a cheap developer on Fiverr who delivered something that passed the backtest but blew up live. Both experiences share the same root cause โ€” the EA was built without understanding how MT5 actually executes code, evaluates risk, or interacts with a broker's infrastructure.

We've built over 100 trading systems on MT4 and MT5. This guide distills what we've learned about building EAs that don't just look good in a backtest but actually survive and profit in live markets.


What an MT5 Expert Advisor Actually Does

An Expert Advisor is compiled .ex5 code attached to a chart that runs on every incoming tick. It reads market data, evaluates conditions, and executes orders โ€” mechanically, without emotion, 24 hours a day. According to MetaQuotes' official documentation, the three primary execution functions are OnInit(), OnTick(), and OnDeinit() โ€” and almost every EA bug we've fixed traces back to a misunderstanding of when and how these fire.

The difference between a good EA and a bad one isn't the entry signal. It's everything else: position sizing, drawdown controls, order execution logic, and what happens when the broker returns an error.


Start With Strategy Documentation, Not Code

Before writing a single line of MQL5, document your strategy in plain language. This is something we enforce with every client before beginning development. A proper strategy spec covers:

Entry conditions โ€” specific and testable, not vague. Not "buy when RSI is oversold." Instead: "Enter long when RSI(14) crosses above 30 AND price is above EMA(200) AND the previous candle's body is at least 10 pips. Market order only."

Exit conditions โ€” fixed TP/SL, trailing stop, ATR-based stop, or time-based exit. Decide this upfront; retrofitting exits onto a coded EA causes more bugs than almost anything else.

Filters โ€” time of day, day of week, spread limits, news windows. One client came to us after three months of losses; the fix was adding a single spread filter. Their EA was entering during low-liquidity Asian session hours when spreads ballooned.

Position sizing method โ€” fixed lot, fixed risk percentage, or volatility-scaled. This single decision determines whether your account survives a drawdown.


๐Ÿค– Can This Strategy Be Automated?

In 2026, top traders run custom EAs โ€” not manual charts. We build MT4/MT5 Expert Advisors that execute your exact strategy 24/7, pass prop firm challenges, and eliminate emotional decisions.

  • Runs 24/7 โ€” no screen time, no missed entries
  • Prop-firm compliant (FTMO, MFF, TFT drawdown rules)
  • MyFXBook-verified backtest results included
  • From strategy brief to live EA in 2โ€“4 weeks

The MQL5 File Structure

Every MT5 EA follows the same skeleton. Here's a clean starting point with the structure we use across all projects:

//--- Input Parameters
input double RiskPercent  = 1.0;   // Risk per trade (% of balance)
input int    StopLossPips = 50;
input int    MAPeriod     = 20;
input int    MagicNumber  = 12345;

//--- Global Variables
int          maHandle;
double       maBuffer[];
CTrade       trade;

int OnInit()
{
   maHandle = iMA(_Symbol, _Period, MAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   if(maHandle == INVALID_HANDLE)
   {
      Print("Failed to create MA handle");
      return INIT_FAILED;
   }
   ArraySetAsSeries(maBuffer, true);
   trade.SetExpertMagicNumber(MagicNumber);
   trade.SetDeviationInPoints(10);
   return INIT_SUCCEEDED;
}

void OnDeinit(const int reason)
{
   IndicatorRelease(maHandle);
}

void OnTick()
{
   if(!IsNewBar()) return;    // Only act on confirmed bar closes
   if(IsDailyLossBreached()) return;
   CheckEntry();
}

Two things worth highlighting here. First, we always validate the indicator handle in OnInit() โ€” MetaTrader can fail to create handles under certain conditions, and an EA that silently continues with INVALID_HANDLE will either crash or trade on garbage data. Second, the IsNewBar() check means the EA only runs logic on bar closes, not on every tick. This eliminates an entire class of false signals that appear on the current forming candle and disappear when it closes.


Building the Signal Logic

Here's a real-world signal function from an EMA crossover strategy we built for a swing trader. The key detail is using buffer index 1 (the confirmed previous bar), not index 0 (the still-forming current bar):

bool CheckLongSignal()
{
   double ema50[3], ema200[3];
   
   if(CopyBuffer(ema50Handle,  0, 1, 3, ema50)  < 3) return false;
   if(CopyBuffer(ema200Handle, 0, 1, 3, ema200) < 3) return false;
   
   // Confirmed crossover on completed candles
   bool crossUp     = (ema50[1] < ema200[1]) && (ema50[0] > ema200[0]);
   bool aboveTrend  = (SymbolInfoDouble(_Symbol, SYMBOL_ASK) > ema200[0]);
   
   return (crossUp && aboveTrend);
}

This looks simple. The non-obvious complexity is in what happens around this signal โ€” what the EA does if there's already an open position, how it handles re-entry after a stop-out, whether it can take multiple simultaneous positions. These are the design decisions that separate a working EA from one that "works in testing."


๐Ÿ“ˆ Stop Trading Manually โ€” Let AI Do It

While you sleep, your EA keeps working. Viprasol builds prop-firm-compliant Expert Advisors with strict risk management, real backtests, and live deployment support.

  • No rule violations โ€” daily drawdown, max drawdown, consistency rules built in
  • Covers MT4, MT5, cTrader, and Python-based algos
  • 5.0โ˜… Upwork record โ€” 100% job success rate
  • Free strategy consultation before we write a single line

Order Execution: The Right Way

MT5's CTrade class from the standard library handles execution cleanly and safely. Here's a buy function with ATR-based stops โ€” the approach we use for most trend-following clients because it adapts to current market volatility rather than using a fixed pip count:

void OpenBuy()
{
   double atr[1];
   if(CopyBuffer(atrHandle, 0, 1, 1, atr) < 1) return;
   
   double ask        = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double sl         = NormalizeDouble(ask - atr[0] * 1.5, _Digits);
   double tp         = NormalizeDouble(ask + atr[0] * 3.0, _Digits);
   double lots       = CalculateLotSize(atr[0] * 1.5 / _Point);
   
   if(lots <= 0) return;
   
   if(!trade.Buy(lots, _Symbol, ask, sl, tp, "EMA Cross v2"))
      Print("Buy failed: ", trade.ResultRetcodeDescription());
}

The SetDeviationInPoints(10) call in OnInit() is the maximum slippage we'll accept. For a scalper that might need to be 3โ€“5 points; for a swing trader on daily bars, 20โ€“30 points is fine. Without this, the EA will fill at whatever price the broker offers โ€” which during news spikes can be 30+ pips away from your intended entry.


Risk Management: Where Most EAs Fail

The signal logic is usually the easiest part of an EA to build. Risk management is where projects get difficult โ€” and where most commercial EAs cut corners.

Fixed risk % position sizing calculates lot size based on how much of the account balance you're willing to lose on this trade's stop loss. The math has to account for the instrument's tick value, the account currency, and the broker's lot step:

double CalculateLotSize(double stopLossPoints)
{
   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 pointVal   = tickValue / tickSize;
   
   double lots       = riskAmount / (stopLossPoints * _Point * pointVal);
   double lotStep    = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   double minLot     = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double maxLot     = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   
   lots = MathRound(lots / lotStep) * lotStep;
   return MathMax(minLot, MathMin(maxLot, lots));
}

We've seen clients arrive with EAs that use fixed lot size regardless of stop distance. That means a 10-pip stop and a 100-pip stop get the same position size โ€” the EA is risking 10x more capital on the wider stop. Over enough trades, this asymmetry destroys accounts even when the win rate is acceptable.

Maximum drawdown kill switch โ€” especially critical for prop firm accounts:

bool IsDailyLossBreached()
{
   double startBal  = GetStartOfDayBalance();
   double equity    = AccountInfoDouble(ACCOUNT_EQUITY);
   double ddPercent = (startBal - equity) / startBal * 100.0;
   
   if(ddPercent >= MaxDailyDrawdown)
   {
      CloseAllPositions();
      Print("Daily loss limit hit: ", DoubleToString(ddPercent, 2), "%");
      return true;
   }
   return false;
}

Backtesting: What the Numbers Actually Mean

MT5's Strategy Tester is materially better than MT4's. The key mode is "Every Tick Based on Real Ticks" โ€” it uses actual historical tick data from MetaQuotes, so fills and stop-hit timing are realistic rather than simulated from bar data. For scalpers or any strategy where intrabar execution matters, this isn't optional.

Metrics we check on every backtest before showing a client results:

MetricTargetWhy It Matters
Profit Factor> 1.5Raw edge strength
Max Drawdown< 15%Account survivability
Recovery Factor> 3.0Profit relative to worst case
Sharpe Ratio> 1.0Risk-adjusted return
Total Trades> 200Statistical significance
Consecutive LossesKnow the numberLive psychological and capital impact

One number we always emphasize to clients: max consecutive losses. If the backtest shows 12 consecutive losses at some point, that will happen again live. Is your risk sizing survivable through 12 back-to-back losses? If the answer is "technically yes but I'd shut it down emotionally" โ€” reduce risk percentage until that's not a concern.

For a deeper look at avoiding overfitting in backtests, see this MQL5 article on walk-forward testing.


VPS Deployment

An EA needs to run 24/5. The VPS options we recommend for clients, in order of performance-to-cost:

OptionMonthly CostLatency to Most BrokersBest For
Contabo VPS (Germany)$5โ€“$810โ€“40msSwing/trend strategies
MetaQuotes MT5 VPS$15โ€“$30Lowest (same data center)Scalping
DigitalOcean/Vultr$6โ€“$1210โ€“30msFlexible, easy to manage

For most clients โ€” trend following, swing trading, grid strategies โ€” a $6/month Contabo VPS running Windows Server 2022 is entirely adequate. MetaTrader 5 runs comfortably on 2 vCPUs and 4 GB RAM even with 3โ€“4 EAs active.


What Ongoing Maintenance Looks Like

We tell every client: an EA is not a set-and-forget system. Markets change. What worked in Q1 may underperform in Q3. At minimum, a live EA needs:

  • Monthly review against live performance metrics vs. backtest expectations
  • Quarterly check on broker execution quality (spread, slippage drift)
  • Parameter re-evaluation every 6โ€“12 months on fresh out-of-sample data
  • Immediate review whenever the broker updates their MT5 server

One of our clients noticed their scalping EA's performance degrading over four months. The culprit wasn't the strategy โ€” it was the broker quietly widening average spreads on their target instruments. The fix was a spread filter that skips entry when current spread exceeds 1.5x the 30-day average. Performance recovered immediately.


Building With Viprasol

We develop MT5 EAs for traders at every level โ€” from individual prop firm participants to institutional desks running multi-currency baskets across managed accounts. Our trading software development service covers the full lifecycle: strategy spec, architecture, MQL5 development, backtesting with full walk-forward analysis, VPS setup, and ongoing support.

We also integrate AI signal filters for clients who want machine learning-enhanced entry logic โ€” a Python model running alongside the MQL5 EA via socket connection.

If you have a strategy and want to turn it into code, get a free consultation. We'll tell you upfront whether your strategy is codeable, what edge cases exist, and what a realistic development timeline looks like.


Summary

Building a profitable MT5 EA comes down to four things done right: a clearly documented strategy, robust risk management that survives drawdowns, a backtest methodology that doesn't lie to you, and ongoing maintenance after deployment. The signal logic โ€” the part everyone focuses on โ€” is actually the least differentiating factor.

The EAs that survive long term are the ones built with discipline at every stage. They're also usually the simpler ones.


See also: MT4 vs MT5 โ€” Which Platform Should Your EA Target? | Prop Firm EA Development Guide

Sources: MetaQuotes MQL5 Documentation ยท Investopedia โ€” Expert Advisor

Share this article:

About the Author

V

Viprasol Tech Team

Custom Software Development Specialists

The Viprasol Tech team specialises in algorithmic trading software, AI agent systems, and SaaS development. With 100+ projects delivered across MT4/MT5 EAs, fintech platforms, and production AI systems, the team brings deep technical experience to every engagement. Based in India, serving clients globally.

MT4/MT5 EA DevelopmentAI Agent SystemsSaaS DevelopmentAlgorithmic Trading

Ready to Automate Your Trading?

Get a custom Expert Advisor built by professionals with verified MyFXBook results.

Free consultation โ€ข No commitment โ€ข Response within 24 hours

Viprasol ยท Trading Software

Need a custom EA or trading bot built?

We specialise in MT4/MT5 Expert Advisor development โ€” prop-firm compliant, forward-tested before live, MyFXBook verifiable. 5.0โ˜… Upwork, 100% Job Success, 100+ projects shipped.