Problem Description
Solution
To ensure your Expert Advisor (EA) manages only its own trades and ignores trades opened by manual execution or other EAs, you must use a Magic Number.
A Magic Number is a unique integer identifier assigned to an order when it is opened. When the EA scans the market to modify or close trades, it checks if the order's Magic Number matches its own.
Here is the complete implementation guide and code structure.
1. Define the Magic Number Input
First, define an input variable so you can assign a unique ID to this specific instance of the EA.
//--- Input Parameters
input int MagicNumber = 123456; // Unique identifier for this EA
input int Slippage = 3; // Max slippage in points
2. Assign the Magic Number When Opening Trades
When calling the OrderSend() function, pass the MagicNumber variable in the correct parameter slot (the 10th parameter).
// Example of opening a BUY order with the Magic Number
int ticket = OrderSend(
Symbol(), // Symbol
OP_BUY, // Operation
0.1, // Volume
Ask, // Price
Slippage, // Slippage
0, // Stop Loss
0, // Take Profit
"My EA Trade", // Comment
MagicNumber, // <--- MAGIC NUMBER GOES HERE
0, // Expiration
clrGreen // Color
);
3. Filter Orders by Magic Number
Whenever your EA needs to count, modify, or close trades, you must iterate through the order pool and check two conditions:
OrderMagicNumber() == MagicNumber: Ensures the trade belongs to this EA.OrderSymbol() == Symbol(): Ensures the trade is for the chart the EA is running on.
Complete Implementation Example
Below is a template for an EA that counts its own trades and applies a Trailing Stop, completely ignoring all other positions on the account.
//+------------------------------------------------------------------+
//| MagicNumber_Manager.mq4 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
//--- Input Parameters
input int MagicNumber = 12345; // Unique ID for this EA instance
input double TrailingStop = 50; // Trailing Stop in points (0 to disable)
input double LotSize = 0.01; // Trade volume
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// 1. Count ONLY trades belonging to this EA
int myBuyOrders = 0;
int mySellOrders = 0;
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
// FILTER: Check Symbol AND Magic Number
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
if(OrderType() == OP_BUY) myBuyOrders++;
if(OrderType() == OP_SELL) mySellOrders++;
}
}
}
// 2. Simple Entry Logic (Example: Open Buy if no Buys exist)
if(myBuyOrders == 0)
{
int ticket = OrderSend(Symbol(), OP_BUY, LotSize, Ask, 3, 0, 0, "MagicEA", MagicNumber, 0, clrBlue);
if(ticket < 0) Print("OrderSend failed with error #", GetLastError());
}
// 3. Manage Trades (Trailing Stop)
ManageMyTrades();
}
//+------------------------------------------------------------------+
//| Function to manage ONLY this EA's trades |
//+------------------------------------------------------------------+
void ManageMyTrades()
{
// Loop through all open orders
for(int i = 0; i < OrdersTotal(); i++)
{
// Select the order
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
// CRITICAL: Filter by Symbol and Magic Number
if(OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber)
continue; // Skip this order if it doesn't belong to us
//--- Logic for BUY orders
if(OrderType() == OP_BUY)
{
// Check if price has moved enough to trail
if(Bid - OrderOpenPrice() > TrailingStop * Point)
{
// Check if the new Stop Loss is higher than the current one
if(OrderStopLoss() < Bid - TrailingStop * Point)
{
bool res = OrderModify(OrderTicket(), OrderOpenPrice(), Bid - TrailingStop * Point, OrderTakeProfit(), 0, clrNONE);
if(!res) Print("Error modifying Buy order: ", GetLastError());
}
}
}
//--- Logic for SELL orders
if(OrderType() == OP_SELL)
{
// Check if price has moved enough to trail
if(OrderOpenPrice() - Ask > TrailingStop * Point)
{
// Check if the new Stop Loss is lower than the current one (or if SL is 0)
if(OrderStopLoss() > Ask + TrailingStop * Point || OrderStopLoss() == 0)
{
bool res = OrderModify(OrderTicket(), OrderOpenPrice(), Ask + TrailingStop * Point, OrderTakeProfit(), 0, clrNONE);
if(!res) Print("Error modifying Sell order: ", GetLastError());
}
}
}
}
}
}
Key Takeaways
- Uniqueness: If you run this EA on two different charts (e.g., EURUSD and GBPUSD), you can use the same Magic Number because the
OrderSymbol() == Symbol()check separates them. - Same Symbol: If you run two instances of the EA on the same symbol (e.g., two EURUSD charts with different timeframes), you must change the
MagicNumberinput for the second instance (e.g., 12345 and 12346) to prevent them from managing each other's trades.
Q&A
Q: What happens if I set the Magic Number to 0?
A: A Magic Number of 0 is generally treated as a manually opened trade. If your EA uses 0, it might accidentally manage trades you opened manually from your phone or terminal. Always use a non-zero integer (e.g., 12345).
Q: Can I change the Magic Number of an open trade?
A: No. Once an order is opened using OrderSend, the Magic Number is permanently attached to that specific ticket. It cannot be modified.
Q: How do I handle Magic Numbers when using OrderCloseBy?
A: OrderCloseBy closes one order using another opposite order. The resulting trade (if there is a remaining volume) usually retains the Magic Number of the order that initiated the close, but this behavior can vary slightly by broker implementation. It is best to ensure both orders involved have the same Magic Number.