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

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:
| Metric | Target | Why It Matters |
|---|---|---|
| Profit Factor | > 1.5 | Raw edge strength |
| Max Drawdown | < 15% | Account survivability |
| Recovery Factor | > 3.0 | Profit relative to worst case |
| Sharpe Ratio | > 1.0 | Risk-adjusted return |
| Total Trades | > 200 | Statistical significance |
| Consecutive Losses | Know the number | Live 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:
| Option | Monthly Cost | Latency to Most Brokers | Best For |
|---|---|---|---|
| Contabo VPS (Germany) | $5โ$8 | 10โ40ms | Swing/trend strategies |
| MetaQuotes MT5 VPS | $15โ$30 | Lowest (same data center) | Scalping |
| DigitalOcean/Vultr | $6โ$12 | 10โ30ms | Flexible, 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
About the Author
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.
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
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.