How to Convert an MT4 EA to MT5: A Practical Guide
By FXNook Lab team

You can convert an MT4 EA to MT5 with a conversion tool or by rewriting its MQL4 code, but either way you must review and test the result. MT5 handles trades, indicators and account modes differently, so a successful compile does not prove that the EA makes the same decisions or places trades as intended.
A small EA with straightforward entries, exits and standard indicators is usually a manageable conversion. An EA that depends on custom libraries, order-ticket behavior, complex trade management or chart functions may need a partial or full rewrite. The practical goal is to preserve the rules where MT5 allows, and identify differences that change behavior.
Can you convert an MT4 EA to MT5 automatically?
Conversion tools can produce a useful starting MQL5 version. They can map common functions and structures, but the output still needs a developer to check how the original EA's trading logic maps to MT5 orders, positions, deals, indicators and account settings.
This is why a line-by-line rename is not enough. For example, an MT4 EA may close a specific order by ticket, while MT5 trade management may need to select a position or deal with several positions on a hedging account. An indicator call that returns a number in MQL4 becomes a handle that must be read from a buffer in MQL5.
A simple EA is a good candidate when it uses built-in indicators, clear entry and exit rules, and basic market orders. A rewrite may be appropriate when the EA relies on custom DLLs or libraries that are unavailable, unsupported chart behavior, complicated order management, or assumptions that only make sense under one MT4 account model. Some MT4 behavior has no exact equivalent in MT5, so record those differences instead of assuming they can be copied exactly.
Before converting, identify what the EA depends on
Start by understanding the EA as a trading program, not just as a source file. Write down what makes it enter, exit, size trades and manage risk. That gives you something concrete to compare against the MQL5 version later.
- Save a separate copy of the original
.mq4source and any included files. Keep the original unchanged. - Record every input, including lot sizing, stop-loss and take-profit distances, magic number, time filters, spread limits and any risk settings.
- List the custom indicators, include files and libraries the EA uses. Confirm that you have the source or an MT5-compatible replacement for each dependency.
- Describe the entry, exit, trailing-stop and position-sizing rules in plain language, including the chart timeframe and symbols used.
- Note broker conditions that affect execution, such as symbol digits, minimum volume, volume step, stop distance, execution mode and whether the account is netting or hedging.
An .ex4 file is compiled output, not MQL4 source code. It cannot be treated as source for a reliable conversion; look for the original .mq4 file and its dependencies. If you only have the compiled file, ask the original author or provider for the source and permission to convert it.
FXNook AI Code Lab's MT4 to MT5 converter reads the program and its dependencies, converts the code, compiles the result and reports behavior differences. The report is useful as a review aid, but you should still test the EA with the account mode and trading conditions you intend to use.
MT4 and MT5 trading models: differences to map
MT4 organizes trade activity around orders. MT5 separates active orders, positions and deals: an order is a request, a position is current exposure, and a deal records an execution. These concepts overlap in a simple market-order EA, but they are not interchangeable in more complex logic.
| Area | MT4 | MT5 | What to review |
|---|---|---|---|
| Send a market trade | OrderSend() | CTrade::Buy(), CTrade::Sell(), or OrderSend() with an MqlTradeRequest | Check the request result and server retcode, not only the function's basic return value. |
| Current exposure | Trades are commonly inspected through order functions such as OrderSelect(). | Current exposure is represented by positions, selected with functions such as PositionSelect(). | Do not assume that selecting an MT5 order selects an open position. |
| Pending requests and history | Order functions cover trade operations and history in the MT4 model. | Active orders and historical deals are separate from open positions. | Choose the correct collection for pending orders, current exposure or past executions. |
| Ticket and symbol selection | OrderSelect() selects an order by ticket or position in the order pool. | Use position, order and deal functions according to what you need; for example, PositionSelect() selects a position by symbol. | Rework loops and ticket-based close or modify logic rather than copying them mechanically. |
| Account mode | MT4 generally presents trades as separate orders. | MT5 accounts can use netting or hedging behavior. | Confirm the account mode. One net position per symbol in a netting account behaves differently from multiple positions in a hedging account. |
| Trade result | OrderSend() returns a ticket on success or a negative result; inspect GetLastError() on failure. | CTrade provides a method result and trade-result details such as ResultRetcode(). | Check the documented return code and log meaningful failure details. |
Account mode can change the rules of the EA itself. If an MT4 strategy expects two independent trades on the same symbol, a netting account may combine exposure into one position instead. On an MT5 hedging account, separate positions can be held, but your code still needs to select and manage the intended position correctly.
Convert a simple OrderSend example to MQL5
The following MQL4 helper sends a buy market order. It is intended to be called when the EA's existing entry condition is true; it is not a complete strategy. Prices are normalized to the symbol's digits, and the distances are expressed in points, not pips.
// MQL4: add to an EA and call SendBuy() when its entry rule is true.
input double Lots = 0.10;
input int StopLossPoints = 300;
input int TakeProfitPoints = 600;
input int Slippage = 10;
input int MagicNumber = 12345;
bool SendBuy()
{
RefreshRates();
double sl = NormalizeDouble(Ask - StopLossPoints * Point, Digits);
double tp = NormalizeDouble(Ask + TakeProfitPoints * Point, Digits);
int ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, Slippage,
sl, tp, "Example buy", MagicNumber, 0, clrGreen);
if(ticket < 0)
{
Print("OrderSend failed. Error=", GetLastError());
return(false);
}
return(true);
}
Here, Lots is the requested volume, while the stop and target are calculated from the current ask price. A production EA should also validate the volume against the symbol's minimum, maximum and step, and check that the stop distances meet the broker's rules. A rejected request can result from invalid volume, invalid stops, unavailable trading or other execution conditions; use the error details to diagnose the actual cause.
In MQL5, a common approach is to use the CTrade class. This equivalent helper uses the current ask by passing zero as the market price. It checks both the method result and the server retcode, because a method call alone is not enough to establish that the trade was accepted and executed.
// MQL5: add to an EA and call SendBuy() when its entry rule is true.
#include <Trade/Trade.mqh>
CTrade trade;
input double Lots = 0.10;
input int StopLossPoints = 300;
input int TakeProfitPoints = 600;
input ulong MagicNumber = 12345;
int OnInit()
{
trade.SetExpertMagicNumber(MagicNumber);
return(INIT_SUCCEEDED);
}
bool SendBuy()
{
MqlTick tick;
if(!SymbolInfoTick(_Symbol, tick))
{
Print("Could not read the latest symbol tick.");
return(false);
}
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
double sl = NormalizeDouble(tick.ask - StopLossPoints * point, digits);
double tp = NormalizeDouble(tick.ask + TakeProfitPoints * point, digits);
if(!trade.Buy(Lots, _Symbol, 0.0, sl, tp, "Example buy"))
{
Print("Buy request failed: ", trade.ResultRetcode(), " ",
trade.ResultRetcodeDescription());
return(false);
}
uint retcode = trade.ResultRetcode();
if(retcode != TRADE_RETCODE_DONE &&
retcode != TRADE_RETCODE_DONE_PARTIAL &&
retcode != TRADE_RETCODE_PLACED)
{
Print("Trade not completed as expected: ", retcode, " ",
trade.ResultRetcodeDescription());
return(false);
}
return(true);
}
TRADE_RETCODE_DONE indicates completion, while TRADE_RETCODE_DONE_PARTIAL indicates a partial execution and TRADE_RETCODE_PLACED indicates that a request was placed. The exact result to expect depends on the request and execution path, so log the retcode and review it rather than treating every non-error-looking call as a filled trade. If the broker rejects the request, the retcode and its description help distinguish issues such as invalid stops, unsupported filling or insufficient trading permission.
Replace MT4 indicator calls with MT5 handles
In MQL4, a call such as iMA() returns the moving-average value for a requested bar. In MQL5, iMA() creates an indicator handle. The EA then reads values from its buffer with CopyBuffer(), and it should release the handle when it no longer needs it.
// MQL5: create the moving-average handle once and read the previous bar.
int maHandle = INVALID_HANDLE;
int OnInit()
{
maHandle = iMA(_Symbol, _Period, 20, 0, MODE_EMA, PRICE_CLOSE);
if(maHandle == INVALID_HANDLE)
{
Print("Could not create MA handle. Error=", GetLastError());
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
bool GetPreviousMA(double &value)
{
if(BarsCalculated(maHandle) < 2)
return(false);
double buffer[1];
if(CopyBuffer(maHandle, 0, 1, 1, buffer) != 1)
return(false);
value = buffer[0];
return(true);
}
void OnDeinit(const int reason)
{
if(maHandle != INVALID_HANDLE)
IndicatorRelease(maHandle);
}
The buffer index 0 refers to the moving-average buffer, and the start position 1 asks for the previous bar rather than the current forming bar. If the handle has not calculated enough bars, or CopyBuffer() cannot provide the requested value, do not use an uninitialized value in a trading decision. Check the return count and try again when the data is ready.
In an MT4 EA, the comparable value call looks like iMA(Symbol(), Period(), 20, 0, MODE_EMA, PRICE_CLOSE, 1). When converting an indicator rule, preserve the intended bar shift and buffer index; confusing the current bar with the last completed bar can change signals even when the indicator parameters appear identical.
Adapt events, prices and trade management
Review event handling as part of the port. Modern MQL4 and MQL5 EAs commonly use OnInit(), OnTick() and OnDeinit(), but older MQL4 code may use init(), start() and deinit(). Move initialization, per-tick work and cleanup deliberately, and also check any timer or chart-event handlers the EA uses.
| Common MQL4 pattern | MQL5 review or replacement |
|---|---|
Ask, Bid, Point, Digits | Read a tick with SymbolInfoTick(); query symbol values with SymbolInfoDouble() and SymbolInfoInteger(). |
MarketInfo() | Use the appropriate SymbolInfoDouble() or SymbolInfoInteger() property for the requested symbol setting. |
OrderSelect() and order loops | Decide whether the code needs active orders, open positions or history, then use the matching MQL5 selection functions. |
OrderClose() and OrderModify() | Use suitable CTrade operations or trade requests, selecting the correct position or order and checking the result. |
| Direct indicator value calls | Create indicator handles, read buffers with CopyBuffer(), check availability and release handles. |
GetLastError() after trade requests | Inspect the trade result retcode and description; use terminal error information where appropriate for local failures. |
Do not replace MarketInfo() with a guessed property. Map each requested setting to the matching documented symbol property, and check that calls use the symbol the EA is trading rather than assuming the chart symbol. If prices or volume are calculated for another instrument, its tick size, digits and volume rules may differ from those of the chart.
Closing logic deserves particular attention. In MT4, an EA may find an order by ticket and close it; in MT5, the code must know whether it is closing a position, canceling a pending order or recording a deal. Confirm that the selection still refers to the intended ticket or symbol after other trades are opened, modified or closed.
Compile, backtest and compare behavior
Use MetaEditor and the Strategy Tester to verify the conversion in stages. A clean compile only confirms that the source passes compilation; it does not show that the EA reaches its trading code, requests valid trades or follows the same strategy rules.
- Compile in MetaEditor. Open the MQL5 project and compile it in the MT5 MetaEditor. Fix errors first, then review warnings that might indicate an incorrect type conversion, unused logic or a faulty assumption. If you need help with compiler messages, the MQL error-fixing page describes a code review and compile-and-check workflow.
- Check dependencies and inputs. Confirm that all included files and custom indicators are available in the MT5 data folder, and compare the input names, defaults and units with the original EA. Pay particular attention to points versus pips and lot size versus volume steps.
- Set up the intended test conditions. In the MT5 Strategy Tester, choose the intended EA, symbol, timeframe, date range, deposit currency and account conditions where available. Test on the same type of account mode the EA will use, especially when its logic expects multiple positions per symbol.
- Compare decisions, not just totals. Use the same historical period and comparable symbol data for MT4 and MT5. Compare when signals occur, whether entry filters pass, the requested trade direction, stop and target calculations, and how exits or trailing rules behave. Differences in price data, execution assumptions and platform behavior can affect the comparison.
- Inspect the logs. Review the Strategy Tester Journal and Experts output for rejected requests, missing indicator data, repeated entries and unexpected selection results. Add temporary, clear diagnostic messages around key rules if you cannot tell why the EA skipped or sent a trade.
- Test edge cases. Check what happens when a trade is rejected, the symbol has a different number of digits, the requested volume is below the minimum, a stop is too close, or an indicator buffer is not ready. Also test the EA's behavior when a position already exists or a pending order is present.
- Run a demo check before live consideration. Confirm that the EA starts, reads inputs and manages trades as expected under the broker's conditions. Backtest and demo results do not guarantee future trading results.
Common conversion mistakes to catch
- Treating every MT5 order as an open position. Keep active orders, positions and deals distinct. Use the right selection and management functions for each type of trade record.
- Ignoring trade retcodes. A CTrade method returning true is not, on its own, proof that the server completed the trade. Log and handle
ResultRetcode()and its description. - Reading an indicator buffer too early. Create handles during initialization, verify calculated bars and check the number returned by
CopyBuffer()before using a value. - Assuming account modes match. Check whether the target MT5 account is netting or hedging. Rework any rules that expect separate same-symbol trades if the account combines exposure.
- Copying ticket logic without checking selection. A ticket may refer to a different kind of object in the new code. Confirm whether each operation targets a position, pending order or historical record.
- Trusting a clean compile. Compilation does not test the strategy. Compare decisions in the tester, inspect logs and test rejected trades and unavailable data.
- Assuming point values and broker rules are identical. Verify symbol digits, tick size, volume limits, volume step and minimum stop distance with the target broker's symbol properties.
Next step
Start with the original .mq4 source, its includes and a written list of the EA's rules. Convert the trade and indicator logic first, then work through the checklist in MetaEditor and the Strategy Tester before considering live use. If you want a conversion workflow, the FXNook Lab converter produces an MQL5 version, compiles it and reports differences for you to review; the final practical step is still to test the converted EA under the account mode and broker conditions you plan to use.
Questions
Can an ex4 file be converted to MT5?
An ex4 file is compiled MT4 output, not the MQL4 source needed for a dependable code conversion. Ask for the original mq4 file and any included dependencies; without them, a reliable source-level conversion is not available.
What is the difference between MT4 orders and MT5 positions?
MT4 primarily uses orders to represent trade activity. MT5 separates active orders, open positions and execution deals, so code must select the right type of record for each task. Netting accounts can combine exposure on a symbol, while hedging accounts can keep separate positions.
Why does an MT4 EA compile in MT5 but not open trades?
A successful compile does not establish that the EA's trade request is accepted or that its entry condition is reached. Check the Experts and Journal logs, trade retcodes, symbol volume and stop rules, account mode, trading permissions and whether indicator data is available.
How do I convert MT4 indicator calls such as iMA to MQL5?
In MQL5, create the indicator handle with iMA(), usually in OnInit(), then retrieve values with CopyBuffer(). Check that the handle has calculated enough bars and that CopyBuffer() returns the requested count, and release the handle with IndicatorRelease() in OnDeinit().