Há algum parâmetro que indica como a operação foi finalizada: por SL ou TP durante simulação?

 

Entendo que a princípio isso possa ser feito por variáveis globais static , mas não consegui entender como detectar que a operação finalizou por SL ou por TP para aí colocar o valor nesta variável estática.

static int slCount = 0;
static int tpCount = 0;


Onde ou a partir de qual parâmetro posso incrementar (++) estas variáveis? Alguém sabe me dizer?

(Imagino que talvez possa ser feito através do histórico, mas há algum meio de saber como finalizou a última operação imediata, para apenas incrementar as variáveis citadas?

 
Henrique Vilela:

Entendo que a princípio isso possa ser feito por variáveis globais static , mas não consegui entender como detectar que a operação finalizou por SL ou por TP para aí colocar o valor nesta variável estática.

static int slCount = 0;
static int tpCount = 0;


Onde ou a partir de qual parâmetro posso incrementar (++) estas variáveis? Alguém sabe me dizer?

(Imagino que talvez possa ser feito através do histórico, mas há algum meio de saber como finalizou a última operação imediata, para apenas incrementar as variáveis citada

Não ha necessidade de se utilizar variável do tipo "static".

Para capturar as informações que precisa, utilize a função de manipulação de eventos OnTradeTransaction.

 
Joscelino Celso de Oliveira:

Não ha necessidade de se utilizar variável do tipo "static".

Para capturar as informações que precisa, utilize a função de manipulação de eventos OnTradeTransaction.

Ta aí um evento que nunca usei... vou pesquisar na documentação. Obrigado!

 
Joscelino:

Não ha necessidade de se utilizar variável do tipo "static".

Para capturar as informações que precisa, utilize a função de manipulação de eventos OnTradeTransaction.

Estou quebrando a cabeça com este evento. O problema é que não estou sabendo como lidar com a "temporização do evento", num teste simples (com um simples print) dá pra perceber que o evento é chamado mais de uma vez  quando ocorre uma "deal" (negociação), lendo a documentação vi que talvez eu deva passar para o tratamento das variáveis request ou result , mas não consegui compreender como relacioná-las a um tipo de saída por SL ou TP.

Consegui através de um vídeo no youtube a solução de verificar o tipo de saída pelo Profit (resultado da operação), sendo positivo presumo TP e negativo SL. Porém para o meu caso já não funcionaria pois meu robô move o SL  (inclusive para valores positivos dependendo da situação) quando alcança um Break Even.

Abaixo o código que peguei em um canal do youtube com modificações que fiz para funcionar para a o que eu precisava:


//+------------------------------------------------------------------+
//|                                     SimpleOrderHistoryProfit.mq5 |
//|                             Copyright 2020, Henrique      Vilela |
//|                          http://                               / |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, Henrique Leal Vilela"
#property link      "https:///"
#property version   "0.01"
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>

CTrade negocio; // Cria instancia da classe CTrade
    
//variavel para abrir compra ou venda após fechamento da posição atual
int pos = 0;   

//fará contagem global de acionamentos de TP e SL
static int sl_count = 0, tp_count = 0, be_count = 0;
//salvara o ultimo ticket analizado

void OnTick() // apenas simula operações
  {

    //calculo do preço ASK
    double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits);
    
    //calculo do preço BID
    double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits);

    if(PositionsTotal() < 1){
    
        //realiza operação de simulação
        
        if(pos) {// pos == 1
            negocio.Buy(1,NULL,Ask,(Ask - 4), (Ask + 4), NULL);
            pos = 0;
        }
        else {
            negocio.Sell(1,NULL,Bid,(Bid + 4),(Bid - 4), NULL);
            pos = 1;
        }
    }
   
 }
  

void OnTradeTransaction(const MqlTradeTransaction &trans,const MqlTradeRequest &request, const MqlTradeResult &result)
  {
    
    //conta SL e TP acada nova negociação finalizada (???) baseado no resultado da ultima negociação
    
    if(trans.type == TRADE_TRANSACTION_REQUEST ){
    

        // calcula o ultimo Lucro/Prejuizo (Profit)
        double lastProfit = 0;
        string MyLastProfit = GetLastProfit(lastProfit);
    
        if(lastProfit < 0 )
            sl_count++;
        else if(lastProfit > 0)
            tp_count++;
        else if (lastProfit == 0)
            be_count++;
       
       string ResultCounter = "\nResultados das saídas:  " +
                              "\nStop Loss: "     + (string)sl_count +
                              "\nTake Profit: "   + (string)tp_count +
                              "\nBreak Even: "    + (string)be_count;
       
     
        // para escrever no gráfico:
        Comment("\nMeu último resultado foi de: ", "\n", MyLastProfit, "\n", ResultCounter);
    
    }
  
  }
 //-----------------------------------------------------------------
  
  
void OnDeinit(const int reason)
  {
    printf("Stop Loss acionado: %d vezes", sl_count);
    printf("TakeProfit acionado: %d vezes", tp_count);
    
    
    printf("Deinit reason: %d", reason);
  }
  
//--------------------------------------------------------------------  
  
  
  
  
//+------------------------------------------------------------------+

string GetLastProfit(double &lastProfit) {

    uint    TotalNumberOfDeals = HistoryDealsTotal();
    ulong   TicketNumber = 0;
    long    OrderType, DealEntry;
    double  OrderProfit = 0;
    string  MySymbol = "";
    string  PositionDirection = "";
    string  LastOut = "";
    
    string  MyResult = "";

    //Ordem > Negócio (Deal) > Posição
    
    //pega o histórico de negociações
    HistorySelect(0,TimeCurrent());
    
    //verifica todas as negociações
    for(uint i=0; i < TotalNumberOfDeals; i++){
    
        //procuramos o ticket da operação
        if((TicketNumber = HistoryDealGetTicket(i)) > 0){
        
            //pega o profit
            OrderProfit = HistoryDealGetDouble(TicketNumber, DEAL_PROFIT);      // recebe um parametro do DEAL do Ticket selecionado, esse parametro é o profit(DEAL_PROFIT)
            
            //pega o tipo
            OrderType = HistoryDealGetInteger(TicketNumber, DEAL_TYPE);
            
            //recebe o papel operado
            MySymbol = HistoryDealGetString(TicketNumber, DEAL_SYMBOL);
            
            //recebe o Deal Entry type para verificar os tipos de fechamento  ----- VER O QUE ESSA VARIAVEL REALMENTE RETORNA: DEAL_ENTRY
            DealEntry = HistoryDealGetInteger(TicketNumber, DEAL_ENTRY);
        
            //ver se o papel no gráfico "bate com o do histórico"
            if(MySymbol == _Symbol){
            
                //se é uma compra ou venda E esta ordem está fechada (DealEntry)
                if(OrderType == ORDER_TYPE_BUY || OrderType == ORDER_TYPE_SELL)
                    
                    if(DealEntry == 1) {
                    
                        //Informa se o fechamento foi comprado ou vendido (se fechou comprado, então veio de uma venda e vice-versa)
                        if(OrderType == ORDER_TYPE_BUY)
                            PositionDirection = "Operado Vendido";
                            
                        if(OrderType == ORDER_TYPE_SELL)
                            PositionDirection = "Operado Comprado";

                        lastProfit = OrderProfit;
                        
                        if(lastProfit < 0 )
                            LastOut = "Stop Loss";
                        else if(lastProfit > 0)
                            LastOut = "Take Profit";
                        else
                            LastOut = "0x0 (Break Even)";
                        
                        
                        // Monta a String de saída
                        MyResult = "Resultado:"                 + (string)  OrderProfit +
                                   "\nTicket: "                 + (string)  TicketNumber +
                                   "\nDireção da Posição: "     +           PositionDirection + 
                                   "\nSaída por: "              +           LastOut;
                                   
                    }
            }
        }
    
    }

    return MyResult;

}

Também no meu robô(não neste exemplo acima) tem acontecido de reconhecer BreakEven (profit = 0) aparentemente toda vez que ocorre uma ordem nova, modificada ou encerrada

Outro fato é que não entendi como eu poderia contar os SL e TP sem usar uma static. o mql já tem algum tipo de variável que já guarda esse número automaticamente?

Uma outra alternativa talvez poderia ser eu fazer (o que acho bem pior e não recomendável - como já acredito que seja apenas o fato de ficar usando statics) usar statics para ir verificando os pontos onde houveram entradas e saídas de operações no código e seus valores e aí, através disso calcular se foi TP, SL ou BE. 

 
Henrique Vilela:

Estou quebrando a cabeça com este evento. O problema é que não estou sabendo como lidar com a "temporização do evento", num teste simples (com um simples print) dá pra perceber que o evento é chamado mais de uma vez  quando ocorre uma "deal" (negociação), lendo a documentação vi que talvez eu deva passar para o tratamento das variáveis request ou result , mas não consegui compreender como relacioná-las a um tipo de saída por SL ou TP.

Consegui através de um vídeo no youtube a solução de verificar o tipo de saída pelo Profit (resultado da operação), sendo positivo presumo TP e negativo SL. Porém para o meu caso já não funcionaria pois meu robô move o SL  (inclusive para valores positivos dependendo da situação) quando alcança um Break Even.

Abaixo o código que peguei em um canal do youtube com modificações que fiz para funcionar para a o que eu precisava:


Também no meu robô(não neste exemplo acima) tem acontecido de reconhecer BreakEven (profit = 0) aparentemente toda vez que ocorre uma ordem nova, modificada ou encerrada

Outro fato é que não entendi como eu poderia contar os SL e TP sem usar uma static. o mql já tem algum tipo de variável que já guarda esse número automaticamente?

Uma outra alternativa talvez poderia ser eu fazer (o que acho bem pior e não recomendável - como já acredito que seja apenas o fato de ficar usando statics) usar statics para ir verificando os pontos onde houveram entradas e saídas de operações no código e seus valores e aí, através disso calcular se foi TP, SL ou BE. 

E aí que entra a inconsistência do MQL5. Tem OOP, mas tem raízes fortíssimas em linguagem estruturada, com algumas nuances de Programação Orientada a Eventos. Os pouquíssimos Hooks que a linguagem tem são totalmente deficitários. Um deles é o OnTradeTransaction(), que é uma confusão por si só...

Estude mais, exercite mais o código do OnTradeTransaction(), você não precisa usar FOR... para capturar o que acabou de acontecer... esse Hook é executado sempre que há um evento de operação no Symbol, seja entrada, saída, ou reposicionamento de stops...


Ponha este código dentro do OnTradeTransaction e você entenderá:

        Print("=====================================================");
        Print("TRANS - deal:",trans.deal," Order:",trans.order," TType:",EnumToString(trans.type)," OType:",EnumToString(trans.order_type)," OState:",EnumToString(trans.order_state)," DType:",EnumToString(trans.deal_type)," Price:",trans.price," Vol:",trans.volume," SL:",trans.price_sl," TP:",trans.price_tp);
        Print("-----------------------------------------------------");
        Print("REQUEST - Action:",EnumToString(req.action)," Order:",req.order," Price:",req.price," Vol:",req.volume," StopLimit:",req.stoplimit," deviation:",req.deviation," o.type:",EnumToString(req.type)," SL:",req.sl," TP:",req.tp);
        Print("-----------------------------------------------------");
        Print("RESULT - RetCode:",res.retcode," Deal:",res.deal," Order:",res.order," PriceConfirmed:",res.price," Vol:",res.volume," RetCodeExternal:",res.retcode_external," RequestID:",res.request_id);
        Print("=====================================================");


;)
 
Henrique Vilela:

Entendo que a princípio isso possa ser feito por variáveis globais static , mas não consegui entender como detectar que a operação finalizou por SL ou por TP para aí colocar o valor nesta variável estática.

