função de filtro que evite repetição de ordens, quando a corretora demora para aceitar ou rejeita

 

Não sei se estou viajando na maionese, mais será que tem alguma função que evite algum bug vindo da corretora que possa fazer o robô entrar em um loop de envios de ordens?

Eu me deparei com esses daqui:

ORDER_STATE_STARTED

Ordem verificada, mas ainda não aceita pela corretora (broker)

ORDER_STATE_REJECTED

Ordem rejeitada


eu consigo fazer isso com eles?

da pra testar em uma conta demo ?

fiz uma função aqui, mais não sei se esta certo.

espero que possam me orientar.

//+------------------------------------------------------------------+
//|                                                       teste1.mq5 |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

 //+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit() {
//---
//---
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
//---
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick() {
                  if(!VerificarOrdensRejeitadas(ORDER_TYPE_BUY, false)) {
                  }
                  else if(!VerificarOrdensRejeitadas(ORDER_TYPE_BUY, false)) {
 
 
 }
 }
 
 //+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
// Parâmetro gravar é automático pelo ontradetrasaction
bool VerificarOrdensRejeitadas( 
ENUM_ORDER_TYPE tipo, bool gravar = false)
// Colocar filtro antes do envio da ordem, deixar como "false" a opção "gravar" durante o envio, ou vazia
{// LIMITE DE TENTATIVAS REJEITADAS DE ENVIO DA ORDEM
int limit = 3;
int tempoordensRep = 15000; //[■tempo de travamento ordens repetidas pela corretora ■]

   datetime hora = TimeCurrent();
   if(tipo == ORDER_TYPE_BUY || tipo == ORDER_TYPE_BUY_LIMIT || tipo == ORDER_TYPE_BUY_STOP) {
      static datetime compras_rejeitadas = hora;
      static int      cnt_c = 0;
      if(gravar) {
         cnt_c++;
         if(cnt_c >= limit
         &&ENUM_ORDER_STATE(ORDER_STATE_STARTED)==true
         &&ENUM_ORDER_STATE(ORDER_STATE_REJECTED)==true 
         &&ENUM_ORDER_STATE(ORDER_STATE_FILLED)==false) {
            printf("Ordens de COMPRAS BLOQUEDAS por %d segundos por excesso de rejeições em %s", tempoordensRep, _Symbol);
            compras_rejeitadas = hora + tempoordensRep;
            cnt_c = 0;
         }
      } else if(compras_rejeitadas > hora)
         return true;
   } else if(tipo == ORDER_TYPE_SELL || tipo == ORDER_TYPE_SELL_LIMIT || tipo == ORDER_TYPE_SELL_STOP) {
      static datetime vendas_rejeitadas = hora;
      static int      cnt_v = 0;
      if(gravar) {
         cnt_v++;
         if(cnt_v >= limit
         &&ENUM_ORDER_STATE(ORDER_STATE_STARTED)==true
         &&ENUM_ORDER_STATE(ORDER_STATE_REJECTED)==true 
         &&ENUM_ORDER_STATE(ORDER_STATE_FILLED)==false) {
            printf("Ordens de VENDAS BLOQUEDAS por %d segundos por excesso de rejeições em %s", tempoordensRep, _Symbol);
            vendas_rejeitadas = hora + tempoordensRep;
            cnt_v = 0;
         }
      } else if(vendas_rejeitadas > hora)
         return true;
   }
   return false;
}
 
Não é mais fácil vc criar uma flag de quando envia a ordem ele e não entra novamente.
E depois reseta quando aparece um candle Novo ou alguma outra configuração?
 

Então @feliperamos,

Fez a função e não testou? Porque não sabe se esta certa homem!? 

Fato é que você enviou false

if(!VerificarOrdensRejeitadas(ORDER_TYPE_BUY, false)

e verifica dentro da função se é true.

if(gravar)

Observe também que determinou como valor padrão para este parâmetro false

bool VerificarOrdensRejeitadas( 
ENUM_ORDER_TYPE tipo, bool gravar = false)

Não vai entrar...


Sugiro inicialmente coletar dados para entender porque suas ordens foram rejeitadas.

Foi o stop com valor errado ou profit?

stop/profit = 0 |

"fora do tick"...tick para win é 5 mandou o valor de 106212

Foi negado/rejeitado devido ao volume?

não tinha contrato disponível para minha ordem BuyStop/SellStop

Assim, para um novo reenvio dessa ordem você teria como tratar o problema e reenviar a ordem com a atualização necessária. 

Mas, se desejar prossegui evitando essa parte, a sugestão do @Eduardo Oliveira resolve

if(!PositionSelect() && reenviar_ordem)
{
        //Reenvie sua ordem novamente
	//Se o seu contador chegar ao limite que você determinou	
	//Ative a flag para reenviar_ordem como o eduardo sugeriu
};
//Implemente uma função que, após um dado período ou candle reset o valor para o reenviar_ordem

Agora, se deseja ter alguns dados sobre as operações que tem ou não sido realizado enquanto sua EA esta rodando, trabalha com uma struct coletando estes dados, vai facilitar em tudo sua vida, apesar de algum trabalho que terá para implementar.

Sucesso por aí

 

O MQL5 é uma m* para tratamento de eventos. Não tem Hooks suficientes para tratar as inúmeras falhas que podem ocorrer durante um trade.

No seu caso eu sugir aguardar o retorno no OnTradeTransaction().

Não adianta aguardar X segundos.

Os eventos de retorno e ocorrências de uma conta DEMO são diferentes na conta REAL.

Uma coisa é tratar uma exceção, a outra é tentar conviver com corretora ruim. Mude de corretora também.

;)

 
Flavio Jarabeck #:

O MQL5 é uma m* para tratamento de eventos. Não tem Hooks suficientes para tratar as inúmeras falhas que podem ocorrer durante um trade.

No seu caso eu sugir aguardar o retorno no OnTradeTransaction().

Não adianta aguardar X segundos.

Os eventos de retorno e ocorrências de uma conta DEMO são diferentes na conta REAL.

Uma coisa é tratar uma exceção, a outra é tentar conviver com corretora ruim. Mude de corretora também.

;)

eu fiz dessa forma com essa função no  OnTradeTransaction(). Agradeço Flavio e sucesso pra ti.

//+------------------------------------------------------------------+
//| TradeTransaction function                                        |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction &trans,
                        const MqlTradeRequest &request,
                        const MqlTradeResult &result) {
   B.Encrypt();
//--- get transaction type as enumeration value
   ENUM_TRADE_TRANSACTION_TYPE type = trans.type;
   ENUM_ORDER_TYPE  lastOrderType  = trans.order_type;
   ENUM_ORDER_STATE lastOrderState = trans.order_state;
   string           trans_symbol   = trans.symbol;
//VARIAVEIS DO ONTRADETRANSACTION
   bool   m_need_delete_buy_stop    = false;
   bool   m_need_delete_sell_stop   = false;
   bool   m_need_place_buy_stop     = false;
   bool   m_need_place_sell_stop    = false;
   double ExtLot                    = 0.0;
   if(trans_symbol != _Symbol) {
      return;
   }
   if(lastOrderState == ORDER_STATE_REJECTED) {//==========================================================
      VerificarOrdensRejeitadas(lastOrderType, true);//==========================================================
   }
//--- if transaction is result of addition of the transaction in history
   if(type == TRADE_TRANSACTION_DEAL_ADD) {
      long     deal_ticket       = 0;
      long     deal_order        = 0;
      long     deal_time         = 0;
      long     deal_time_msc     = 0;
      long     deal_type         = -1;
      long     deal_entry        = -1;
      long     deal_magic        = 0;
      long     deal_reason       = -1;
      long     deal_position_id  = 0;
      double   deal_volume       = 0.0;
      double   deal_price        = 0.0;
      double   deal_commission   = 0.0;
      double   deal_swap         = 0.0;
      double   deal_profit       = 0.0;
      string   deal_symbol       = "";
      string   deal_comment      = "";
      string   deal_external_id  = "";
      if(HistoryDealSelect(trans.deal)) {
         deal_ticket       = HistoryDealGetInteger(trans.deal, DEAL_TICKET);
         deal_order        = HistoryDealGetInteger(trans.deal, DEAL_ORDER);
         deal_time         = HistoryDealGetInteger(trans.deal, DEAL_TIME);
         deal_time_msc     = HistoryDealGetInteger(trans.deal, DEAL_TIME_MSC);
         deal_type         = HistoryDealGetInteger(trans.deal, DEAL_TYPE);
         deal_entry        = HistoryDealGetInteger(trans.deal, DEAL_ENTRY);
         deal_magic        = HistoryDealGetInteger(trans.deal, DEAL_MAGIC);
         deal_reason       = HistoryDealGetInteger(trans.deal, DEAL_REASON);
         deal_position_id  = HistoryDealGetInteger(trans.deal, DEAL_POSITION_ID);
         deal_volume       = HistoryDealGetDouble(trans.deal, DEAL_VOLUME);
         deal_price        = HistoryDealGetDouble(trans.deal, DEAL_PRICE);
         deal_commission   = HistoryDealGetDouble(trans.deal, DEAL_COMMISSION);
         deal_swap         = HistoryDealGetDouble(trans.deal, DEAL_SWAP);
         deal_profit       = HistoryDealGetDouble(trans.deal, DEAL_PROFIT);
         deal_symbol       = HistoryDealGetString(trans.deal, DEAL_SYMBOL);
         deal_comment      = HistoryDealGetString(trans.deal, DEAL_COMMENT);
         deal_external_id  = HistoryDealGetString(trans.deal, DEAL_EXTERNAL_ID);
      } else
         return;
      if(deal_symbol == simbolo.Name() && deal_magic == in_magic) {
         if(deal_entry == DEAL_ENTRY_IN) {
            if(deal_type == DEAL_TYPE_BUY || deal_volume == DEAL_TYPE_SELL) {
               m_need_delete_buy_stop  = true;
               m_need_delete_sell_stop = true;
               ExtLot                  = in_volume * 2.0;
               m_need_place_buy_stop   = true;
               m_need_place_sell_stop  = true;
            }
         }
      }
   }
}
 
