FX NOOKAI CODE LAB
Loading

MQL4 to MQL5 Conversion Guide: Code, APIs, Testing

By FXNook Lab team

Developer reviewing code notes at a desk while preparing an MT4-to-MT5 migration

MQL4 code is not a drop-in replacement for MQL5. Converting it means adapting how the program places and tracks trades, reads indicator values, and handles account and market data. Start by documenting the EA’s rules, then convert each API area and verify both compilation and runtime behavior in MT5.

A rename-only port often compiles only after substantial edits, and a clean compile still does not prove the EA trades as intended. MT5 distinguishes positions, pending orders, and deals; its built-in indicators return handles; and a netting account can behave differently from an MT4-style hedging setup. The sections below give you a practical code-level reference for those changes.

What changes when you move MQL4 code to MQL5

The largest changes are in the trading model and indicator access. MQL4 trade functions work with orders and commonly return a ticket. In MQL5, trade requests create or modify orders, positions, and deals through a different API. Indicator functions such as iMA return a handle in MQL5; you retrieve values from that handle with CopyBuffer.

MQL4 patternMQL5 patternWhat to account for
OrderSend, OrderClose, OrderSelectCTrade or MqlTradeRequest; position, order, and history APIsA trade ticket is not always the same thing as a current position.
iMA(..., shift) returns a valueiMA(...) creates a handle; CopyBuffer reads valuesCreate handles once, check them, and release them.
Orders commonly represent open tradesPositions represent exposure; orders can be pending or active requests; deals are executionsDecide which entity each management rule must inspect.
MarketInfo, predefined price variablesSymbolInfoDouble, symbol properties, and explicit data accessCheck the correct symbol’s price, volume, and trading constraints.
MT4 event functionsShared event names plus MT5-specific events such as OnTradeTransactionMatch the handler to the program type and the event being handled.

These differences are why a line-by-line replacement is not enough. Before changing code, identify what each function is responsible for in the strategy, then decide which MQL5 entity or API represents the same intent.

Inventory the EA or indicator before converting it

Write down the behavior before you edit the source. That gives you a reference for checking whether the port preserved the strategy, and it helps separate a conversion error from a behavior difference that comes from MT5 or the broker.

  1. Record entry and exit rules. Note the exact signal conditions, the bar or tick on which they are checked, and whether the EA can open more than one trade in a direction.
  2. List inputs and defaults. Include lot sizing, stop-loss and take-profit rules, magic numbers, spread filters, and any switches that change behavior.
  3. List symbols and timeframes. Record whether the EA trades only the chart symbol or reads other symbols and periods as well.
  4. Map indicators and buffers. Note every built-in or custom indicator, its parameters, the buffer used, and the shift read by the original code.
  5. Describe order management. Include entry, modification, partial close, trailing stop, break-even, and close-all logic. Record how the EA identifies its own trades.
  6. Write down broker assumptions. Check lot minimum and step, stop-distance rules, execution and filling behavior, symbol suffixes, and whether the account is netting or hedging.

This inventory matters most when the EA has several open trades or uses ticket-based management. For example, an MT4 loop that selects every order and modifies matching tickets cannot be translated safely until you know whether it is managing pending orders, open exposure, or both.

Replace MQL4 trade calls with MQL5 trade logic

A typical MQL4 market entry uses OrderSend and receives a ticket number when the call succeeds. The example below is an MQL4 EA code fragment; it assumes the order parameters are suitable for the account and symbol.

int ticket = OrderSend(Symbol(), OP_BUY, 0.10, Ask, 3, 0, 0,
                       "MQL4 example", 12345, 0, clrBlue);
if(ticket < 0)
   Print("OrderSend failed: ", GetLastError());

In MQL5, the CTrade class is a common way to send market trades. Include the trade library and check the result code as well as the method’s Boolean return value. A true return means the request passed the class’s basic checks; inspecting the server retcode tells you whether the trade was executed or otherwise accepted.

#include <Trade/Trade.mqh>

CTrade trade;

bool SendBuy()
{
   if(!trade.Buy(0.10, _Symbol, 0.0, 0.0, 0.0, "MQL5 example"))
   {
      Print("Buy request failed. Retcode=", trade.ResultRetcode(),
            " ", trade.ResultRetcodeDescription());
      return false;
   }

   uint code = trade.ResultRetcode();
   if(code != TRADE_RETCODE_DONE &&
      code != TRADE_RETCODE_DONE_PARTIAL)
   {
      Print("Buy was not fully executed. Retcode=", code,
            " ", trade.ResultRetcodeDescription());
      return false;
   }

   return true;
}

The example intentionally leaves stop-loss and take-profit values at zero. Add the EA’s actual exit rules rather than assuming the sample values are appropriate. In production code, also account for the symbol’s allowed volume, price precision, stop distance, and permitted filling mode.

You can also use the lower-level MqlTradeRequest and MqlTradeResult structures with OrderSend. That gives you explicit control over request fields, but it does not remove the need to inspect result.retcode. A successful function call alone does not necessarily mean a requested market action has been filled.