static int slCount = 0;
static int tpCount = 0;


Onde ou a partir de qual parâmetro posso incrementar (++) estas variáveis? Alguém sabe me dizer?

(Imagino que talvez possa ser feito através do histórico, mas há algum meio de saber como finalizou a última operação imediata, para apenas incrementar as variáveis citadas?

Você pode pegar o lucro da última operação e concluir que: se positivo = atingiu TP, negativo atingiu SL.
Dá pra usar o código:

double ResultadoUltimoTrade()
  {
    HistorySelect(0,TimeCurrent());
    ulong _ticket = HistoryDealGetTicket(HistoryDealsTotal()-1);
    return(HistoryDealGetDouble(_ticket,DEAL_PROFIT));
  }
 
Thiago Duarte:

Você pode pegar o lucro da última operação e concluir que: se positivo = atingiu TP, negativo atingiu SL.
Dá pra usar o código:

Flavio Jarabeck:

E aí que entra a inconsistência do MQL5. Tem OOP, mas tem raízes fortíssimas em linguagem estruturada, com algumas nuances de Programação Orientada a Eventos. Os pouquíssimos Hooks que a linguagem tem são totalmente deficitários. Um deles é o OnTradeTransaction(), que é uma confusão por si só...

Estude mais, exercite mais o código do OnTradeTransaction(), você não precisa usar FOR... para capturar o que acabou de acontecer... esse Hook é executado sempre que há um evento de operação no Symbol, seja entrada, saída, ou reposicionamento de stops...


Ponha este código dentro do OnTradeTransaction e você entenderá:


;)

Muito Obrigado Thiago e Flavio, espero chegar ao nível de conhecimento de vocês para poder colaborar assim aqui no fórum. Assim que puder vou testar fazer os testes sugeridos!

Não vejo perguntas mais iniciantes mas talvez o máximo que eu poderia ajudar nos básicos da linguagem C/C++, a forma de estruturação do MQL ainda é meio confusa para mim (talvez por essa mistura toda de conceitos... quem sabe as coisas se organizem melhor num futuro MQL6...(?)... 

#OFF estou estudando a biblioteca Allegro5 também e tive no começo praticamente os mesmos problemas com essa mistura de Eventos + OOP e estou conseguindo desenvolver bem, tirando o fato de não ter entendido de fato o conceito de "orientação a eventos", mas me parece como se o sistema ficasse aguardando interrupções (estilo ASM/ baixo nível)  para executar um trecho de código...

 
Henrique Vilela:   ...o conceito de "orientação a eventos", mas me parece como se o sistema ficasse aguardando interrupções (estilo ASM/ baixo nível)  para executar um trecho de código...

Exato!  Você não chama as rotinas, elas são chamadas quando "algo" acontece.

O MQL5 é bem capenga nessa área...

;)

 
Flavio Jarabeck:

E aí que entra a inconsistência do MQL5. Tem OOP, mas tem raízes fortíssimas em linguagem estruturada, com algumas nuances de Programação Orientada a Eventos. Os pouquíssimos Hooks que a linguagem tem são totalmente deficitários. Um deles é o OnTradeTransaction(), que é uma confusão por si só...

Estude mais, exercite mais o código do OnTradeTransaction(), você não precisa usar FOR... para capturar o que acabou de acontecer... esse Hook é executado sempre que há um evento de operação no Symbol, seja entrada, saída, ou reposicionamento de stops...


Ponha este código dentro do OnTradeTransaction e você entenderá:


;)

Foi de ótimo auxílio esta lista de argumentos que me passou. Estudando elas consegui exatamente o que queria e sem artifícios muito complexos, bastou separar os parâmetros que ocorriam a cada tipo de operação que eu precisava verificar. E o melhor não precisei usar o Profit para a contagem, o que estava achando que ia tornar o código mais complexo já que dependendo das entradas eu precisaria realizar calculos individuais com os valores obtidos. Abaixo fica o trecho do código com a SOLUÇÃO parcial do problema caso alguém necessite:

    // verifica se uma negociação foi iniciada
    if(trans.type == TRADE_TRANSACTION_REQUEST)
        if(req.action == TRADE_ACTION_DEAL){
            
            ordemEmAberto = true; // setamos que há uma ordem em aberto - valido apenas para ordens de entrada única por enquanto
            prOP = req.price;   // price Open (preço de abertura)
            prTP = req.tp;      // preço para Take Profit
            prSL = req.sl;      // preço para Stop Loss
            
            trOrd = res.order;//pega o número da ordem para avaliar com "+1" na hora do fechamento, assim garantindo que foi a ordem subsequente (ou TALVEZ +2) em caso de Order Modify)
        }
        
    // Verifica se uma posição foi fechada
    if(trans.type == TRADE_TRANSACTION_HISTORY_ADD && trans.order == (trOrd+1))
        if(trans.price != 0.0){
            if(trans.price == prSL)
                slCount++;
            else if(trans.price == prTP)
                tpCount++;
            else
                beCount++;
       }
   
  }

Além de remover as "deselegantes" variáveis estáticas uma vez que posso apenas usar uma variável global comum para realizar a contagem, já que preciso do resultado só no DeInit().

O código acima é colocado todo dentro da OnTradeTransaction() e o abaixo são todas declarações globais.

o código acima é para teste como disse, mas já ajudará se alguém estiver procurando por esta solução. 

Esqueci das variáveis:

bool ordemEmAberto = false;      // analisará se há ordem aberta de acordo com dados da, e APENAS da, OnTradeTransaction()

// dados para serem analisados na contagem
double prOP =  0.0; // price Open (preço de abertura)- não utilizada neste exemplo
double prTP =  0.0; // preço para Take Profit
double prSL =  0.0; // preço para Stop Loss

ulong    trOrd = 0; // pega o número de ordem da transação em aberto


Novamente obrigado pelo apoio!

 
Henrique Vilela:

Foi de ótimo auxílio esta lista de argumentos que me passou. Estudando elas consegui exatamente o que queria e sem artifícios muito complexos, bastou separar os parâmetros que ocorriam a cada tipo de operação que eu precisava verificar. E o melhor não precisei usar o Profit para a contagem, o que estava achando que ia tornar o código mais complexo já que dependendo das entradas eu precisaria realizar calculos individuais com os valores obtidos....

Bela contribuição pra galera @Henrique Vilela!  Parabéns!

;)

 

Com esses dados percebi que meu robô estava sendo um "Grande Vencedor de Break Evens!!!" Já que o Backtest do Metatrader estava me dando 80% de Gains com meu robô. Agora, contabilizados separadamente vi que 70% era tudo "Break Even" (BE) e piorava a minha visão dos dados quando eu ainda colocava uma proteção (para pagar os custos), pois ganho é ganho e o backtest  não distingue o tamanho do ganho para considera-lo ou não um ganho...

Tá certo que acho que fui inocente de achar que tava com 80% de Ganhos de Take Profit, mas me surpreendi de sair desses 80 para 10% apenas!

Minha desconfiança veio do fato de que quando coloquei para rodar na conta real esta acontecendo exatamente isso : pouquíssimos Stop Losses .. até aí OK.  Mas um excesso absurdo de Break Even, totalmente "destoante" do resultado em backtest (meu robô não dá muita margem para diferenças tão absurdas por conta do método decisivo dele - não é baseado em médias nem coisa do tipo). 

E agora com esta solução no OnTradeTransaction confirmei minha hipótese: o backteste do metatrader considera Break Even como GANHO! - com certeza não é uma descoberta nova, mas no meu caso com essa solução consigo inclusive separar por valores de saída e ter cada resultado do backtest, inclusive separar ganhos pequenos (de proteção) de ganhos de TP (grandes ou maiores). E, se quiser dá pra separar ganhos intermediários, ganhos por trailling stop e outros conforme a criatividade.