Adailton Silva #:

Então @feliperamos,

Fez a função e não testou? Porque não sabe se esta certa homem!? 

Fato é que você enviou false

e verifica dentro da função se é true.

Observe também que determinou como valor padrão para este parâmetro false

Não vai entrar...


Sugiro inicialmente coletar dados para entender porque suas ordens foram rejeitadas.

Foi o stop com valor errado ou profit?

stop/profit = 0 |

"fora do tick"...tick para win é 5 mandou o valor de 106212

Foi negado/rejeitado devido ao volume?

não tinha contrato disponível para minha ordem BuyStop/SellStop

Assim, para um novo reenvio dessa ordem você teria como tratar o problema e reenviar a ordem com a atualização necessária. 

Mas, se desejar prossegui evitando essa parte, a sugestão do @Eduardo Oliveira resolve

Agora, se deseja ter alguns dados sobre as operações que tem ou não sido realizado enquanto sua EA esta rodando, trabalha com uma struct coletando estes dados, vai facilitar em tudo sua vida, apesar de algum trabalho que terá para implementar.

Sucesso por aí

Ok guerreiro, agradeço por ajudar irei testar essas opções. Grato sucesso

 
Eduardo Oliveira #:
Não é mais fácil vc criar uma flag de quando envia a ordem ele e não entra novamente.
E depois reseta quando aparece um candle Novo ou alguma outra configuração?

vou testa sua sugestão Guerreiro. Agradeço por ajudar qualquer coisa estamos aqui. Grato.

 
felipe ramos:

Não sei se estou viajando na maionese, mais será que tem alguma função que evite algum bug vindo da corretora que possa fazer o robô entrar em um loop de envios de ordens?

Olá Felipe,

o MT5 é um bicho de sete cabeças no tocante a travamentos.  Depois de sofrer alguns prejuízos e brigar com as corretoras, escrevi a função que estou compartilhando. O objetivo da  função  é abortar o EA em caso de travamento de uma ordem por mais de 60 segundos.

Ela é chamada imediatamente após ao OrderSend().

Também é chamada no OnTimer(), porque também ocorre travamento nas ordens emitidas pelos gatilhos de SL/TP da posição. 

 

