Expert_ID MT4

เริ่มโดย admin, ธันวาคม 22, 2015, 10:53:32 PM

« หน้าที่แล้ว - ต่อไป »

admin

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 temrinal 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 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", 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( "Ошибка 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.
บจก.สยามเอวีเอส
63 Moo 2 แพรกษาใหม่ เมือง สมุทรปราการ
นำเข้า-จำหน่าย เครื่องจักร cnc มือสองญี่ปุ่น
ติดต่อ คุณ ธนเดช  084-387-2401
EMAIL kiattub@gmail.com
คลิกลิ้งแอดไลน์ได้เลย Line id : boysiamavs
http://line.me/ti/p/~boysiamavs