HomeSample Page

Sample Page Title


MQL4 to MQL5 Migration: A Sensible Information from the Trenches

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:

MQL4MQL5Notes
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

ActivityMQL4MQL5
Present bidBidSymbolInfoDouble(_Symbol, SYMBOL_BID)
Present askAskSymbolInfoDouble(_Symbol, SYMBOL_ASK)
Level dimensionLevelSymbolInfoDouble(_Symbol, SYMBOL_POINT)
DigitsDigitsSymbolInfoInteger(_Symbol, SYMBOL_DIGITS)
Present shutShut[0]iClose(_Symbol, _Period, 0)
Bar relyBarsBars(_Symbol, _Period)
Open purchaseOrderSend(…, OP_BUY, …)commerce.Purchase(…)
Shut placeOrderClose(ticket, …)commerce.PositionClose(ticket)
Rely positionsOrdersTotal()PositionsTotal()
Get MA worthiMA(…, 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.

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles