English Русский 中文 Español Deutsch 日本語
MagicNumber: Identificador "mágico" do pedido

MagicNumber: Identificador "mágico" do pedido

MetaTrader 4Exemplos | 18 fevereiro 2016, 09:28
6 529 0
Andrey Khatimlianskii
Andrey Khatimlianskii

1. Preâmbulo

No MT3, o gerenciamento de posições consumia bastante tempo. Traders tinham à disposição um conjunto de ferramentas bastante limitado para trabalhar com a lista de posições abertas e fechadas. O problema de distinguir entre as "próprias" posições e as "alheias" era resolvido de modos bastante complicados. No MT4 esta situação mudou radicalmente. Agora o trader pode usar uma grande variedade de funções e gerenciar completamente todas as posições abertas e pedidos realizados, e ter acesso a informações sobre quaisquer posições fechadas.

Um parâmetro especial chamado MagicNumber foi adicionado para identificar os pedidos. Este é o parâmetro do qual o nosso artigo irá tratar.

2. O que é o MagicNumber?

A referência MQL4:

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. Pode ser usada como um identificador definido pelo usuário


Por exemplo, quando um pedido está sendo feito (uma posição está sendo aberta), pode-se atribuir um número único a ele. Este número será consequentemente usado para distinguir o pedido acima dos outros. Não há utilidade (ou sequer possibilidade) na aplicação deste recurso ao se realizar transações manualmente, mas ele é indispensável ao se realizar transações utilizando um sistema especializado (transações automatizadas).


Exemplo 1: Um trader humano e um sistema especializado estão realizando transações no terminal do cliente simultaneamente.
Tarefa: O sistema especializado deve realizar transações de acordo com o seu algoritmo, e não deve fazer nada em relação às posições abertas manualmente.
Solução: O sistema especializado deve atribuir um MagicNumber único e diferente de zero à posição sendo aberta. No futuro, ele deve gerenciar apenas posições cujo MagicNumber é igual ao predefinido.

Exemplo 2: Dois sistemas especializados com algoritmos diferentes estão realizando transações no terminal do cliente simultaneamente.
Tarefa: O sistema especializado deve gerenciar apenas os "seus" pedidos.
Solução: Cada sistema especializado deve usar o seu MagicNumber único e diferente de zero ao abrir posições. No futuro, eles devem gerenciar apenas posições cujo MagicNumber é igual ao pré-definido.

Exemplo 3: Vários sistemas especializados, um trader humano e um sistema especializado assistente realizando um limite móvel não padrão estão realizando transações em um terminal do cliente simultaneamente.
Tarefa: Os sistemas especializados devem trabalhar de acordo com os seus algoritmos, e não deve fazer nada em relação às posições abertas manualmente. O sistema especializado assistente que realiza limites móveis pode modificar apenas as posições abertas manualmente, mas não aquelas abertas por outros sistemas especializados.
Solução: Os sistemas especializados devem usar MagicNumbers únicos e gerenciar apenas as "suas" posições. O sistema especializado assistente deve modificar apenas aquelas posições que possuam um MagicNumber igual a 0.

Todos os três exemplos são bastante realistas, e os usuários provavelmente poderiam se deparar com tais problemas. Em todos os três casos, o MagicNumber é usado para resolver o problema. Esta não é a única solução, mas é a mais simples.

3. Realização

Vamos agora completar esta tarefa específica: criar um sistema especializado que poderia trabalhar apenas com as suas "próprias" posições, sem dar atenção a posições abertas manualmente ou por outros sistemas especializados.

Vamos primeiro escrever um sistema especializado simples, para o qual o sinal de abrir uma posição ocorrerá quando o indicador MACD chegar à linha zero. O sistema especializado terá a seguinte aparência:

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);
}


Vamos conectá-lo ao gráfico e ver como ele se sai:



Tudo está indo bem, mas há um problema aqui. Se nós abrirmos uma posição durante a operação do sistema especializado, ele irá considerar esta posição como sendo "sua", e agirá de acordo. Não é isso que nós queremos.

