MagicNumber: "Magic" Identifier of the Order
1. Preamble
In МТ3, management of open positions was rather time-taking. Traders had at their disposal a rather limited tool set to work with the list of open and closed positions. The problem of distinguishing between "own" and "someone else's" positions was solved in rather complicated ways. In МТ4, the situation has cardinally changed. Now, trader can use a great variety of functions and fully manage all open positions and placed orders and get access to information about any closed positions.
A special parameter named MagicNumber was added to identify orders. This is the
parameter our article will deal with.
2. What Is MagicNumber?
MQL4 Reference:
int OrderSend( string symbol, int cmd, double volume, double price, int slippage, double stoploss,
double takeprofit, string comment=NULL, int magic=0, datetime expiration=0, color arrow_color=CLR_NONE)
…
magic - Order magic number. May be used as user defined identifier
I.e., when an order is being placed (a position is being opened), one can assign a unique number to it. This number will consequently be used to distinguish the above order from others. There is no use (or even possibility) applying this feature when trading manually, but it is really unexpendable when trading using an expert (automated trading).
Example 1: A human trader and an expert are trading in the client terminal at the same time.
Task: The expert must trade according to its algorithm and may not do anything with positions
opened manually.
Solution: The expert must assign a unique, non-zero MagicNumber to the position being opened.
In future, it must manage only positions, the MagicNumber of which is equal to
the preset one.
Example 2: Two experts with different algorithms are trading in the client terminal at the
same time.
Task: The expert must manage only "their" orders.
Solution: Each expert must use its unique non-zero MagicNumber when opening positions. In
future, they must manage only positions, the MagicNumber of which is equal to the
preset one.
Example 3: Several experts, a human trader and an assisting expert realizing a non-standard
Trailing Stop are operating in the client terminal simultaneously.
Task: Trading experts must work according to their algorithms and may not do anything
with positions opened manually. The assisting expert that realizes Trailing Stop
may modify only positions opened manually, but not those opened by other experts.
Solution: The trading experts must use unique MagicNumbers and manage only "their"
positions. The assisting expert must modify only those positions having MagicNumber
equal to 0.
All three examples are quite realistic, and the users could probably have set such problems for themselves. In all three cases, the MagicNumber is used to solve it. This way is not the unique one, but the easiest.
3. Realization
Now let us solve the specific task: create an expert that could work only with its "own" positions without paying attention to positions opened manually or by other experts.
Let us first write a simple expert, for which the signal to open a position will
be when the MACD indicator meets zero line. The expert will look like this:
int start() { //---- Remember the indicator's values for further analysis //---- Note that we use the 1st and the 2nd bar. This allows a 1-bar delay //---- (i.e., the signal will appear later), but protects against repeated opening and closing //---- of positions within a bar double MACD_1 = iMACD( Symbol(), 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 1 ); double MACD_2 = iMACD( Symbol(), 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 2 ); int _GetLastError = 0, _OrdersTotal = OrdersTotal(); //---- search in all open positions for ( int z = _OrdersTotal - 1; z >= 0; z -- ) { //---- if an error occurs at selecting of a position, go to the next one if ( !OrderSelect( z, SELECT_BY_POS ) ) { _GetLastError = GetLastError(); Print( "OrderSelect( ", z, ", SELECT_BY_POS ) - Error #", _GetLastError ); continue; } //---- if the position was opened not for the current symbol, skip it if ( OrderSymbol() != Symbol() ) continue; //---- if the BUY position has been opened, if ( OrderType() == OP_BUY ) { //---- if the MACD has met the zero line top-down, if ( NormalizeDouble( MACD_1, Digits + 1 ) < 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0 ) { //---- close the position if ( !OrderClose( OrderTicket(), OrderLots(), Bid, 5, Green ) ) { _GetLastError = GetLastError(); Alert( "Error OrderClose # ", _GetLastError ); return(-1); } } //---- if the alert has not been changed, exit: it is too early for opening a new position else return(0); } //---- if the SELL position has been opened, if ( OrderType() == OP_SELL ) { //---- if the MACD has met the zero line bottom-up, if ( NormalizeDouble( MACD_1, Digits + 1 ) > 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0 ) { //---- close the position if ( !OrderClose( OrderTicket(), OrderLots(), Ask, 5, Red ) ) { _GetLastError = GetLastError(); Alert( "Error OrderClose # ", _GetLastError ); return(-1); } } //---- if the alert has not been changed, exit: it is too early for opening a new position else return(0); } } //+------------------------------------------------------------------+ //| if execution reached this point, there is no open position | //| check whether it is still possible to open a position | //+------------------------------------------------------------------+ //---- if the MACD has met the zero line bottom-up, if ( NormalizeDouble( MACD_1, Digits + 1 ) > 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0 ) { //---- open a BUY position if ( OrderSend( Symbol(), OP_BUY, 0.1, Ask, 5, 0.0, 0.0, "MACD_test", 0, 0, Green ) < 0 ) { _GetLastError = GetLastError(); Alert( "Error OrderSend # ", _GetLastError ); return(-1); } return(0); } //---- if the MACD has met the zero line top-down, if ( NormalizeDouble( MACD_1, Digits + 1 ) < 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0 ) { //---- open a SELL position if ( OrderSend( Symbol(), OP_SELL, 0.1, Bid, 5, 0.0, 0.0, "MACD_test", 0, 0, Red ) < 0 ) { _GetLastError = GetLastError(); Alert( "Error OrderSend # ", _GetLastError ); return(-1); } return(0); } return(0); }
Let us attach it to the chart and see how it works:
Everything is ok, but there is one problem here. If we open a position during the expert's operation, it will consider this position as its "own" and act accordingly. This is not what we want.
We will modify our expert in such a way that it manages only its "own" positions:
- Add the external variable named Expert_ID to be used for changing the MagicNumber values for positions opened by the expert
- After the position has been selected by the OrderSelect() function, add checking for whether the MagicNumber of the selected order complies with that of the Expert_ID variable
- We will write the value of the Expert_ID instead of 0 into the MagicNumber field during position opening
Considering the above changes, the code will appear as follows:
extern int Expert_ID = 1234; int start() { //---- Remember the indicator's values for further analysis //---- Note that we use the 1st and the 2nd bar. This allows a 1-bar delay //---- (i.e., the signal will appear later), but protects against repeated opening and closing //---- positions within a bar double MACD_1 = iMACD( Symbol(), 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 1 ); double MACD_2 = iMACD( Symbol(), 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 2 ); int _GetLastError = 0, _OrdersTotal = OrdersTotal(); //---- search in all open positions for ( int z = _OrdersTotal - 1; z >= 0; z -- ) { //---- if an error occurs when searching for a position, go to the next one if ( !OrderSelect( z, SELECT_BY_POS ) ) { _GetLastError = GetLastError(); Print( "OrderSelect( ", z, ", SELECT_BY_POS ) - Error #", _GetLastError ); continue; } //---- if a position is closed not for the current symbol, skip it if ( OrderSymbol() != Symbol() ) continue; //---- if the MagicNumber is not equal to the Expert_ID, skip this position if ( OrderMagicNumber() != Expert_ID ) continue; //---- if a BUY position is opened, if ( OrderType() == OP_BUY ) { //---- if the MACD has met the zero line top-down, if ( NormalizeDouble( MACD_1, Digits + 1 ) < 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0 ) { //---- close the position if ( !OrderClose( OrderTicket(), OrderLots(), Bid, 5, Green ) ) { _GetLastError = GetLastError(); Alert( "Error OrderClose # ", _GetLastError ); return(-1); } } //---- if the alert has not changed, exit: it is too early to open a new position else { return(0); } } //---- if a SELL position is opened, if ( OrderType() == OP_SELL ) { //---- if the MACD has met the zero line bottom-up, if ( NormalizeDouble( MACD_1, Digits + 1 ) > 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0 ) { //---- close the position if ( !OrderClose( OrderTicket(), OrderLots(), Ask, 5, Red ) ) { _GetLastError = GetLastError(); Alert( "Error OrderClose № ", _GetLastError ); return(-1); } } //---- if the alert has not changed, exit: it is too early to open a new position else return(0); } } //+------------------------------------------------------------------+ //| if execution reached this point, there is no an open position | //| check whether it is still possible to open a position | //+------------------------------------------------------------------+ //---- if the MACD has met the zero line bottom-up, if ( NormalizeDouble( MACD_1, Digits + 1 ) > 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0 ) { //---- open a BUY position if ( OrderSend( Symbol(), OP_BUY, 0.1, Ask, 5, 0.0, 0.0, "MACD_test", Expert_ID, 0, Green ) < 0 ) { _GetLastError = GetLastError(); Alert( "Error OrderSend # ", _GetLastError ); return(-1); } return(0); } //---- if the MACD has met the zero line top-down, if ( NormalizeDouble( MACD_1, Digits + 1 ) < 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0 ) { //---- open a SELL position if ( OrderSend( Symbol(), OP_SELL, 0.1, Bid, 5, 0.0, 0.0, "MACD_test", Expert_ID, 0, Red ) < 0 ) { _GetLastError = GetLastError(); Alert( "Error OrderSend # ", _GetLastError ); return(-1); } return(0); } return(0); }
Now, when the expert is working, the user can open positions manually. The expert will not touch them.
4. Multiple Identic Experts on Different Charts of One Symbol
There are cases where the same EA must trade on the charts of the same symbol, but with different timeframes, for instance. If we try to attach our expert to the chart EURUSD, H1, and to the EURUSD, M30, simultaneously, they will interfere each other: each will "consider" the open position to be "its" position and modify it at its discretion.
This problem can be solved by assigning another Expert_ID to the other expert. But this is not very convenient. If there are many experts used, one can just get entangled among their IDs.
We can meet this problem using the chart period as MagicNumber. How shall we do it? If we just add the chart period to the Expert_ID, it is possible that 2 different experts on 2 different charts generate the same MagicNumber.
So we will better multiply Expert_ID by 10 and put the chart period (its code from 1 to 9, to be exact) at the end.
It will look something like this:
int Period_ID = 0; switch ( Period() ) { case PERIOD_MN1: Period_ID = 9; break; case PERIOD_W1: Period_ID = 8; break; case PERIOD_D1: Period_ID = 7; break; case PERIOD_H4: Period_ID = 6; break; case PERIOD_H1: Period_ID = 5; break; case PERIOD_M30: Period_ID = 4; break; case PERIOD_M15: Period_ID = 3; break; case PERIOD_M5: Period_ID = 2; break; case PERIOD_M1: Period_ID = 1; break; } _MagicNumber = Expert_ID * 10 + Period_ID;
Now add this code to the expert's init() function and replace Expert_ID with _MagicNumber everywhere.
The final version of the EA looks like this:
extern int Expert_ID = 1234; int _MagicNumber = 0; int init() { int Period_ID = 0; switch ( Period() ) { case PERIOD_MN1: Period_ID = 9; break; case PERIOD_W1: Period_ID = 8; break; case PERIOD_D1: Period_ID = 7; break; case PERIOD_H4: Period_ID = 6; break; case PERIOD_H1: Period_ID = 5; break; case PERIOD_M30: Period_ID = 4; break; case PERIOD_M15: Period_ID = 3; break; case PERIOD_M5: Period_ID = 2; break; case PERIOD_M1: Period_ID = 1; break; } _MagicNumber = Expert_ID * 10 + Period_ID; return(0); } int start() { //---- Remember the indicator's values for further analysis //---- Note that we use the 1st and the 2nd bar. This allows a 1-bar delay //---- (i.e., the signal will appear later), but protects against repeated opening and closing //---- positions within a bar double MACD_1 = iMACD( Symbol(), 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 1 ); double MACD_2 = iMACD( Symbol(), 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 2 ); int _GetLastError = 0, _OrdersTotal = OrdersTotal(); //---- search in all open positions for ( int z = _OrdersTotal - 1; z >= 0; z -- ) { //---- if an error occurs when searching for a position, go to the next one if ( !OrderSelect( z, SELECT_BY_POS ) ) { _GetLastError = GetLastError(); Print( "OrderSelect( ", z, ", SELECT_BY_POS ) - Error #", _GetLastError ); continue; } //---- if a position is opened not for the current symbol, skip it if ( OrderSymbol() != Symbol() ) continue; //---- if the MagicNumber is not equal to _MagicNumber, skip this position if ( OrderMagicNumber() != _MagicNumber ) continue; //---- if a BUY position is opened, if ( OrderType() == OP_BUY ) { //---- if the MACD has met the zero line top-down, if ( NormalizeDouble( MACD_1, Digits + 1 ) < 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0 ) { //---- close the position if ( !OrderClose( OrderTicket(), OrderLots(), Bid, 5, Green ) ) { _GetLastError = GetLastError(); Alert( "Error OrderClose # ", _GetLastError ); return(-1); } } //---- if the alert has not been changed, quit: it is too early to open a new position else return(0); } //---- if a SELL position is opened, if ( OrderType() == OP_SELL ) { //---- if the MACD has met the zero line bottom-up, if ( NormalizeDouble( MACD_1, Digits + 1 ) > 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0 ) { //---- close the position if ( !OrderClose( OrderTicket(), OrderLots(), Ask, 5, Red ) ) { _GetLastError = GetLastError(); Alert( "Error OrderClose № ", _GetLastError ); return(-1); } } //---- if the alert has not changed, quit: it is too early to open a new position else return(0); } } //+------------------------------------------------------------------+ //| if execution reached this point, there is no an open position | //| check whether it is still possible to open a position | //+------------------------------------------------------------------+ //---- if the MACD has met the zero line bottom-up, if ( NormalizeDouble( MACD_1, Digits + 1 ) > 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0 ) { //---- open a BUY position if ( OrderSend( Symbol(), OP_BUY, 0.1, Ask, 5, 0.0, 0.0, "MACD_test", _MagicNumber, 0, Green ) < 0 ) { _GetLastError = GetLastError(); Alert( "Error OrderSend # ", _GetLastError ); return(-1); } return(0); } //---- if the MACD has met the zero line top-down, if ( NormalizeDouble( MACD_1, Digits + 1 ) < 0.0 && NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0 ) { //---- open a SELL position if ( OrderSend( Symbol(), OP_SELL, 0.1, Bid, 5, 0.0, 0.0, "MACD_test", _MagicNumber, 0, Red ) < 0 ) { _GetLastError = GetLastError(); Alert( "Error OrderSend # ", _GetLastError ); return(-1); } return(0); } return(0); }
In such appearance, the expert can be used on several charts with different periods.
The Expert_ID variable value will be to change only if there is a need to launch
two experts on charts of the same symbol and period (for example, EURUSD H1 and
EURUSD H4), but this happens extremely rarely.
Similarly, using the above code, the user can improve his or her EAs and "teach"
them to distinguish "their" positions from the "foreign" ones.
Translated from Russian by MetaQuotes Ltd.
Original article: https://www.mql5.com/ru/articles/1359
- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
Andrey
have you considered having the EA generate its own ID at start up and have the ability to not only see its own orders but to be able to track each of its orders even if it has 100 orders open. It would have to have the ability to recover its ID or restates as well. With that you can create a function to be called in the int() function at start up.
I need to know how to get the minimal magic number available.
Example: there are two open orders with magic numbers "1" and "3", so the minimal available is "2"