Keep the three MT5 concepts separate. A position is current market exposure, an order is an instruction such as a pending order, and a deal records an execution. A strategy that closes an MT4 order by ticket may need different logic in MT5 to select and close a position, especially if it must also handle pending orders or execution history.

On a hedging account, multiple positions can exist for one symbol. On a netting account, exposure for a symbol is represented by a single net position. An EA written around several independent MT4 tickets may therefore need a deliberate redesign for netting rather than a mechanical conversion. See the official MQL5 CTrade reference for the class methods and result accessors.

Convert indicator calls and buffer access

In MQL4, a call such as iMA can return the moving-average value for a requested shift directly. In MQL5, the corresponding call creates an indicator handle. Read its output buffer separately, and check that the handle is valid and that the requested number of values was copied.

// MQL4: read the moving average value at shift 1.
double ma = iMA(NULL, 0, 14, 0, MODE_SMA, PRICE_CLOSE, 1);

Here is the equivalent access pattern for an MQL5 EA. The handle is created during initialization, buffer zero is read at shift one, and the handle is released when the EA is removed.

int maHandle = INVALID_HANDLE;

int OnInit()
{
   maHandle = iMA(_Symbol, _Period, 14, 0, MODE_SMA, PRICE_CLOSE);
   if(maHandle == INVALID_HANDLE)
   {
      Print("iMA handle creation failed: ", GetLastError());
      return INIT_FAILED;
   }
   return INIT_SUCCEEDED;
}

void OnTick()
{
   double ma[1];
   if(CopyBuffer(maHandle, 0, 1, 1, ma) != 1)
   {
      Print("CopyBuffer failed: ", GetLastError());
      return;
   }

   Print("MA at shift 1: ", ma[0]);
}

void OnDeinit(const int reason)
{
   if(maHandle != INVALID_HANDLE)
      IndicatorRelease(maHandle);
}

The arguments to CopyBuffer specify the handle, buffer number, starting position, number of values, and destination array. Here, buffer zero is the moving average’s output, and start position one requests the previous bar rather than the current bar. Check the requested count before using the array: indicator data may not be ready yet, or the request may fail.

Apply the same pattern to iRSI, iCustom, and other MQL5 indicators that return handles. For a custom indicator, confirm the buffer number and parameter order against that indicator’s source or documentation. Mixing up a buffer index or bar shift can produce a valid number that represents the wrong signal, so the compiler will not necessarily catch the mistake. See the official CopyBuffer documentation for details.

Adapt event handlers, data types, and account logic

Many familiar event names exist in both languages, but a shared name does not mean the full program model is identical. Check the handler signature and responsibilities, then review all code that selects trades or reads prices.

AreaMT4MT5 conversion point
EA initialization and ticksOnInit and OnTickThese are also used by MT5 EAs. Create indicator handles in initialization and validate them there.
Indicator calculationsIndicator code commonly uses start or OnCalculateUse the MT5 OnCalculate signature and check its array and calculation conventions.
Trade selectionOrderSelect and order propertiesSelect positions, active orders, or history records according to what the logic needs; do not treat them as interchangeable.
Trade changesOrderClose, OrderModifyUse the appropriate position or order operation, commonly through CTrade or trade requests.
Price and symbol propertiesMarketInfo, Bid, AskUse symbol properties such as SymbolInfoDouble and check the requested symbol and property.
Trade notificationsPolling and trade-related checksOnTradeTransaction can respond to trade transactions when event-driven handling is needed.
Tickets and numeric typesOrder tickets are often stored as intUse the types expected by MT5 APIs, including ulong for many ticket identifiers.

For example, avoid assuming the chart’s current Bid or Ask is always the right value for another symbol. Query the required symbol with SymbolInfoDouble, and check the function result before using the value. Likewise, do not assume that an MT4 series array and an MT5 copied array have identical indexing unless the code explicitly establishes the intended order.

Account mode is part of the conversion, not just a tester setting. If the code expects to track separate entries by ticket, verify that the target account is hedging or redesign the management rules for netting. Also revisit volume rounding and stop placement: broker constraints can reject a request even when the strategy conditions are correct.

Fix the conversion errors that appear most often

SymptomCommon causeWhat to check or change
Undeclared identifierThe source uses an MT4-only function, variable, or constant in an MT5 file.Replace it with the appropriate MT5 API and include the required library, such as Trade/Trade.mqh when using CTrade.
Wrong parameter count or type mismatchA familiar function name has a different signature, or an MT4 value-returning indicator call was copied unchanged.Check the MT5 function signature. For indicators, create the handle with the new parameter list and read values with CopyBuffer.
Invalid indicator handleHandle creation failed, parameters are invalid, or a handle was used before it was initialized.Check for INVALID_HANDLE in OnInit, log GetLastError, and do not call CopyBuffer on an invalid handle.
CopyBuffer returns too few valuesData is not ready, the handle is wrong, the requested shift is unavailable, or the buffer index is incorrect.Check the return count, confirm the buffer and shift, and retry only when the program’s timing and logic allow it.
Compiles, but a trade request is rejectedInvalid volume or stops, unsupported filling, closed market, disabled trading, or insufficient margin.Read the trade retcode and check symbol volume and stop constraints, account permissions, and market conditions.
EA manages the wrong exposureCode assumes an order ticket means the same thing as an MT5 position, or assumes hedging behavior on a netting account.Separate position, order, and deal logic, then test with the intended account mode.

For MT5 runtime failures, inspect ResultRetcode and its description when using CTrade, or MqlTradeResult.retcode when sending a raw request. Retcodes such as TRADE_RETCODE_INVALID_VOLUME, TRADE_RETCODE_INVALID_STOPS, TRADE_RETCODE_MARKET_CLOSED, and TRADE_RETCODE_NO_MONEY point to different fixes. Do not treat a generic “trade failed” message as enough diagnostic information.

MetaEditor errors such as “undeclared identifier,” wrong parameter counts, and type mismatches usually indicate code-level incompatibility. A compile-clean EA that does not trade needs runtime checks: confirm the entry condition is reached, trading is allowed, the request is valid for the symbol, and the result code is logged. The MQL4/MQL5 error-fixing page explains how the Lab checks compilation and reports changes.

Compile, test, and compare behavior in MT5

Use a test sequence that separates compiler problems from strategy differences. A test pass should confirm not only that a trade appears, but also that its trigger, size, stop management, and exit match the intended rules.

  1. Compile the correct source in MetaEditor. Confirm the file is an MT5 EA or indicator, not an MT4 file with a changed extension. Resolve errors first, then review warnings that could point to conversions, uninitialized values, or unreachable logic.
  2. Check dependencies. Confirm that included files and custom indicators are available in the MT5 project and that their function signatures and buffers match the converted calls.
  3. Run Strategy Tester with the right symbol and timeframe. Choose a tick model appropriate to the EA’s timing. If behavior depends on intrabar price movement, use an available real-tick mode where appropriate; a bar-based model may not represent that logic.
  4. Set realistic test conditions. Match the symbol, date range, starting deposit, leverage, and account mode as closely as practical. Confirm whether the test uses netting or hedging if the EA’s trade management depends on it.
  5. Inspect Journal and trade results. Look for retcodes, initialization failures, missing indicator data, and repeated requests. Check the Experts and Journal output as well as the tester’s trade list and graph.
  6. Compare rule by rule with MT4. Check signal timing, entry and exit conditions, position sizing, and trade management. Do not expect identical fills: pricing, execution, spreads, account mode, and tester data can differ between platforms.
  7. Test the edge cases. Check the first available bars, low history, rejected requests, symbol constraints, and the EA’s behavior when it already has exposure or a pending order.

Keep test assumptions with the results. A converted EA can pass one test configuration and still behave differently with another symbol, broker, or account mode. Past or tested results do not guarantee future results.

When to convert automatically and when to rewrite

Assisted conversion is a reasonable starting point for code with straightforward entry rules, familiar indicators, and simple trade handling. Even then, review the generated code: the conversion needs to preserve the strategy’s meaning, not just produce valid MQL5 syntax.

Plan for manual redesign when the EA depends on complex ticket-based order management, multiple simultaneous entries, broker-specific execution behavior, chart functions with no direct equivalent, or assumptions that only make sense on a hedging account. Those areas need a clear decision about the intended MT5 behavior before you can judge whether the port is correct.

The FXNook Lab MT4-to-MT5 converter reads the program and its dependencies, converts the code, compiles the MT5 result, and reports differences that may affect behavior. It keeps the original as a separate version. Use the report as a review aid, then verify the result in MetaEditor and the MT5 Strategy Tester against your own rules and test conditions.

Your next step is to make the inventory above, convert one API area at a time, and run the checklist before relying on the port. If you want an assisted conversion, review the converter and its difference report; if MetaEditor is already showing errors, use the error-fixing workflow to identify and check them.

Questions

Can MQL4 code run directly in MetaTrader 5?

No. MT5 uses MQL5, which has different trade handling and indicator access, among other changes. Convert the source to MQL5 and compile and test it in MetaEditor and MT5 before use.

What is the biggest difference between MQL4 and MQL5?

For many EAs, the biggest difference is how trades are represented and managed. MT4 code commonly manages orders, while MT5 separates current positions, pending orders, and execution deals, and account mode affects how exposure is represented.

How do I convert OrderSend from MQL4 to MQL5?

Replace the MQL4 call with an MQL5 trade operation, commonly a method of the CTrade class or a request sent with MqlTradeRequest. Check the result retcode as well as the function return, and verify volume, stops, filling rules, and account mode.

Why does my converted MQL5 EA compile but not trade?

Compilation does not confirm that the EA reaches its entry condition or that the broker accepts its request. Log the trade retcode, check that trading is permitted, validate symbol volume and stop constraints, and review the Experts and Journal logs in the tester.