
MagicNumber: Identificador "mágico" do pedido
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





- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso