Dúvida sobre OrderSelect() e OrdersTotal()

 

Olá a todos.

Estou desenvolvendo uma função para agredir o preço BID com as ordens pendentes de venda, e me deparei com algumas dúvidas, pois na conta demo, é quase tudo uma maravilha.

Está descrito abaixo o funcionamento da função, porém vou dar um resumo básico:

 - a função, primeiramente, guarda o valor de BID em uma variável local para garantir o preço de agressão sempre igual.

 - coleta a ordem de venda com o maior preço; modifica o preço para o valor guardado na variável local (valor BID naquele momento) e envia a ordem; se sobrou saldo de cotas, a ordem é alterada para o preço original, que também está guardado numa variável local;

 - se a ordem de venda foi totalmente executada, será coletada uma nova ordem de venda com maior preço, repetindo os passos descritos acima; 

OBS.: Estou em posição comprada, logo a função executa operações de venda, me "retirando" do mercado. Em Fundos Imobiliários, não é possível posicionar vendido.

Acredito que estou fazendo alguma confusão com a forma como as ordens são executadas, como coletar dados para averiguação. A função descrita abaixo pode não estar semanticamente correta.

Este trecho de código é executado após o envio da ordem de venda, com o preço modificado para o valor BID (agressão de venda), pois preciso saber se a ordem tem saldo de cotas. Se houver saldo, preciso modificar novamente a ordem de venda para o seu preço original, que está guardado na variável ' current_order_price'. 

         // trecho de código para alterar a ordem se houver cotas não executadas.
         ticket = result.order;          
         if(!OrderSelect(ticket)){ // <= isso está estranho

Procurando aqui na comunidade, encontrei um tópico (https://www.mql5.com/pt/forum/87308) que me ajudou a clarear um pouco as coisas. Já entendi que uma ordem executada em sua totalidade não pode ser selecionada por ' OrderSelect()', então vem a primeira dúvida:

 - na lógica da função que desenvolvi, se a ordem foi totalmente executada, será coletada uma nova ordem de venda, para agredir BID. Então ...

  if(!OrderSelect(ticket)){ // <= isso está estranho
         
     PrintFormat("OrderSelect error %d",GetLastError());     // if unable to send the request, output the error code
     ResetLastError();
     //end_of_processing = true; // to exit do-while
     continue; // pula para a próxima iteração     
  }

... se o 'OrderSelect()' retornar 'false', significa que a ordem foi totalmente executada. 

E a dúvida está justamente nessa forma de verificação, que não parece ser a mais adequada, apesar de ter lógica.

A outra questão está no loop que optei usar (do-while).

Optei por usar um do-while para garantir que, a cada iteração, sempre vou pegar o valor atual de 'OrdersTotal()' para pesquisar por uma nova ordem de venda. Pelo que entendi, através de outros questionamentos, como há o "risco" de uma execução total de uma ordem, ' OrdersTotal()'  vai ser alterado. Lógico que mesmo tendo esse cuidado, e se eu não estiver errado, um evento de trade pode acontecer durante a execução da função descrita abaixo.

A outra dúvida é se esse do-while faz sentido neste caso, ou se tem uma outra forma de abordagem. 


/**
   Função para agredir, com todas as ordens pendentes de venda, exclusivamente e somente, na melhor oferta de compra (BID).
   
   Funcionamento:
    1 - o valor da melhor oferta de compra (BID), será atribuido a uma variável local;
    2 - será coletada a ordem de venda mais distante do preço ASK (ou seja, com maior preço);
    3 - será modificado o preço, desta ordem de venda, para o preço BID, atribuido a uma 
    variável local;
    4 - caso a ordem de venda seja integralmente executada, será repetido 
    os passos 2 e 3;
    5 - caso sobre saldo de cotas, a ordem será alterada em seu preço novamente, para o valor anterior
    e a função é finalizada.
*/
void CTradeFIIDialog::BaterBID_ComTodasAsOrdensPendentesDeVenda(){
      
   // coletar o preço BID atual para uma variável local;
   double BID_atual = SymbolInfoDouble(Symbol(),SYMBOL_BID); 
   
   double current_order_price = 0.0;
   bool end_of_processing = false;
   double maior = 0.0;
   ulong ticket = 0;
   
   MqlTradeRequest request = {0};
   MqlTradeResult result = {0};
   int orders_total = 0;
   
   do{
      
      current_order_price = 0.0;
      orders_total = 0;
      ticket = 0.0;
      //--- zerar os valores de pedido e o seu resultado
      ZeroMemory(request);
      ZeroMemory(result); 
   
      orders_total = OrdersTotal();
      if(orders_total <= 0){
         Print("BaterBID_ComTodasAsOrdensPendentesDeVenda - Não há ordens pendentes na pedra.");
         end_of_processing = true; // to exit do-while
         continue; 
      }
      
      for(int i = 0; i < orders_total; i++){
         if(OrderGetTicket(i) > 0) {
            if((OrderGetString(ORDER_SYMBOL) == Symbol())
               && (OrderGetInteger(ORDER_MAGIC) == MAGIC_NUMBER)
               && (OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_LIMIT)) {
             
               if(OrderGetDouble(ORDER_PRICE_OPEN) >  maior){
                  maior  = OrderGetDouble(ORDER_PRICE_OPEN);
                  ticket = OrderGetInteger(ORDER_TICKET); 
               }
            }          
         }
      }
      
      if(maior <= 0.0){
         Print("BaterBID_ComTodasAsOrdensPendentesDeVenda - Não há ordens de venda na pedra.");
         end_of_processing = true; // to exit do-while
         continue;
      }
      
      current_order_price = maior; // apenas uma atribuição para melhor entendimento da função
      maior = 0.0;
      
      // modifica a ordem para agredir o preço BID.
      request.action = TRADE_ACTION_MODIFY;
      request.order = ticket;
      request.price = BID_atual;
      request.symbol =Symbol(); // símbolo
      
      if(!OrderSend(request, result)) {
        PrintFormat("BaterBID_ComTodasAsOrdensPendentesDeVenda - modify order buy limit - OrderSend error %d", GetLastError());
        ResetLastError();
        end_of_processing = true; // to exit do-while
        continue; // pula para a próxima iteração            
      }else{
            
         PrintFormat("Ordem Modificada! retcode=%u  deal=%I64u  order=%I64u  price=%.4f",result.retcode,result.deal,result.order,result.price); 
         
         // trecho de código para alterar a ordem se houver cotas não executadas.
         ticket = result.order;          
         if(!OrderSelect(ticket)){ // <= isso está estranho
         
            PrintFormat("OrderSelect error %d",GetLastError());     // if unable to send the request, output the error code
            ResetLastError();
            //end_of_processing = true; // to exit do-while
            continue; // pula para a próxima iteração     
         } 
             
         double vol = OrderGetDouble(ORDER_VOLUME_CURRENT);         
         if(vol > 0){
         
            //--- zerar os valores de pedido e o seu resultado
            ZeroMemory(request);
            ZeroMemory(result);  
            
            // modifica novamente a ordem de venda para o seu valor original.
            request.action = TRADE_ACTION_MODIFY;
            request.order = ticket;
            request.price = current_order_price;
            request.symbol =Symbol(); // símbolo
            if(!OrderSend(request, result)) {
               PrintFormat("BaterBID_ComTodasAsOrdensPendentesDeVenda - REMODIFY order buy limit - OrderSend error %d", GetLastError());
               ResetLastError();
               end_of_processing = true; // to exit do-while
               continue; // pula para a próxima iteração            
            }else{
               PrintFormat("BaterBID_ComTodasAsOrdensPendentesDeVenda - REMODIFY order buy limit - order=%I64u  price=%.4f", ticket, current_order_price);
               end_of_processing = true; // to exit do-while
            }
         }       
      }       
   }while(!end_of_processing);
   
   
   // coletar a ordem de venda mais distante de ASK, ou seja, com maior preço;
   // coletar o preço atual da ordem de venda para uma variável local;
   // modificar o preço desta ordem de venda para o preço BID;
   // verificar se sobrou saldo de cotas;
   // caso tenha sobrado saldo, alterar novamente o valor da ordem de venda para o valor anterior;
   // caso a ordem foi executada integralmente, coletar a ordem mais distante de ASK da lista que sobrou.
}


Abraço a todos.

Obter o ticket utilizado no último pedido. - trade.RequestOrder()
Obter o ticket utilizado no último pedido. - trade.RequestOrder()
  • 2016.06.03
  • www.mql5.com
Pessoal, Estou tentando obter o nº do ticket de uma ordem logo após o seu envio através da função RequestOrder() da biblioteca padrão CTrade...
Razão: