Skip to content
MQL4 Programming Language Guide — Expert Advisors for MetaTrader 4

MQL4 Programming Language Guide — Expert Advisors for MetaTrader 4

DodaTech Updated Jun 7, 2026 8 min read

MQL4 (MetaQuotes Language 4) is the programming language for the MetaTrader 4 trading platform — a C-like scripting language used to create Expert Advisors, custom indicators, and scripts for automated forex and CFD trading. In this tutorial, you’ll learn the MQL4 program model, its trade functions, and why migrating to MQL5 is the recommended path for new projects.

Why it matters: MetaTrader 4 still holds a massive share of the retail forex market. Thousands of EAs and indicators on the MQL4 Marketplace generate real trading income every day. Understanding MQL4 lets you maintain legacy systems, migrate them to MQL5, and tap into a vast library of existing trading tools.

Real-world use: Signal providers run MQL4 EAs on VPS servers to auto-copy trades to hundreds of subscriber accounts. Brokers offer MT4-compatible servers specifically because of the ecosystem of existing MQL4 indicators and EAs.

What You’ll Learn

  • MQL4 basics: syntax, program types, and execution model
  • Event handlers: init, deinit, start, and tick processing
  • Trade functions: OrderSend, OrderSelect, OrderModify, OrderClose
  • MQL4 vs MQL5 differences and migration path
  • Common pitfalls when writing MQL4 EAs
  • When to stay on MQL4 and when to migrate

Learning Path

    flowchart LR
  A[MQL4 Basics<br/>You are here] --> B[Program Types & Event Handlers]
  B --> C[Trade Functions & Indicators]
  C --> D{Should I Migrate?}
  D -->|Yes| E[MQL5 Migration Path]
  D -->|No| F[Optimize Existing MQL4 EA]
  

What Is MQL4?

MQL4 uses a C-like syntax with limited object-oriented support (you get structures and some built-in classes, but no user-defined classes with inheritance). The language is interpreted at runtime by the MT4 client terminal. Compiled MQL4 programs produce .ex4 files.

The key distinction from MQL5: MQL4 is order-oriented — every trade operation works with an “order” (which can be a market position, a pending order, or even a closed trade). MQL5 separates these into distinct concepts (positions, orders, deals).

MQL4 Program Types

TypePurposeEntry Point
Expert AdvisorAutomated trading botstart()
Custom IndicatorCustom chart indicatorstart()
ScriptOne-time executionstart()

Unlike MQL5, MQL4 has no Service or Library program types. Include files (.mqh) exist but are text-only — there is no compiled library format.

Event Handlers

int init() {
   // Called once when EA is loaded onto a chart
   return(0);
}

int deinit() {
   // Called once when EA is removed from the chart
   return(0);
}

int start() {
   // Called on every new tick — the core trading function
   return(0);
}
HandlerTrigger
init()EA loaded onto chart
deinit()EA removed from chart
start()Every new tick (equivalent to MQL5’s OnTick)

Trade Functions

MQL4’s trade functions are direct-call — you pass parameters directly rather than using a request struct:

FunctionPurpose
OrderSend(symbol, cmd, volume, price, slippage, sl, tp, comment, magic, expiration, arrow)Open a new order
OrderSelect(index, select, pool)Select an order for reading/modification
OrderModify(ticket, price, sl, tp, expiration, arrow)Modify SL, TP, or price of an open order
OrderClose(ticket, volume, price, slippage, arrow)Close a market order
OrderDelete(ticket)Delete a pending order
OrderTicket()Return ticket of selected order
OrderLots() / OrderOpenPrice() / etc.Read properties of selected order

Example — Simple Moving Average EA

// Simple SMA Crossover EA for MQL4
extern double LotSize = 0.1;
extern int    FastMA  = 10;
extern int    SlowMA  = 30;
extern int    Magic   = 2024;

int init() {
   return(0);
}

int deinit() {
   return(0);
}

