Problem Description
Solution
In MQL4, there is no dedicated "metadata" field for orders. However, you can save extra information using two specific properties of an order:
- Magic Number (
int): The most robust method. It is a unique integer identifier assigned by the EA. Brokers do not modify this value. - Order Comment (
string): A text field. While easier to read, it is unreliable because brokers often overwrite comments (e.g., during partial closes or stop-loss triggers).
The best practice is to use the Magic Number to identify the strategy logic and map that number to a name within your code.
Implementation: Using Magic Numbers to Identify Strategies
The following code demonstrates a robust framework. It defines unique IDs for different strategies, assigns them when opening orders, and includes a helper function to read that ID and return the human-readable strategy name.
//+------------------------------------------------------------------+
//| StrategyIdentifier_Demo.mq4|
//| Copyright 2023, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
//--- 1. Define Unique IDs for your strategies
#define STRATEGY_TREND_FOLLOWING 1001
#define STRATEGY_MEAN_REVERSION 1002
#define STRATEGY_SCALPER 1003
//--- Input parameters
input double Lots = 0.1;
input int StopLoss = 50;
input int TakeProfit = 100;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
// Example: Open two trades with different Strategy IDs for testing
// Note: In a real EA, this would happen based on logic in OnTick
if(OrdersTotal() == 0)
{
// Open a Buy using the Trend Strategy ID
OpenTrade(OP_BUY, STRATEGY_TREND_FOLLOWING);
// Open a Sell using the Mean Reversion Strategy ID
OpenTrade(OP_SELL, STRATEGY_MEAN_REVERSION);
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Periodically check open orders to see which strategy opened them
ReportOpenOrders();
}
//+------------------------------------------------------------------+
//| Helper: Open a trade with a specific Magic Number (Strategy ID) |
//+------------------------------------------------------------------+
void OpenTrade(int type, int strategyID)
{
double price, sl, tp;
if(type == OP_BUY)
{
price = Ask;
sl = (StopLoss > 0) ? price - StopLoss * Point : 0;
tp = (TakeProfit > 0) ? price + TakeProfit * Point : 0;
}
else
{
price = Bid;
sl = (StopLoss > 0) ? price + StopLoss * Point : 0;
tp = (TakeProfit > 0) ? price - TakeProfit * Point : 0;
}
// --- CRITICAL STEP ---
// The 'strategyID' is passed as the 'magic' parameter (2nd to last)
int ticket = OrderSend(_Symbol, type, Lots, price, 3, sl, tp, "Trade Comment", strategyID, 0, clrNONE);
if(ticket < 0)
{
Print("OrderSend failed with error #", GetLastError());
}
else
{
Print("Order Opened. Ticket: ", ticket, " | Strategy ID: ", strategyID);
}
}
//+------------------------------------------------------------------+
//| Helper: Convert Magic Number ID to String Name |
//+------------------------------------------------------------------+
string GetStrategyName(int magicNumber)
{
switch(magicNumber)
{
case STRATEGY_TREND_FOLLOWING: return("Trend Following");
case STRATEGY_MEAN_REVERSION: return("Mean Reversion");
case STRATEGY_SCALPER: return("Scalper");
default: return("Unknown/Manual");
}
}
//+------------------------------------------------------------------+
//| Logic: Loop through orders and identify their origin |
//+------------------------------------------------------------------+
void ReportOpenOrders()
{
int total = OrdersTotal();
for(int i = 0; i < total; i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
// 1. Get the Magic Number
int magic = OrderMagicNumber();
// 2. Translate it to a name
string stratName = GetStrategyName(magic);
// 3. Print the info
Print("Ticket #", OrderTicket(),
" | Symbol: ", OrderSymbol(),
" | Magic: ", magic,
" | Strategy: ", stratName);
}
}
}
//+------------------------------------------------------------------+
Key Concepts Explained
-
#defineConstants:
We define readable names for integer IDs (e.g.,STRATEGY_TREND_FOLLOWINGis1001). This prevents "magic number" confusion in the code. -
OrderSendParameter:
TheOrderSendfunction signature is:
OrderSend(symbol, cmd, volume, price, slippage, sl, tp, comment, magic, expiration, arrow_color)
We pass our Strategy ID into the 9th parameter (magic). -
OrderMagicNumber():
When looping through orders usingOrderSelect, this function retrieves the integer we saved duringOrderSend. -
GetStrategyName():
Since the order only stores an integer (1001), we use aswitchstatement to map that integer back to a human-readable string ("Trend Following") for logging or on-screen display.
Alternative: Using Comments (Not Recommended)
You can pass a string to the 8th parameter of OrderSend (the comment field).
OrderSend(_Symbol, OP_BUY, Lots, Ask, 3, 0, 0, "TrendStrategy", 0, 0, clrNONE);
And read it back using:
string comment = OrderComment();
Why this is dangerous:
If you perform a partial close (e.g., closing 0.5 lots of a 1.0 lot position), the broker/server will automatically change the comment of the remaining position to something like "from #123456". Your original strategy tag ("TrendStrategy") will be deleted, and your code will lose track of the trade. Magic Numbers persist through partial closes.
Q&A: Trade Metadata in MQL4
Q: Can I change the Magic Number of an open trade?
A: No. The Magic Number is assigned when the order is created and cannot be modified via OrderModify. It is immutable for the life of the order.
Q: Can I store more complex data, like the value of an indicator at the time of entry?
A: Not directly in the order. To do this, you must use the Magic Number as a "Key". You would write the complex data to a CSV file or a Global Variable using the Order Ticket or Magic Number as the reference ID, and look it up later.
Q: What happens if I restart the terminal?
A: Magic Numbers are stored on the trade server. If you restart your terminal or move to a different computer, OrderMagicNumber() will still retrieve the correct ID.
Q: How do I handle manual trades?
A: Manual trades usually have a Magic Number of 0. You can handle this in your GetStrategyName function (as shown in the default case in the code above).