Nós iremos modificar o nosso sistema especializado de modo que ele passe a gerenciar apenas as suas "próprias" posições:

  • Adicione uma variável externa chamada Expert_ID, que será usada para alterar os valores do MagicNumber em relação a posições abertas pelo sistema especializado
  • Após a posição ter sido selecionada pela função OrderSelect(), e termos verificado se o MagicNumber do pedido selecionado corresponde ao da variável Expert_ID
  • Nós iremos escrever o valor do Expert_ID ao invés de 0 no campo do MagicNumber durante a abertura de posição

Considerando as alterações acima, o código será assim:

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);
}


Agora, quando o sistema especializado estiver em funcionamento, o usuário poderá abrir posições manualmente. O sistema especializado não irá interferir com eles.


4. Múltiplos sistemas especializados idênticos em diferentes gráficos de um símbolo

Há casos nos quais o mesmo EA deve realizar transações nos mesmos gráficos do mesmo símbolo, mas com cronogramas diferentes, por exemplo. Se nós tentarmos conectar o nosso sistema especializado ao gráfico EURUSD, H1, e ao EURUSD, M30, simultaneamente, eles irão interferir um com o outro: cada um irá "considerar" a posição aberta como sendo "sua", e modificá-la como bem entender.

Este problema pode ser resolvido através da atribuição de outro Expert_ID ao outro sistema especializado. Mas isso não é muito conveniente. Caso muitos sistemas especializados estejam sendo usados, é possível se perder entre os seus IDs.

Nós podemos resolver este problema usando o período do gráfico como o MagicNumber. Como podemos fazer isso? Se nós simplesmente adicionarmos o período do gráfico ao Expert_ID, é possível que 2 sistemas especializados diferentes em 2 gráficos diferentes gerem o mesmo MagicNumber.

Então é melhor multiplicar o Expert_ID por 10 e colocar o período do gráfico (o seu código, de 1 a 9, para ser preciso) no final.

Ele ficará parecido com isto:

    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;

Agora adicione este código à função init() do sistema especializado e substitua Expert_ID por _MagicNumber em todas as ocorrências.



A versão final do EA terá a seguinte aparência:

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);
}


Com esta aparência, o sistema especializado pode ser usado em vários gráficos com diferentes períodos.

O valor variável de Expert_ID será alterado apenas se houver a necessidade de executar dois sistemas especializados em gráficos que possuam o mesmo símbolo e período (por exemplo, EURUSD H1 e EURUSD H4), mas isso é bastante raro.


De modo semelhante, o usuário pode usar o código acima para melhorar os seus EAs e "ensiná-los" a distinguir entre as "suas" posições e as "alheias".

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/1359

Expert Advisor gráfico: AutoGraf Expert Advisor gráfico: AutoGraf
O artigo mostra a operacionalidade de gráficos na criação de uma interface conveniente para o gerenciamento de transações.
Uma pausa entre operações Uma pausa entre operações
O artigo trata do problema relativo a como organizar pausas entre operações de comércio quando vários sistemas especializados trabalham em um terminal do cliente MT4. Ele é destinado a usuários que possuam habilidades básicas no trabalho com o terminal e em programação em MQL4.
Trabalhando com arquivos. Um exemplo de visualização de eventos de mercado importantes Trabalhando com arquivos. Um exemplo de visualização de eventos de mercado importantes
O artigo trata das perspectivas do uso do MQL4 para a realização de trabalhos mais produtivos nos mercados FOREX.
Teoria de Mercado Teoria de Mercado
A lógica completa da teoria do mercado que cobre todos os tipos e variedades de mercados de bens e serviços, não estava disponível até agora aos mercados micro e macro, como o Forex. Este artigo aborda a essência de uma nova teoria do mercado com base na análise do lucro, revela padrões de mudança dos preços em andamento e o princípio da operação de um mecanismo a permitir que o preço encontre o seu valor ideal, através da formação de uma cadeia de preços virtuais que desenvolvem um controle sobre o preço real. Mecanismos de formação e de mudança das tendências do mercado também são identificados aqui.