int start() {
   double fastNow = iMA(NULL, 0, FastMA, 0, MODE_SMA, PRICE_CLOSE, 0);
   double fastPrev = iMA(NULL, 0, FastMA, 0, MODE_SMA, PRICE_CLOSE, 1);
   double slowNow = iMA(NULL, 0, SlowMA, 0, MODE_SMA, PRICE_CLOSE, 0);
   double slowPrev = iMA(NULL, 0, SlowMA, 0, MODE_SMA, PRICE_CLOSE, 1);

   int total = OrdersTotal();
   bool hasPosition = false;

   for(int i = 0; i < total; i++) {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
         if(OrderMagicNumber() == Magic && OrderSymbol() == Symbol()) {
            hasPosition = true;
            break;
         }
      }
   }

   if(!hasPosition) {
      if(fastNow > slowNow && fastPrev <= slowPrev) {
         OrderSend(Symbol(), OP_BUY, LotSize, Ask, 3, 0, 0, "", Magic, 0, Green);
      }
      if(fastNow < slowNow && fastPrev >= slowPrev) {
         OrderSend(Symbol(), OP_SELL, LotSize, Bid, 3, 0, 0, "", Magic, 0, Red);
      }
   }

   return(0);
}

Expected behavior: On each tick, the EA calculates two SMAs. If the fast MA crosses above the slow MA and there is no existing position with the same Magic number, it sends a market buy order. The cross in the opposite direction triggers a sell. Note that in MQL4, iMA() returns the indicator value directly — there is no handle or CopyBuffer pattern.

Example — Close All Orders Script

// Close all open orders for this symbol
int start() {
   for(int i = OrdersTotal() - 1; i >= 0; i--) {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
         if(OrderSymbol() == Symbol()) {
            if(OrderType() == OP_BUY)
               OrderClose(OrderTicket(), OrderLots(), Bid, 3, Red);
            if(OrderType() == OP_SELL)
               OrderClose(OrderTicket(), OrderLots(), Ask, 3, Red);
         }
      }
   }
   return(0);
}

Expected behavior: Iterates all open orders in reverse, selects each one, and closes market orders at the current price. Pending orders are left untouched.

MQL4 vs MQL5 — Migration Path

    flowchart TD
  MQL4[MQL4 Code] --> Analyze{Analyze usage}
  Analyze -->|OrderSend/ OrderClose| Positions[Map to MQL5<br/>PositionOpen, PositionClose]
  Analyze -->|iMA returns value| Handles[Map to handle-based<br/>iMA + CopyBuffer]
  Analyze -->|start()| Events[Map to OnTick]
  Analyze -->|extern| Inputs[Map to input]
  Analyze -->|No classes| OOP[Refactor to classes]

  Positions --> Test
  Handles --> Test
  Events --> Test
  Inputs --> Test
  OOP --> Test
  Test[Backtest in MQL5<br/>Strategy Tester] --> Result{Matching results?}
  Result -->|No| Debug[Debug & Re-run]
  Debug --> Test
  Result -->|Yes| Done[Migration Complete]
  

Key Migration Table

MQL4MQL5 Equivalent
int start()void OnTick()
int init()int OnInit()
int deinit()void OnDeinit(int reason)
iMA(NULL,0,14,0,MODE_SMA,PRICE_CLOSE,0)Create handle → CopyBuffer(handle,0,0,1,buf)
OrderSend(Symbol(),OP_BUY,0.1,Ask,3,0,0,"",magic,0,Red)MqlTradeRequest + OrderSend(req, res)
OrdersTotal() + OrderSelect() loopPositionSelect() or PositionsTotal()
extern double x;input double x;
No classesFull OOP: classes, inheritance, polymorphism
9 timeframes21 timeframes
Single-currency testerMulti-currency tester

Why MQL5 Is Recommended for New Projects

MetaQuotes has frozen MQL4 development. All new features — ONNX integration, multi-currency backtesting, 64-bit compilation, custom graphics — land in MQL5 first (or exclusively). The MQL5 compiler produces faster, more reliable code, and the backtester is significantly more accurate with “Every tick” modelling.

You should migrate when:

  • You need multi-currency or multi-asset strategies
  • You want to use machine learning (ONNX) in your EA
  • You’re building a commercial product (MQL5 Marketplace is the active marketplace)
  • Your MQL4 EA has become too complex to maintain without OOP

You can stay on MQL4 when:

  • You maintain legacy EAs that work reliably
  • Your broker only offers MT4 (no MT5)
  • You use third-party MQL4-only tools (signal copiers, custom indicators)

Common Errors

1. OrderSend returns -1 (error)

The most common error is incorrect price. Always use Ask for buys and Bid for sells. Slippage set too low (e.g., 0) can also cause rejection — use 3–5 pips for forex.

2. OrderSelect fails after OrderSend

OrderSend changes the order pool. Always re-select the order after sending if you need to read its properties. Use the ticket returned by OrderSend.

3. iMA() returns 0 or wrong value

Check that the symbol and timeframe arguments are valid. NULL means “current chart symbol”, 0 means “current timeframe”. The last parameter is the shift — index 0 is current bar (which may be forming), 1 is the completed bar.

4. Loop modifies OrdersTotal() during iteration

When closing or deleting orders inside a loop, the total changes. Always iterate backwards (for(int i=OrdersTotal()-1; i>=0; i--)) to avoid index skipping.

5. Magic number collision

Every EA should have a unique Magic number to identify its own orders. Without it, multiple EAs on the same symbol will interfere with each other’s positions.

Practice Questions

  1. What is the entry-point function for an MQL4 Expert Advisor? start() — it fires on every new tick. Equivalent to OnTick() in MQL5.

  2. How does MQL4’s iMA() differ from MQL5’s iMA()? In MQL4, iMA() returns the indicator value directly (e.g., iMA(NULL,0,14,0,MODE_SMA,PRICE_CLOSE,0)). In MQL5, iMA() returns a handle which you then pass to CopyBuffer() to get values.

  3. Why should I loop backwards through OrdersTotal()? When you close or delete an order, the order count decreases and higher-indexed orders shift down. A forward loop skips orders; a backward loop avoids this.

  4. What is a Magic number and why do I need one? A Magic number is a unique identifier assigned to an EA’s orders. It prevents one EA from accidentally closing another EA’s positions on the same symbol.

  5. How do I convert an MQL4 indicator call to MQL5? Replace the direct iMA(... shift) call with: (1) create a handle in OnInit() with iMA(...), (2) copy values in OnTick() with CopyBuffer(handle, 0, 0, count, array), (3) use array[0] for the current bar.

Challenge: Take an existing MQL4 EA you’ve written or found, identify every MQL4-only function call (OrderSend with direct params, iMA with shift, start()), and write the equivalent MQL5 version. Run both in their respective Strategy Testers and compare the equity curves.

FAQ

Is MQL4 still supported by MetaQuotes?
MetaQuotes provides bug fixes but no new features. The last major MQL4 update was in 2020. All innovation goes into MQL5.
Can I run MQL4 EAs on MetaTrader 5?
No — MT5 cannot load .ex4 files and MT4 cannot load .ex5 files. You must manually rewrite MQL4 code to MQL5 syntax.
Which is faster, MQL4 or MQL5?
MQL5 compiles to native x86/x64 code and runs significantly faster — especially in the Strategy Tester — because MQL4 is interpreted at runtime.
Should I learn MQL4 or MQL5 first?
If you’re starting today, learn MQL5. MQL4 knowledge is useful only for maintaining existing EAs or migrating them. All new features, tools, and Marketplace activity are on MT5.
Do brokers still offer MT4?
Yes — hundreds of brokers still offer MT4, and it remains popular in Asia, Africa, and South America. MT4 is not going away soon, but its ecosystem is shrinking.
Can I use Python with MQL4?
Not natively. MQL4 lacks the ONNX integration that Python users have in MQL5. You can communicate via files (CSV), WebRequest(), or custom DLL bridges, but it is much harder than MQL5’s built-in ONNX support.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro