Ajuda com Função de Take Profit - página 2

 
Ricardo Rodrigues Lucca #:

NormalizeDoubles nesse ultimo EA está claramente errado. Stop level só é usado no momento de colocar a ordem. O código supostamente modificado estava intocado. Mas não é bem o ponto.

Muda a ordem no OnTick para o CloseAll ser feito depois da martingale e da open alguma coisa. Me parece que não esta tendo chance desse código executar já que as posições foram encerradas.

Boa tarde,

NormalizeDoubles nesse ultimo EA está claramente errado.

O que há de errado na função? Tenho total interesse em corrigir a função.

Stop level só é usado no momento de colocar a ordem.

Fiz essa correção por meio da função abaixo. A chamo sempre que uma nova posição vai ser aberta.

//---
double GetMinStopLevel()
  {
   long minStopLevel = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
   if(minStopLevel == 0)
      minStopLevel = 1;
//---
   return minStopLevel * point;
  }


Muda a ordem no OnTick..

Fiz as modificações conforme sugerido, mas o problema com a posição do Take Profit ainda persiste, como pode ser observado na imagem abaixo.


Como não há um padrão consistente na quantidade de pontos adicionais sendo definidos para o Take Profit, isso torna tudo mais obscuro.

Mais uma vez obrigado pela disponibilidade em ajudar.

text - Schema.org Property
  • schema.org
Schema.org Property: text - The textual content of this CreativeWork.
 
Jeovane Reges #Bom dia! Você está absolutamente correto. Para sair do campo teórico, envio em anexo um EA demonstrativo que desenvolvi. Segue a descrição das principais funções que merecem atenção: CalculateTakeProfit: Responsável por definir os take profits de maneira que, quando atingidos, o lucro das posições positivas seja X (multipler) vezes maior do que a soma das posições negativas. GetProfitPositions: Retorna um valor booleano indicando se as posições abertas têm lucro X (multipler) vezes maior do que as perdas das posições negativas. CloseAllForce: Fecha automaticamente as posições se a função GetProfitPositions retornar TRUE. Para desativá-la, basta alterar o valor da variável ClosePositions para FALSE. Martingale:  Além de fazer o médio das posições negativas, também chama a função CalculateTakeProfit para ajustar o take profit das posições abertas. Essa verificação/mudança ocorre a cada 1 minuto, conforme definido na função OnTick. No print abaixo, pode-se observar que a função CloseAllForce fecha as posições antes do Take Profit setado pela função CalculateTakeProfit. Por isso, tenho insistido que os takes estão sendo definidos em um local "errado". A razão pela qual não quero usar a função CloseAllForce no mercado real já foi mencionada anteriormente. A estratégia do EA é apenas para efeito demonstrativo. Sei que não é o propósito, mas abaixo é apresentado o resultado do backtesting entre 01.01.2020 e 01.01.2024. Caso alguém queira aprimorá-la, fique à vontade. Mais uma vez obrigado pela disponibilidade em ajudar.

Ok, a partir do seu EA anexado, implementarei a função CalculateAverageTP() para realizar os testes que solicitei...

 

Adicionei ao seu código (editado) a função CalculateAverageTP() que foi sugerida anteriormente, testei (telas a seguir), e, aparentemente, funciona com precisão cirúrgica... 😁

Esse trecho de código foi inserido na função apenas para se comparar os valores previstos na mesma com os que foram efetivamente realizados:

   double open_price[], lots[]; // Utilizados apenas para testes
   ArrayResize(open_price, PositionsTotal());
   ArrayResize(lots, PositionsTotal());

//---

            open_price[pos_cnt] = price_open;
            lots[pos_cnt] = volume;

//---

//+  -  -  -  -  -  -  -  +
//| Apenas para testes    |
//+  -  -  -  -  -  -  -  +
//======================================================================================================================
   double profit, expected_profit = 0.0;
   ENUM_ORDER_TYPE order_type = type == POSITION_TYPE_BUY ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
   NormalizePrice(_Symbol, adjusted_tp);
   for(int i = 0; i < pos_cnt; i ++)
     {
      if(OrderCalcProfit(order_type, _Symbol, lots[i], open_price[i], adjusted_tp, profit))
        {
         expected_profit += profit;
        }
     }
   Print("### Perda atual: ", DoubleToString(total_loss, 2), "### Nº de posições: ", pos_cnt, " ### TP Ajustado: ", DoubleToString(adjusted_tp, _Digits), " ### Lucro Previsto: ", DoubleToString(expected_profit, 2));
//======================================================================================================================


Veja um exemplo do que foi previsto (clique para ampliar):


... E veja o que foi realizado (se não errei na soma, 😊 dá exatamente $ 4.14):


Então, a meu ver, a sua solicitação no comentário de abertura deste tópico foi devidamente atendida vários comentários atrás... 😁 Boa sorte!! 👍




Algumas alterações feitas no código original

- Removidas as constantes BUY e SELL

- Função CalculateTakeProfit() substituída pela função CalculateAverageTP() sugerida para testes

- Implementada a função UpdateAverageTP()

- Removida a função CloseAllForce()

- Removida a função CountPositions()

- Removida a função GetProfitPositions()

- Removida a função Martingale()

- Removida a função NormalizeDoubles()

- Adicionada a função NormalizePrice()

- Removido parâmetro de entrada ProfitMultiplier

- Removidas variáveis ClosePositions, stopLevel, _stopLevel, _tickSize

- Removida a função GetTicketLastPosition()

- Removidos parâmetro de entrada Stop e variável StopLoss

- Removidas variáveis MaximumNumberTrade, RepeatLot, IncrementSize


Exemplos bem básicos de funções, sem as devidas verificações de erro que o mercado real requer, apenas para testes...

Não sei se esqueci alguma coisa (provavelmente sim 😊), definitivamente não está "elegante", mas acho que, para os testes que solicitei, isso é suficiente.

Arquivos anexados:
EA-01.mq5  29 kb
 
Vinicius Pereira De Oliveira #:

Adicionei ao seu código (editado) a função CalculateAverageTP() que foi sugerida anteriormente, testei (telas a seguir), e, aparentemente, funciona com precisão cirúrgica... 😁

Esse trecho de código foi inserido na função apenas para se comparar os valores previstos na mesma com os que foram efetivamente realizados:


Veja um exemplo do que foi previsto (clique para ampliar):


... E veja o que foi realizado (se não errei na soma, 😊 dá exatamente $ 4.14):


Então, a meu ver, a sua solicitação no comentário de abertura deste tópico foi devidamente atendida vários comentários atrás... 😁 Boa sorte!! 👍




Algumas alterações feitas no código original

- Removidas as constantes BUY e SELL

- Função CalculateTakeProfit() substituída pela função CalculateAverageTP() sugerida para testes

- Implementada a função UpdateAverageTP()

- Removida a função CloseAllForce()

- Removida a função CountPositions()

- Removida a função GetProfitPositions()

- Removida a função Martingale()

- Removida a função NormalizeDoubles()

- Adicionada a função NormalizePrice()

- Removido parâmetro de entrada ProfitMultiplier

- Removidas variáveis ClosePositions, stopLevel, _stopLevel, _tickSize

- Removida a função GetTicketLastPosition()

- Removidos parâmetro de entrada Stop e variável StopLoss

- Removidas variáveis MaximumNumberTrade, RepeatLot, IncrementSize


Exemplos bem básicos de funções, sem as devidas verificações de erro que o mercado real requer, apenas para testes...

Não sei se esqueci alguma coisa (provavelmente sim 😊), definitivamente não está "elegante", mas acho que, para os testes que solicitei, isso é suficiente.

Boa noite, Vinicius.

Primeiramente obrigado pela paciência e disponibilidade. 😃

Não estou em casa, mas amanhã pela manhã irei testar e te dou um feedback. 

Abraços!
 
Vinicius Pereira De Oliveira #:

Adicionei ao seu código (editado) a função CalculateAverageTP() que foi sugerida anteriormente, testei (telas a seguir), e, aparentemente, funciona com precisão cirúrgica... 😁

Esse trecho de código foi inserido na função apenas para se comparar os valores previstos na mesma com os que foram efetivamente realizados:


Veja um exemplo do que foi previsto (clique para ampliar):


... E veja o que foi realizado (se não errei na soma, 😊 dá exatamente $ 4.14):


Então, a meu ver, a sua solicitação no comentário de abertura deste tópico foi devidamente atendida vários comentários atrás... 😁 Boa sorte!! 👍




Algumas alterações feitas no código original

- Removidas as constantes BUY e SELL

- Função CalculateTakeProfit() substituída pela função CalculateAverageTP() sugerida para testes

- Implementada a função UpdateAverageTP()

- Removida a função CloseAllForce()

- Removida a função CountPositions()

- Removida a função GetProfitPositions()

- Removida a função Martingale()

- Removida a função NormalizeDoubles()

- Adicionada a função NormalizePrice()

- Removido parâmetro de entrada ProfitMultiplier

- Removidas variáveis ClosePositions, stopLevel, _stopLevel, _tickSize

- Removida a função GetTicketLastPosition()

- Removidos parâmetro de entrada Stop e variável StopLoss

- Removidas variáveis MaximumNumberTrade, RepeatLot, IncrementSize


Exemplos bem básicos de funções, sem as devidas verificações de erro que o mercado real requer, apenas para testes...

Não sei se esqueci alguma coisa (provavelmente sim 😊), definitivamente não está "elegante", mas acho que, para os testes que solicitei, isso é suficiente.

Bom dia, Vinicius.

Vamos lá...

O código ainda está se comportando de maneira "inadequada".

Vou tentar explicar de outra forma o que estou pretendendo fazer. Para isso, vamos imaginar de maneira abstrata que eu tenha 3 posições abertas representadas por P1, P2 e P3, e cada uma tenha o seguinte flutuante:

  • P1: -$1,00
  • P2: -$0,75
  • P3: -$0,50

Quando essas três posições atingirem o take profit, quero que o resultado seja algo semelhante ao seguinte:

  • P1: -$0,50
  • P2: $0,50
  • P3: $1,00

Como pode ser observado, a soma das posições positivas ($1,50) é 3x maior do que a posição negativa (-$0,50). Não espero que o lucro final seja 3x maior, mas sim que a soma das posições positivas seja 3x maior que a negativa.

Talvez eu tenha me expressado de forma errada ou não tão clara anteriormente, e se isso aconteceu, peço desculpas antecipadamente.

 
Jeovane Reges #Bom dia, Vinicius. Vamos lá... O código ainda está se comportando de maneira "inadequada". Vou tentar explicar de outra forma o que estou pretendendo fazer. Para isso, vamos imaginar de maneira abstrata que eu tenha 3 posições abertas representadas por P1, P2 e P3, e cada uma tenha o seguinte flutuante: P1: -$1,00   P2: -$0,75   P3: -$0,50   Quando essas três posições atingirem o take profit, quero que o resultado seja algo semelhante ao seguinte: P1: -$0,50   P2: $0,50   P3: $1,00   Como pode ser observado, a soma das posições positivas ($1,50) é 3x maior do que a posição negativa (-$0,50). Não espero que o lucro final seja 3x maior, mas sim que a soma das posições positivas seja 3x maior que a negativa. Talvez eu tenha me expressado de forma errada ou não tão clara anteriormente, e se isso aconteceu, peço desculpas antecipadamente.

Boa noite, Jeovane!! Sim, a explicação atual mudou o meu entendimento do que seria a sua solicitação inicial... 😁 Mas vamos lá: vou ver o que consigo por aqui (casa alguém não apresente uma solução mais adequada)...

 
Considerando que, matematicamente, a condição dada (APARENTEMENTE) não pode ser atendida de maneira exata com as posições disponíveis e os preços de abertura, volumes e a relação desejada entre lucros e perdas, considerando também que neste fórum nós não utilizamos "gambiarras" em nossas sugestões 😂, eu parti para uma "solução engenhosa de engenharia criativa" (ou "inovação improvisada") 😁. A função seguinte parece estar funcionando corretamente, porém, como falei, trata-se de uma gigantesca gambiarra, acredito que, nem de longe, seja a solução mais inteligente e, definitivamente, também não está um código "elegante", mas pode ser útil em seus testes para validar (ou invalidar) a estratégia... Caso a estratégia se comprove eficiente, então você busca uma solução mais adequada para utilizar no seu código em conta real...
double CalculateAverageTP(ENUM_POSITION_TYPE type)
  {
// Inicialização de variáveis
   int pos_cnt = 0;
   double min_open = 0.0;
   double max_open = 0.0;
   double open_price[], lots[];

// Redimensiona os arrays conforme o número total de posições
   ArrayResize(open_price, PositionsTotal());
   ArrayResize(lots, PositionsTotal());

// Coleta dados das posições abertas
   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      if(PositionGetTicket(i) != 0 &&
         PositionGetString(POSITION_SYMBOL) == _Symbol &&
         (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == type)
        {
         double price_open = PositionGetDouble(POSITION_PRICE_OPEN);
         double volume = PositionGetDouble(POSITION_VOLUME);

         // Atualiza min_open e max_open
         if(min_open == 0.0 || min_open > price_open)
            min_open = price_open;
         if(max_open < price_open)
            max_open = price_open;

         open_price[pos_cnt] = price_open;
         lots[pos_cnt] = volume;
         pos_cnt++;
        }
     }

// Verifica se há menos de duas posições
   if(pos_cnt < 2)
      return 0.0;

// Calcula o limite de TP
   double limit_tp = (type == POSITION_TYPE_BUY) ?
                     NormalizeDouble(max_open + (max_open - min_open) * multiplierTP, _Digits) :
                     NormalizeDouble(min_open - (max_open - min_open) * multiplierTP, _Digits);

// Determina o tipo de ordem e o tamanho do tick
   ENUM_ORDER_TYPE order_type = (type == POSITION_TYPE_BUY) ? ORDER_TYPE_BUY : ORDER_TYPE_SELL;
   double tick_size;
   SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE, tick_size);
   if(type == POSITION_TYPE_SELL)
      tick_size *= -1.0;

// Pega o preço atual
   double curr_price = SymbolInfoDouble(_Symbol, (type == POSITION_TYPE_BUY) ? SYMBOL_ASK : SYMBOL_BID);

// Itera sobre os possíveis níveis de TP
   for(double curr_tp = curr_price; (type == POSITION_TYPE_BUY) ? curr_tp <= limit_tp : curr_tp >= limit_tp; curr_tp += tick_size)
     {
      double expected_profit = 0.0, expected_loss = 0.0;

      // Calcula o lucro/perda esperado para cada posição
      for(int i = 0; i < pos_cnt; i++)
        {
         double profit;
         if(OrderCalcProfit(order_type, _Symbol, lots[i], open_price[i], curr_tp, profit))
           {
            if(profit > 0.0)
               expected_profit += profit;
            else
               expected_loss += MathAbs(profit);
           }
        }

      // Verifica se a condição de lucro/perda é satisfeita
      if(expected_profit >= multiplierTP * expected_loss)
         return curr_tp;
     }

   return 0.0; // Retorna 0.0 se nenhum TP adequado for encontrado
  }
Arquivos anexados:
EA-01.mq5  29 kb
 
Vinicius Pereira De Oliveira #:
Considerando que, matematicamente, a condição dada (APARENTEMENTE) não pode ser atendida de maneira exata com as posições disponíveis e os preços de abertura, volumes e a relação desejada entre lucros e perdas, considerando também que neste fórum nós não utilizamos "gambiarras" em nossas sugestões 😂, eu parti para uma "solução engenhosa de engenharia criativa" (ou "inovação improvisada") 😁. A função seguinte parece estar funcionando corretamente, porém, como falei, trata-se de uma gigantesca gambiarra, acredito que, nem de longe, seja a solução mais inteligente e, definitivamente, também não está um código "elegante", mas pode ser útil em seus testes para validar (ou invalidar) a estratégia... Caso a estratégia se comprove eficiente, então você busca uma solução mais adequada para utilizar no seu código em conta real...

Fala, Vinicius.

Desculpa a demora pelo feedback, passei o dia preso em "burocracias" e só agora à tarde consegui parar para testar sua solução SUPER ELEGANTE.

A solução está tão elegante e funcional que nem precisa aplicar nenhuma técnica de Design Patterns haha.

MUITO BOA A SUA PROPOSTA DE SOLUÇÃO, PARABÉNS.

Mais uma vez, obrigado pela ajuda e disponibilidade. Fico feliz em saber que o fórum tem pessoas tão boas e dispostas a ajudar como você :-D

PARABÉNS E OBRIGADO.

Design Patterns
Design Patterns
  • refactoring.guru
Design Patterns are typical solutions to commonly occurring problems in software design. They are blueprints that you can customize to solve a particular design problem in your code.
 
Jeovane Reges #Fala, Vinicius. Desculpa a demora pelo feedback, passei o dia preso em "burocracias" e só agora à tarde consegui parar para testar sua solução SUPER ELEGANTE. A solução está tão elegante e funcional que nem precisa aplicar nenhuma técnica de Design Patterns haha. MUITO BOA A SUA PROPOSTA DE SOLUÇÃO, PARABÉNS. Mais uma vez, obrigado pela ajuda e disponibilidade. Fico feliz em saber que o fórum tem pessoas tão boas e dispostas a ajudar como você :-D PARABÉNS E OBRIGADO.

De nada, Jeovane!! 😊 Boa sorte com seus projetos!! 👍