MQL4 to MQL5 Migration: A Sensible Information from the Trenches
Introduction
For those who’re studying this, you most likely have a working MQL4 EA or indicator that you have to port to MQL5. Perhaps your dealer is phasing out MT4, possibly you need entry to MQL5’s higher backtesting, or possibly a shopper is paying you to transform their legacy code.
No matter your purpose, I have been there. I’ve migrated dozens of EAs and indicators, and I can let you know: it is not a easy find-and-replace job. Nevertheless it’s additionally not as scary because it appears to be like.
This information offers you the sensible information I want I had after I began.
The Massive Image: What Truly 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); // Wish to open a commerce? One perform. int ticket = OrderSend(Image(), OP_BUY, 0.1, Ask, 3, 0, 0);
MQL5: Deal with-Primarily based and Object-Oriented
// RSI requires a deal with (create as soon as, use many occasions) 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 #embrace 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 straightforward half. Discover and exchange:
| MQL4 | MQL5 | Notes |
|---|---|---|
| init() | onInit() | Should return INIT_SUCCEEDED or INIT_FAILED |
| deinit() | OnDeinit(const int purpose) | Now receives a purpose 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:
#embrace #embrace #embrace
Then declare world situations:
CTrade commerce; CPositionInfo place; CSymbolInfo symbol_info;
In OnInit():
commerce.SetExpertMagicNumber(MagicNumber); commerce.SetDeviationInPoints(10); symbol_info.Title(_Symbol);
Step 3: Changing Order Features
That is the place most individuals wrestle. 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());
}
Word: 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 most important psychological shift. Create handles as soon as, learn values many occasions.
Instance: Transferring 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 world stage
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 information
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 sequence flips it so index 0 is the present bar (like MQL4).
Step 5: Value Information
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 so forth.
Step 6: Account and Image Information
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! All the time launch indicator handles in OnDeinit():
void OnDeinit(const int purpose)
{
IndicatorRelease(ma_handle);
IndicatorRelease(rsi_handle);
// and so forth.
}
2. Arrays Not Set as Collection
Your code appears to be like proper however offers improper values? Examine ArraySetAsSeries(). MQL5 arrays are “as sequence” = false by default.
3. Bid/Ask Not Updating
symbol_info.Bid() returns cached values. Name symbol_info.RefreshRates() first, or use SymbolInfoDouble() instantly.
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 → Similar identify, however test the worth matches
- PRICE_CLOSE → Similar identify
Fast Reference Card
| Activity | MQL4 | MQL5 |
|---|---|---|
| Present bid | Bid | SymbolInfoDouble(_Symbol, SYMBOL_BID) |
| Present ask | Ask | SymbolInfoDouble(_Symbol, SYMBOL_ASK) |
| Level measurement | 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) |
| Depend positions | OrdersTotal() | PositionsTotal() |
| Get MA worth | iMA(…, shift) | CopyBuffer(ma_handle, …) |
Migration Guidelines
- ☐ Rename init() → OnInit() (return INIT_SUCCEEDED)
- ☐ Rename deinit() → OnDeinit(const int purpose)
- ☐ Rename begin() → OnTick() (EA) or OnCalculate() (indicator)
- ☐ Add #embrace and mates
- ☐ Create CTrade commerce; world 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 so forth. with iClose()/iHigh()/and so forth.
- ☐ Check totally in Technique Tester
Ultimate 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, all the pieces clicks.
The payoff is value it: sooner backtesting, cleaner code, higher debugging instruments, and entry to the rising MQL5 market.
Need assistance migrating your EA? Examine my GitHub portfolio for examples: https://github.com/jimmer89/mql5-portfolio
© 2026 Jaume Sancho. Free to make use of and share with attribution.