Discussão do artigo "Biblioteca para criação simples e rápida de programas para MetaTrader (Parte XXVI): trabalho com ordens de negociação pendentes - primeira implementação (abertura de posições)"

 

Novo artigo Biblioteca para criação simples e rápida de programas para MetaTrader (Parte XXVI): trabalho com ordens de negociação pendentes - primeira implementação (abertura de posições) foi publicado:

No artigo, abordaremos o armazenamento de alguns dados no valor do número mágico de ordens e posições, e implementaremos ordens pendentes. Para examinar a ideia, criaremos a primeira ordem pendente de teste para abrir posições a mercado quando recebermos um erro do servidor requerendo aguardar e enviar uma segunda solicitação.

Compilamos e iniciamos o EA. Desligamos a Internet de qualquer forma e aguardamos tal ícone no canto inferior direito do terminal:



Após desconectar a Internet e clicar no botão Sell, o servidor de negociação retorna um erro e no log são exibidas as seguintes entradas:

2019.11.26 15:34:48.661 CTrading::OpenPosition<uint,uint>: Invalid request:
2019.11.26 15:34:48.661 No connection with the trade server
2019.11.26 15:34:48.661 Correction of trade request parameters ...
2019.11.26 15:34:48.661 Trading attempt #1. Error: No connection with the trade server

Após receber desse erro, a biblioteca cria uma ordem pendente com os parâmetros existentes no momento da tentativa sem êxito de abrir uma posição curta.
A ordem pendente também contém o número de tentativas e um tempo de espera de 20 segundos.

Em seguida, conectamos a Internet, restaurando assim a comunicação com o servidor de negociação:


Assim que a conexão é restaurada, a biblioteca começa a processar a ordem pendente, enviando-a para o servidor. Como resultado, temos uma posição aberta com entradas no log:

2019.11.26 15:35:00.853 CTrading::OpenPosition<double,double>: Invalid request:
2019.11.26 15:35:00.853 Trading is prohibited for the current account
2019.11.26 15:35:00.853 Correction of trade request parameters ...
2019.11.26 15:35:00.853 Trading operation aborted
2019.11.26 15:35:01.192 CTrading::OpenPosition<double,double>: Invalid request:
2019.11.26 15:35:01.192 Trading is prohibited for the current account
2019.11.26 15:35:01.192 Correction of trade request parameters ...
2019.11.26 15:35:01.192 Trading operation aborted
2019.11.26 15:35:01.942 - Position is open: 2019.11.26 10:35:01.660 -
2019.11.26 15:35:01.942 EURUSD Opened 0.10 Sell #486405595 [0.10 Market-order Sell #486405595] at price 1.10126, sl 1.10285, tp 1.09985, Magic number 17629307 (123), G1: 13
2019.11.26 15:35:01.942 OnDoEasyEvent: Position is open

Como se pode ver no log, após reconectar ao servidor de negociação, a permissão de negociação para a conta atual não foi ativada imediatamente.
Mas, seja como for, a ordem pendente fez o que devia fazer
...

Também no log vemos o número mágico real 17629307, atrás dele entre parênteses vemos o magic definido nas configurações do EA (123), além de uma entrada G1: 13, que nos diz que o identificador do primeiro grupo é 13 e o identificador do segundo grupo não existe, pois seu valor acabou sendo zero, portanto, não foi gerao o segundo registro com os identificadores do segundo grupo G2: XX

Autor: Artyom Trishkin

 
Olá! Baixei a versão mais recente da biblioteca e do Expert Part_26, coloquei o modo visual no testador e as ordens de mercado são abertas, mas nem todas as ordens pendentes são.

As ordens de mercado são abertas, mas todas as ordens pendentes não são.

Símbolos de câmbio, corretor Otkritie, versão 5.00 build 2190.

 
Alexander:
Olá! Fiz o download da versão mais recente da biblioteca e do Expert Part_26, coloquei o modo visual e o modo de mercado no testador.

As ordens são abertas, mas todas as ordens pendentes não são.

Símbolos de câmbio, corretor Otkritie, versão 5.00 build 2190.

Fórum sobre negociação, sistemas de negociação automatizados e teste de estratégias de negociação

Discussão do artigo "Biblioteca para criação fácil e rápida de programas para MetaTrader (Parte XXV): Manipulação de erros retornados pelo servidor de negociação"

Artyom Trishkin, 2019.11.28 09:39

Nesta versão da biblioteca, bem como na próxima, não verifiquei os tipos de preenchimento de ordens e os tipos de expiração de ordens. Haverá correções no próximo artigo (27).

Por enquanto, posso sugerir que você especifique explicitamente o tipo de expiração ao enviar uma solicitação de negociação. Por exemplo, para colocar uma ordem pendente Sell Limit, você precisa adicioná-la no Expert Advisor de teste:

//--- Se o botão BUTT_SELL_LIMIT for pressionado: Definir SellLimit
else if(button==EnumToString(BUTT_SELL_LIMIT))
  {
   //--- Definir ordem SellLimit
   engine.PlaceSellLimit(lot,Symbol(),distance_pending,stoploss,takeprofit,magic,TextByLanguage("Pending SellLimit" (Limite de venda pendente),"Pending order SellLimit"),0,ORDER_TIME_DAY);
  }

E fazer o mesmo em todas as linhas que contêm a chamada de métodos para definir ordens pendentes.


 
Sim, obrigado, é assim que funciona.
 
//--- Localização dos dados no valor do número mágico int
      //-----------------------------------------------------------
      // bit 32|31 24|2316|15 8|7 0|
      //-----------------------------------------------------------
      // byte | 3 | 2| 1 | 0 |
      //-----------------------------------------------------------
      // dados | uchar | uchar | ushort |
      //-----------------------------------------------------------
      // descr |pend req id| id2 | id1 | magic |
      //----------------------------------------------------------- 
//--- Retorna (1) o número mágico especificado, a ID do (2) primeiro grupo, (3) segundo grupo, (4) solicitação pendente do valor do número mágico
   ushort            GetMagicID(void)                                const { return ushort(this.Magic() & 0xFFFF);                                 }
   uchar             GetGroupID1(void)                               const { return uchar(this.Magic()>>16) & 0x0F;                                }
   uchar             GetGroupID2(void)                               const { return uchar((this.Magic()>>16) & 0xF0)>>4;                           }
   uchar             GetPendReqID(void)                              const { return uchar(this.Magic()>>24) & 0xFF;                                }

Existe uma função conveniente para extrair bits de um número.

//--- extrair bits cnt na posição do k-ésimo bit
   uint              _getBits(const uint number,uint pos,uint cnt=1) const { return (number >> pos) & ((1 << cnt) - 1);                            }
      
   ushort            GetMagicID(void)                                const { return ushort(_getBits(this.Magic(),0,16));                           }
   uchar             GetGroupID1(void)                               const { return uchar(_getBits(this.Magic(),16,4));                            }
   uchar             GetGroupID2(void)                               const { return uchar(_getBits(this.Magic(),20,4));                            }
   uchar             GetPendReqID(void)                              const { return uchar(_getBits(this.Magic(),24,8));                            }
 
amrali:

Existe uma função conveniente para extrair bits de um número.

Agradecimentos
 
Existe uma implementação na biblioteca para abrir uma execução de mercado imediata?
 
iabbott:
Existe uma implementação na biblioteca para abrir uma execução de mercado imediata?
Sim
 

Você poderia me dizer, por favor, onde exatamente, em que método, você decodifica a mágica codificada na solicitação pendente?

Após um erro ao abrir uma posição(fundos insuficientes) e acionar uma solicitação pendente, tenho uma posição criada com uma mágica completamente diferente (aparentemente, a que foi codificada).

Onde você a decodifica? Quero uma mágica nativa, não uma nova.

 
void CTradingControl::OnPReqByErrCodeHandler()

É aqui que você deve chamar o método que retorna a mágica original. E que método é esse? GetMagicID()?

 
//+------------------------------------------------------------------+
//| Retorna o lucro da ordem em pips|
//+------------------------------------------------------------------+
int COrder::ProfitInPoints(void) const
  {
   MqlTick tick={0};
   string symbol=this.Symbol();
   if(!::SymbolInfoTick(symbol,tick))
      return 0;
   ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)this.TypeOrder();
   double point=::SymbolInfoDouble(symbol,SYMBOL_POINT);
   if(type==ORDER_TYPE_CLOSE_BY || point==0) return 0;
   if(this.Status()==ORDER_STATUS_HISTORY_ORDER)
      return int(type==ORDER_TYPE_BUY ? (this.PriceClose()-this.PriceOpen())/point : type==ORDER_TYPE_SELL ? (this.PriceOpen()-this.PriceClose())/point : 0);
   else if(this.Status()==ORDER_STATUS_MARKET_POSITION)
     {
      if(type==ORDER_TYPE_BUY)
         return int((tick.bid-this.PriceOpen())/point);
      else if(type==ORDER_TYPE_SELL)
         return int((this.PriceOpen()-tick.ask)/point);
     }
   else if(this.Status()==ORDER_STATUS_MARKET_PENDING)
     {
      if(type==ORDER_TYPE_BUY_LIMIT || type==ORDER_TYPE_BUY_STOP || type==ORDER_TYPE_BUY_STOP_LIMIT)
         return (int)fabs((tick.bid-this.PriceOpen())/point);
      else if(type==ORDER_TYPE_SELL_LIMIT || type==ORDER_TYPE_SELL_STOP || type==ORDER_TYPE_SELL_STOP_LIMIT)
         return (int)fabs((this.PriceOpen()-tick.ask)/point);
     }
   return 0;
  }

Por que não há cálculo aqui para o tipo ORDER_STATUS_DEAL?

Em geral, não está claro como obter o lucro em pontos de uma negociação ou posição fechada...
E é sempre 0:

deal_profit_pts=(int)deal.GetProperty(ORDER_PROP_PROFIT_PT)