Introduction
When you’re studying this, you in all probability have a working MQL4 EA or indicator that it is advisable to port to MQL5. Possibly your dealer is phasing out MT4, possibly you need entry to MQL5’s higher backtesting, or possibly a consumer is paying you to transform their legacy code.
No matter your motive, I have been there. I’ve migrated dozens of EAs and indicators, and I can inform you: it is not a easy find-and-replace job. But it surely’s additionally not as scary because it seems.
This information provides you the sensible data I want I had after I began.
The Large Image: What Really Modified?
Earlier than diving into code, perceive the architectural shift:
MQL4: Easy and Direct
// Need the RSI? Simply name it. double rsi = iRSI(NULL, 0, 14, PRICE_CLOSE, 0); // Need to open a commerce? One perform. int ticket = OrderSend(Image(), OP_BUY, 0.1, Ask, 3, 0, 0);
MQL5: Deal with-Based mostly and Object-Oriented
// RSI requires a deal with (create as soon as, use many instances) int rsi_handle = iRSI(_Symbol, _Period, 14, PRICE_CLOSE); double rsi_buffer[]; ArraySetAsSeries(rsi_buffer, true); CopyBuffer(rsi_handle, 0, 0, 1, rsi_buffer); double rsi = rsi_buffer[0]; // Buying and selling makes use of the CTrade class #embody <TradeTrade.mqh> CTrade commerce; commerce.Purchase(0.1, _Symbol);
Why the change? Efficiency. MQL5’s deal with system lets the terminal cache indicator calculations. In MQL4, iRSI() recalculates each time you name it. In MQL5, you calculate as soon as and skim from reminiscence.
Step 1: The Entry Factors
That is the simple half. Discover and exchange:
| MQL4 | MQL5 | Notes |
|---|---|---|
| init() | OnInit() | Should return INIT_SUCCEEDED or INIT_FAILED |
| deinit() | OnDeinit(const int motive) | Now receives a motive code |
| begin() | OnTick() | For EAs |
| begin() | OnCalculate(…) | For indicators (completely different signature!) |
Frequent mistake: Forgetting that OnInit() should return an int. Your MQL4 init() that returned 0 must return INIT_SUCCEEDED.
int OnInit() { // Setup code… if(something_failed) return(INIT_FAILED); return(INIT_SUCCEEDED); }
Step 2: Add the Commerce Libraries
On the prime of your file, add:
#embody <TradeTrade.mqh> #embody <TradePositionInfo.mqh> #embody <TradeSymbolInfo.mqh>
Then declare international situations:
CTrade commerce; CPositionInfo place; CSymbolInfo symbol_info;
In OnInit():
commerce.SetExpertMagicNumber(MagicNumber); commerce.SetDeviationInPoints(10); symbol_info.Identify(_Symbol);
Step 3: Changing Order Features
That is the place most individuals battle. MQL5 separates orders (pending) from positions (open trades).
Opening Trades
MQL4:
int ticket = OrderSend(Image(), OP_BUY, 0.1, Ask, 3, sl, tp, “Remark”, Magic); if(ticket < 0) Print(“Error: “, GetLastError());
MQL5:
if(!commerce.Purchase(0.1, _Symbol, 0, sl, tp, "Remark"))
{
Print("Error: ", commerce.ResultRetcodeDescription());
}
Notice: In MQL5, passing 0 as worth means “use present market worth” — the category handles Ask/Bid robotically.
Closing Trades
MQL4:
OrderClose(ticket, OrderLots(), Bid, 3);
MQL5:
commerce.PositionClose(ticket);
Checking Open Positions
MQL4:
for(int i = OrdersTotal() – 1; i >= 0; i–) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { if(OrderSymbol() == Image() && OrderMagicNumber() == Magic) { // Discovered our place } } }
MQL5:
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(place.SelectByIndex(i))
{
if(place.Image() == _Symbol && place.Magic() == Magic)
{
// Discovered our place
}
}
}
Step 4: Changing Indicators
That is the largest psychological shift. Create handles as soon as, learn values many instances.
Instance: Shifting Common
MQL4:
double ma = iMA(NULL, 0, 20, 0, MODE_SMA, PRICE_CLOSE, 0); double ma_prev = iMA(NULL, 0, 20, 0, MODE_SMA, PRICE_CLOSE, 1);
MQL5:
// Declare at international degree
int ma_handle;
double ma_buffer[];
// In OnInit()
ma_handle = iMA(_Symbol, _Period, 20, 0, MODE_SMA, PRICE_CLOSE);
if(ma_handle == INVALID_HANDLE)
{
Print("Error creating MA deal with");
return(INIT_FAILED);
}
ArraySetAsSeries(ma_buffer, true);
// In OnTick()
if(CopyBuffer(ma_handle, 0, 0, 2, ma_buffer) < 2)
return; // Not sufficient knowledge
double ma = ma_buffer[0];
double ma_prev = ma_buffer[1];
// In OnDeinit() - IMPORTANT!
IndicatorRelease(ma_handle);
Why ArraySetAsSeries()? MQL5 arrays index from oldest to latest by default. Setting as collection flips it so index 0 is the present bar (like MQL4).
Step 5: Worth Knowledge
MQL4:
double shut = Shut[0]; double excessive = Excessive[1]; datetime time = Time[0];
MQL5:
double shut = iClose(_Symbol, _Period, 0); double excessive = iHigh(_Symbol, _Period, 1); datetime time = iTime(_Symbol, _Period, 0);
Or utilizing arrays:
double shut[], excessive[]; ArraySetAsSeries(shut, true); ArraySetAsSeries(excessive, true); CopyClose(_Symbol, _Period, 0, 10, shut); CopyHigh(_Symbol, _Period, 0, 10, excessive); // Now shut[0] is present bar, shut[1] is earlier, and many others.
Step 6: Account and Image Data
MQL4:
double steadiness = AccountBalance(); double fairness = AccountEquity(); double level = Level; int digits = Digits; double bid = Bid; double ask = Ask;
MQL5:
double steadiness = AccountInfoDouble(ACCOUNT_BALANCE); double fairness = AccountInfoDouble(ACCOUNT_EQUITY); double level = SymbolInfoDouble(_Symbol, SYMBOL_POINT); int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); // Or utilizing CSymbolInfo class: symbol_info.RefreshRates(); double bid = symbol_info.Bid(); double ask = symbol_info.Ask();
Frequent Pitfalls (Be taught from My Errors)
1. Forgetting to Launch Handles
Reminiscence leak alert! At all times launch indicator handles in OnDeinit():
void OnDeinit(const int motive)
{
IndicatorRelease(ma_handle);
IndicatorRelease(rsi_handle);
// and many others.
}
2. Arrays Not Set as Sequence
Your code seems proper however provides unsuitable values? Verify ArraySetAsSeries(). MQL5 arrays are “as collection” = false by default.
3. Bid/Ask Not Updating
symbol_info.Bid() returns cached values. Name symbol_info.RefreshRates() first, or use SymbolInfoDouble() immediately.
4. Place vs Order Confusion
- OrdersTotal() = pending orders solely
- PositionsTotal() = open positions solely
In MQL4, OrdersTotal() included each. In MQL5, they’re separate.
5. ENUM Modifications
Some enums modified names:
- OP_BUY → ORDER_TYPE_BUY (however commerce.Purchase() handles this)
- MODE_SMA → Identical identify, however verify the worth matches
- PRICE_CLOSE → Identical identify
Fast Reference Card
| Activity | MQL4 | MQL5 |
|---|---|---|
| Present bid | Bid | SymbolInfoDouble(_Symbol, SYMBOL_BID) |
| Present ask | Ask | SymbolInfoDouble(_Symbol, SYMBOL_ASK) |
| Level dimension | Level | SymbolInfoDouble(_Symbol, SYMBOL_POINT) |
| Digits | Digits | SymbolInfoInteger(_Symbol, SYMBOL_DIGITS) |
| Present shut | Shut[0] | iClose(_Symbol, _Period, 0) |
| Bar rely | Bars | Bars(_Symbol, _Period) |
| Open purchase | OrderSend(…, OP_BUY, …) | commerce.Purchase(…) |
| Shut place | OrderClose(ticket, …) | commerce.PositionClose(ticket) |
| Rely positions | OrdersTotal() | PositionsTotal() |
| Get MA worth | iMA(…, shift) | CopyBuffer(ma_handle, …) |
Migration Guidelines
- ☐ Rename init() → OnInit() (return INIT_SUCCEEDED)
- ☐ Rename deinit() → OnDeinit(const int motive)
- ☐ Rename begin() → OnTick() (EA) or OnCalculate() (indicator)
- ☐ Add #embody <TradeTrade.mqh> and mates
- ☐ Create CTrade commerce; international variable
- ☐ Set magic quantity in OnInit(): commerce.SetExpertMagicNumber(Magic)
- ☐ Convert all OrderSend() → commerce.Purchase()/Promote()
- ☐ Convert all OrderClose() → commerce.PositionClose()
- ☐ Convert order loops to place loops
- ☐ Convert indicators to handle-based system
- ☐ Add IndicatorRelease() calls in OnDeinit()
- ☐ Substitute Bid/Ask with SymbolInfoDouble()
- ☐ Substitute Shut[]/Excessive[]/and many others. with iClose()/iHigh()/and many others.
- ☐ Take a look at completely in Technique Tester
Remaining Ideas
MQL5 migration is not nearly making code compile — it is about understanding the brand new structure. When you internalize the handle-based indicator system and the position-based order administration, every little thing clicks.
The payoff is price it: quicker backtesting, cleaner code, higher debugging instruments, and entry to the rising MQL5 market.
Need assistance migrating your EA? Verify my GitHub portfolio for examples: https://github.com/jimmer89/mql5-portfolio
© 2026 Jaume Sancho. Free to make use of and share with attribution.