void ToDoTravamentoOrdem()
  {
   int contOrderState = 0;
   bool flagOrdemTravada = false;
   do
     {
      for(int i = OrdersTotal() - 1; i >= 0; i--)
        {
         if(OrderSelect(OrderGetTicket(i)))
           {
            if(OrderGetString(ORDER_SYMBOL) == ativoOper
               && OrderGetInteger(ORDER_MAGIC) == inpMagicNumber
               && (OrderGetInteger(ORDER_STATE) == ORDER_STATE_STARTED
                || OrderGetInteger(ORDER_STATE) == ORDER_STATE_REQUEST_ADD))
              {
               Sleep(100);
               flagOrdemTravada = true;
               contOrderState++;
               break;
              }
           }
        }
     }
   while(contOrderState < 600 && flagOrdemTravada == true);
   if(contOrderState >= 600)
     {
      string txt = strNomeEA + " Requer sua atenção, ordem travada: " + (string) OrderGetInteger(ORDER_TICKET) + " " + EnumToString((ENUM_ORDER_STATE) OrderGetInteger(ORDER_STATE)) ;
      Alert(txt);
      SendNotification(txt);
      ExpertRemove();
     }
  }
 
Rogerio Giannetti Torres #:

Olá Felipe,

o MT5 é um bicho de sete cabeças no tocante a travamentos.  Depois de sofrer alguns prejuízos e brigar com as corretoras, escrevi a função que estou compartilhando. O objetivo da  função  é abortar o EA em caso de travamento de uma ordem por mais de 60 segundos.

Ela é chamada imediatamente após ao OrderSend().

Também é chamada no OnTimer(), porque também ocorre travamento nas ordens emitidas pelos gatilhos de SL/TP da posição. 

 

Obrigado Rogerio por  compartilhar sua ideia , irei utilizar em meu projeto . Todas as ideias de sistemas de segurança e bem vinda. Agradeço! 

 
Rogerio Giannetti Torres #:

Olá Felipe,

o MT5 é um bicho de sete cabeças no tocante a travamentos.  Depois de sofrer alguns prejuízos e brigar com as corretoras, escrevi a função que estou compartilhando. O objetivo da  função  é abortar o EA em caso de travamento de uma ordem por mais de 60 segundos.

Ela é chamada imediatamente após ao OrderSend().

Também é chamada no OnTimer(), porque também ocorre travamento nas ordens emitidas pelos gatilhos de SL/TP da posição. 

 

Eu fiz assim.

// Se bem sucessedida a verificação a ordem é enviada
   if(!OrderSend(request, result)) {
      // Mensagem exibida em caso de falha no envio da ordem
      printf(__FUNCTION__, "[%s] Erro %d no envio da ordem. Código %d (%s)",
             in_nome, GetLastError(), result.retcode, result.comment);
      PrintResultTrade(trade, simbolo);
     ToDoTravamentoOrdem();
      return(false);
   } else
      printf(__FUNCTION__, "[%s] Sucesso no negócio [%d]. Código %d (%s)",
             in_nome, result.order, result.retcode, result.comment);
   PrintResultTrade(trade, simbolo);
   return(true);
}
 

Na questão de atraso de ordem e entre outros similares, eu fiz isso para "simular" esse B.O, mais não sei se e útil.  

//+------------------------------------------------------------------+
//|                                                      ProjectName |
//|                                      Copyright 2020, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+

#include <Trade/Trade.mqh>
#include <Trade/Trade.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\AccountInfo.mqh>

//--- Load the class
CTrade trade;
CPositionInfo m_Position;

 
struct s_posicoes {
   double            volume; // Lot
   double            lucro; // Lucro real da posição aberta, referente ao verdadeiro preço de saída
   datetime          abertura; // Horário que se inicio a posição
   ulong             ticket_compra; // Bilhete da posição se for de compra
   ulong             ticket_venda; // Bilhete da posição de venda se existir ambas simultanemanetes, são fechadas entre si
};
enum e_sn {
   nao = 0, // Não
   sim = 1 // Sim
};
 
input double LotSize = 1.0;
input int    MagicNumber = 65262;
input int    Slippage = 10;

input double ValorStop = 100.00;
input double RelacaoGainStop = 3;

input int    HoraInicioOper = 09;
input int    MinInicioOper  = 10;
input int    HoraFimOper = 17;
input int    MinFimOper  = 30;
input int    HoraFechOper = 17;
input int    MinFechOper  = 30;

input bool   DebugAtivo = true;
input group              "[■  slippeges BACKTEST ■]"
input int                 slippeges = 100;//[■ slippeges BACKTEST/500=5MS ■]
sinput e_sn               in_hab_slippeges = true; //[■Habilitar slippeges  BACKTEST ■]

double Gain = 0;
double Stop = 0;
double TamanhoLote = 1;
int    Horario_Proxima_Verificacao = 0;

ulong  ticketCorrente = 0;

MqlDateTime DataHoraAtu;

double bid, ask, High[], Low[], Close[], Open[];
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnInit() {
// parte efetivamente escrita para o trading:
   trade.SetExpertMagicNumber(MagicNumber);
   trade.SetDeviationInPoints(Slippage);
   trade.SetAsyncMode(false);
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTick() {
   s_posicoes posicao = posicionamento(); // Contabilizando posições abertas
// obtem data e hora corrente
   TimeToStruct(TimeCurrent(), DataHoraAtu);
 // Verifica se está fora do horário de negociação definido em parâmetro
   if(RestringeHoraNegociacao())
      return;
   ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
   bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
   if(TimeCurrent() > Horario_Proxima_Verificacao ) {
      if(!TemTradeAberto()) {
         VerificarEntradas();
      } else {
         VerificarSaidas();
      }}}
 

 
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool TemTradeAberto() {
   if(m_Position.Select(Symbol()))
      return true;
   else
      return false;
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void VerificarEntradas() {
   int Numero = rand();
   if(MathMod(Numero, 2) == 0.00) {
      Gain = ask + (ValorStop * RelacaoGainStop);
      Stop = ask - ValorStop;
      iniciar_SLIP();//========================================================================/////aqui
      if(!trade.Buy(TamanhoLote, Symbol())) {
         Print("Buy falhou: Cod. retorno= ", trade.ResultRetcode(), " Tamanho lote: ", TamanhoLote, "descricao: ", trade.ResultRetcodeDescription());
      }
      Horario_Proxima_Verificacao = int(TimeLocal()) + 2;
   } else {
      Gain = bid - (ValorStop * RelacaoGainStop);
      Stop = bid + ValorStop;
     iniciar_SLIP();//========================================================================/////aqui
      if(!trade.Sell(TamanhoLote, Symbol())) {
         Print("Sell falhou: Cod. retorno= ", trade.ResultRetcode(), " Tamanho lote: ", TamanhoLote, "descricao: ", trade.ResultRetcodeDescription());
      }
      Horario_Proxima_Verificacao = int(TimeLocal()) + 2;
   }
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void VerificarSaidas() {
   int pt = PositionsTotal();
   for(int i = 0; i < pt; i++) {
      //Print("verificar saidas: ", PositionGetInteger(POSITION_MAGIC), " ", PositionGetInteger(POSITION_TYPE) );
      if(PositionGetInteger(POSITION_MAGIC) == MagicNumber && PositionGetSymbol(i) == _Symbol) {
         if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
            if(bid >= Gain || bid <= Stop) {
               ulong esteticket = trade.PositionClose(Symbol());
               Horario_Proxima_Verificacao = int(TimeLocal()) + 2;
            }
         } else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) {
            if(ask <= Gain || ask >= Stop) {
               ulong esteticket = trade.PositionClose(Symbol());
               Horario_Proxima_Verificacao = int(TimeLocal()) + 2   ;
            }
         }
      }
   }
}



//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool RestringeHoraNegociacao() {
   int DtHrAtu = (DataHoraAtu.hour * 100) + DataHoraAtu.min;
   int DtHrIni = (HoraInicioOper * 100) + MinInicioOper;
   int DtHrFim = (HoraFimOper * 100) + MinFimOper;
// se horário está entre hora ini e fim definidos, seguir com o EA
// senão, verificar se tem posição aberta e encerrar o trade
   if(DtHrAtu >= DtHrIni && DtHrAtu <= DtHrFim)
      return false;
   else {
      if(TemTradeAberto()) {
         trade.PositionClose(Symbol());
         if(DebugAtivo)
            Print("Fechou o trade por horário limite. Retcode ", trade.ResultRetcode());
      }
      return true;
   }
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool DisplayInfoConta() {
//--- objeto criado para carregar informacoes de conta
   CAccountInfo account;
//--- variavel que recebe o numero da conta de trading
   long login = account.Login();
   Print("Login=", login);
//--- verifica tipo de conta
   ENUM_ACCOUNT_TRADE_MODE account_type = account.TradeMode();
//--- if the account is real, the Expert Advisor is stopped immediately!
   /*   if(account_type==ACCOUNT_TRADE_MODE_REAL)
        {
         MessageBox("Trading on a real account is forbidden, disabling","The Expert Advisor has been launched on a real account!");
         return(false);
         } */
//--- mostra o tipo de conta
   Print("Account type: ", EnumToString(account_type));
//--- emite aviso se o tipo de conta permite o trade:
   if(account.TradeAllowed())
      Print("Trading on this account is allowed");
   else
      Print("Trading on this account is forbidden: you may have entered using the Investor password");
//--- verifica se a conta permite expert advisors (robo trader)
   if(account.TradeExpert())
      Print("Automated trading on this account is allowed");
   else
      Print("Automated trading using Expert Advisors and scripts on this account is forbidden");
//--- verifica numero máximo de ordens pendentes
   int orders_limit = account.LimitOrders();
   if(orders_limit != 0)
      Print("Maximum permissible amount of active pending orders: ", orders_limit);
//--- mostra a corretora e o servidor
   Print(account.Company(), ": server ", account.Server());
//--- Mostra o saldo e o lucro no final
   Print("Balance=", account.Balance(), "  Profit=", account.Profit(), "   Equity=", account.Equity());
   Print(__FUNCTION__, "  completed"); //---
   return true;
}
//+------------------------------------------------------------------+



//+------------------------------------------------------------------+
//========================================================================
//========================================================================
//==FUNÇAO Posicionamento |
//========================================================================
//========================================================================
s_posicoes posicionamento(void) {
// Estrutura para armazenar os dados de ordens executadas
   s_posicoes posicao;
   ZeroMemory(posicao);
   string err_text = "";
   for(int i = PositionsTotal() - 1; i >= 0; i--) {
      ulong ticket = PositionGetTicket(i);
      if(!PositionSelectByTicket(ticket))
         continue;
      if(PositionGetInteger(POSITION_MAGIC) != 1344)
         continue;
      if(PositionGetString(POSITION_SYMBOL) != _Symbol)
         continue;
      ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
      double vol = PositionGetDouble(POSITION_VOLUME);
      double price = PositionGetDouble(POSITION_PRICE_OPEN);
      if(posicao.abertura == 0)
         posicao.abertura = (datetime)PositionGetInteger(POSITION_TIME);
      if(tipo == POSITION_TYPE_BUY) {
         posicao.volume += vol; // Verifica o volume aberto, positivo para compras
         posicao.ticket_compra = ticket;
         // Verifica o lucro real da posição com base no preço verdadeiro de saída e não pelo último negócio
         if(!OrderCalcProfit(ORDER_TYPE_BUY, _Symbol, vol, price,
                             SymbolInfoDouble(_Symbol, SYMBOL_BID), posicao.lucro))
            printf(__FUNCTION__, "[%s] Falha no cálculo de lucro da posição comprada %d"
                   , "", (string)ticket, err_text);
      } else {
         posicao.volume -= vol; // Verifica o volume aberto, negativo para vendas
         posicao.ticket_venda = ticket;
         if(!OrderCalcProfit(ORDER_TYPE_SELL, _Symbol, vol, price,
                             SymbolInfoDouble(_Symbol, SYMBOL_ASK), posicao.lucro))
            printf(__FUNCTION__, "[%s] Falha no cálculo de lucro da posição vendida %d",
                   "", (string)ticket, err_text);
      }
   }
   return posicao;
}


//+------------------------------------------------------------------+
//____________________________________________________________________________
//____________________________________________________________________________
//
//slippaggen SIMULADOR
//____________________________________________________________________________
bool iniciar_SLIP(void) {//=======================================aqui funcao
   if(!in_hab_slippeges) {
      return false ;
   }
   Sleep(slippeges);
   return true;
}
Razão: