Edgoro
Platforms

MQL5 magic numbers explained: keep each Expert Advisor's trades separate

What a magic number is in MetaTrader 5, how to set and filter it in MQL5, how to pick unique numbers, and the netting-account case where it can't help.

Run two Expert Advisors on one MetaTrader 5 account and sooner or later one of them closes a trade that belongs to the other. Or an EA restarts, forgets which positions are its own, and opens a duplicate. The fix for both is the magic number, a small integer that most EA code mentions and few explanations cover properly.

This article explains what a magic number is, how to set it and filter by it in MQL5, how to choose numbers that won't collide, and the one account type where it can't keep EAs apart.

What a magic number is

A magic number is an integer (an unsigned 64-bit ulong in MQL5) attached to every order an Expert Advisor sends. It travels with the order, the deals it produces and the position that results, so you can later ask "which of these did my EA open?".

  • Trades you place by hand carry magic number 0.
  • MetaTrader doesn't enforce uniqueness. Two EAs can use the same number, and then they can't tell each other's trades apart.
  • The number is yours to choose. It has no meaning to the broker.

Setting it

With the standard CTrade class, set it once and every order sent through that object carries it:

trade.SetExpertMagicNumber(InpMagic);

If you build requests by hand with MqlTradeRequest, set request.magic on every request. Forgetting it on one code path, such as a pending order or a partial close, is a classic source of orphaned trades.

Filtering by it

The other half is reading: whenever the EA loops through positions, orders or history, it should skip anything without its number. Positions and orders also need a symbol filter, because the same EA may run on several charts.

#include <Trade/Trade.mqh>

input ulong InpMagic = 260100; // Unique for each EA, symbol and setup

CTrade trade;

// Open positions that belong to this EA on this chart's symbol.
int CountOwnPositions()
  {
   int count = 0;
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      ulong ticket = PositionGetTicket(i);   // also selects the position
      if(ticket == 0)
         continue;
      if(PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == (long)InpMagic)
         count++;
     }
   return count;
  }

// Pending orders placed by this EA on this symbol.
int CountOwnOrders()
  {
   int count = 0;
   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      ulong ticket = OrderGetTicket(i);      // also selects the order
      if(ticket == 0)
         continue;
      if(OrderGetString(ORDER_SYMBOL) == _Symbol && OrderGetInteger(ORDER_MAGIC) == (long)InpMagic)
         count++;
     }
   return count;
  }

// Realised result of this EA's deals since a given time: profit, swap and commission.
double ClosedProfitSince(const datetime from)
  {
   if(!HistorySelect(from, TimeCurrent()))
      return 0.0;
   double total = 0.0;
   for(int i = HistoryDealsTotal() - 1; i >= 0; i--)
     {
      ulong ticket = HistoryDealGetTicket(i);
      if(ticket == 0)
         continue;
      if(HistoryDealGetInteger(ticket, DEAL_MAGIC) != (long)InpMagic || HistoryDealGetString(ticket, DEAL_SYMBOL) != _Symbol)
         continue;
      total += HistoryDealGetDouble(ticket, DEAL_PROFIT) + HistoryDealGetDouble(ticket, DEAL_SWAP) + HistoryDealGetDouble(ticket, DEAL_COMMISSION);
     }
   return total;
  }

int OnInit()
  {
   trade.SetExpertMagicNumber(InpMagic);   // every order sent through this object carries the number
   if(AccountInfoInteger(ACCOUNT_MARGIN_MODE) != ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
      Print("Netting account: one position per symbol, shared by every EA that trades it.");
   // After a restart, the EA's state comes from the account, not from variables that were lost.
   PrintFormat("Found %d open position(s) and %d pending order(s) with magic %I64u", CountOwnPositions(), CountOwnOrders(), InpMagic);
   return INIT_SUCCEEDED;
  }

void OnTick()
  {
  }

Note the cast (long)InpMagic: the getters return long while the input is a ulong. For the small numbers people actually use, the comparison is exact.

Choosing numbers that won't collide

Pick a scheme and write it down. One simple pattern encodes the EA, the symbol and the setup:

PartDigitsExample
EA identifierFirst two26 = your trend EA
Symbol slotNext two01 = EUR/USD, 02 = gold
Setup or timeframeLast two00 = H1 default, 01 = H4 variant

So 260100 is the trend EA on EUR/USD with its default setup, and 260201 the same EA on gold with the H4 variant. Make the number an input so each chart can get its own value, and keep a list next to your VPS notes.

Also avoid 0, which is what manual trades use, and don't copy the magic numbers from published code: someone else's EA on the same account may be using them too.

Why not use the order comment?

Some EAs tag their trades with a comment such as "trend-EA" and filter on that instead. It's fragile: comments are free text, brokers may overwrite or append to them (for example when a stop-loss or take-profit closes the trade), and two EAs can easily choose the same word. The magic number is an exact integer that travels with the order unchanged. Use comments for humans reading the history, and magic numbers for code.

Several setups in one EA

One Expert Advisor can run more than one logic, say a breakout leg built on a Donchian channel and a mean-reversion leg on Bollinger Bands, both on the same symbol. Give each its own number, either with one CTrade object per leg or by calling SetExpertMagicNumber() before each order. Each leg then counts, trails and closes only its own positions, and the history shows which leg made or lost money.

Restarts and state

Terminals restart, VPSs reboot and EAs get recompiled. Anything kept only in ordinary variables is lost. A robust EA rebuilds its view of the world from the account in OnInit(): its open positions and pending orders (filtered by magic number), and, if it needs them, today's deals from the history. Persistent values like the day's starting equity can live in terminal global variables whose names include the magic number, as in the prop-firm daily loss guard.

Netting accounts: where magic numbers can't help

MetaTrader 5 accounts are either hedging (several positions per symbol allowed) or netting (one position per symbol). On a netting account, a buy from one EA and a sell from another on the same symbol don't create two positions; they offset into one. No magic number can split that shared position back into two EAs' trades.

If you run several EAs on a netting account, give each its own symbol, or use a hedging account. The example's OnInit() prints a warning when the account isn't hedging.

Common mistakes

MistakeWhat goes wrongFix
No magic filter in a close-all loopThe EA closes manual trades and other EAs' positionsFilter by magic number and symbol
Same magic on two chartsTwo copies of the EA manage each other's tradesOne number per EA, symbol and setup
Using OrdersTotal() to count positionsIn MQL5, orders are pending orders only; positions are separateUse PositionsTotal() for positions
Magic set on entries but not on pending ordersOrders the EA can't recognise laterSet it once on the CTrade object, or on every request
State only in variablesDuplicate trades after a restartRebuild state from positions in OnInit()

These checks are part of the MQL5 Expert Advisor risk checklist, and they matter for any trade management code, such as a trailing stop.

Sources and further reading

Try it with Edgoro

Every MT5 Expert Advisor Edgoro generates comes with a magic-number input and filters its own trades by it. Ask for "an EA that only manages its own positions on this symbol and rebuilds its state after a restart" and check the code yourself. Generate your EA.

Test every EA on a demo account before going live. Automated trading carries substantial risk of loss; nothing here is investment advice.

Build it with Edgoro

Describe your strategy in plain English and get a TradingView indicator in Pine Script v6 or a MetaTrader 5 Expert Advisor in minutes. Every first purchase is covered by a 7-day money-back guarantee.

Build your indicator with Edgoro