English Русский 中文 Español Deutsch 日本語
preview
Negociação de notícias facilitada (parte 5): realizando negociações (II)

Negociação de notícias facilitada (parte 5): realizando negociações (II)

MetaTrader 5Sistemas de negociação |
183 6
Kabelo Frans Mampa
Kabelo Frans Mampa

Introdução

Neste artigo, nosso principal objetivo é escrever o código para implementar ordens stop no expert de trading de notícias. Essas ordens stop serão usadas em um artigo posterior para negociar eventos de notícias. Além disso, criaremos funções para gerenciar o slippage das ordens stop, fechar trades e realizar verificações de validação para indicar se um trade ou uma ordem pode ser aberta. O gerenciamento de trades é crucial em qualquer sistema de trading algorítmico porque envolve tarefas como abrir e fechar posições, ajustar stop-losses e gerenciar take-profits. Um gerenciamento de trades eficiente pode ajudar o trader a capturar mais lucro, ao mesmo tempo em que minimiza a exposição a movimentos adversos do mercado.


Por que usar ordens stop?


Ordem limite vs Ordem stop

O uso de ordens stop ao negociar eventos de notícias é uma estratégia comum porque elas ajudam os traders a capitalizar os movimentos bruscos de preço que frequentemente seguem grandes divulgações econômicas, enquanto também minimizam certos riscos.

Capturando Movimentos de Breakout

Eventos de notícias, como relatórios econômicos ou anúncios de bancos centrais, frequentemente levam a movimentos repentinos e significativos de preço. Esses movimentos são conhecidos como breakouts. Uma ordem stop permite que o trader entre no mercado em um nível de preço pré-definido quando o preço ultrapassa determinado limite, o que é ideal para capturar esses movimentos de breakout sem precisar monitorar o mercado manualmente.

  • Buy Stop Order: Colocada acima do preço atual de mercado. Aciona uma ordem de compra quando o preço sobe, capturando o impulso de alta após uma notícia positiva.
  • Sell Stop Order: Colocada abaixo do preço atual de mercado. Aciona uma ordem de venda quando o preço cai, aproveitando uma notícia negativa.

Pode ajudar a evitar Whipsaws de Mercado

A volatilidade relacionada a notícias pode causar flutuações de preço antes que uma direção clara seja estabelecida. Traders que entram em posições cedo demais podem ser pegos em whipsaws — movimentos rápidos em ambas as direções que podem acionar os stops. As ordens stop ajudam a evitar esses falsos sinais, garantindo que a trade só seja acionada quando o mercado realmente se comprometer com uma direção além de um ponto de preço específico.

Limitando a Análise Excessiva no Trading

Operar em torno de eventos de notícias pode ser estressante devido aos movimentos rápidos do mercado. Configurar ordens stop com antecedência permite que os traders entrem e saiam de posições sem interferência emocional ou necessidade de adivinhar a direção do evento. Uma vez que as ordens são colocadas, a decisão do trader já está tomada, eliminando a tentação de reagir em excesso às flutuações de curto prazo. No contexto deste artigo, isso significa que discursos e outros eventos de notícias que não têm impacto direto podem ser operados com o uso de ordens stop, já que a direção é difícil ou impossível de prever antecipadamente.

Minimizando o Slippage

Ao usar ordens stop, os traders podem evitar o slippage associado a ordens de mercado feitas durante períodos de alta volatilidade. Embora o slippage ainda possa ocorrer, uma ordem stop tem mais chance de ser executada próxima ao nível desejado do que uma ordem de mercado colocada após a notícia já ter causado uma mudança significativa no preço

Gestão de Risco

As ordens stop ajudam a automatizar o gerenciamento de risco. Por exemplo, se um trader antecipa uma reação volátil a um evento de notícias, ele pode colocar tanto uma ordem buy stop quanto uma ordem sell stop (straddle strategy). Essa abordagem ajuda o trader a entrar no mercado em qualquer direção, dependendo de como o preço se movimentar. Uma vez acionada, a ordem stop oposta pode ser cancelada para gerenciar o risco.

Cenário:

Você está negociando os EUA. o dólar americano em torno do anúncio do Payroll Não-Agrícola (NFP), um dos eventos de notícias mais impactantes do mercado. Esperando que os dados causem um movimento significativo no par EUR/USD, você coloca uma ordem buy stop acima do preço atual e uma ordem sell stop abaixo do preço atual (estratégia straddle).

Cenário antes do NFP

  • Dados NFP positivos: O dólar se fortalece, fazendo o EUR/USD cair, acionando sua ordem sell stop.
  • Dados NFP negativos: O dólar enfraquece, fazendo o EUR/USD subir, acionando sua ordem buy stop.

Snapshot depois do NFP

Ao usar ordens stop, você está preparado para movimento em qualquer direção e entra no mercado automaticamente assim que a ação do preço confirma a direção do breakout.


Propriedades da conta de classe

A classe CAccountProperties, que herda da classe CAccountInfo no MQL5. O objetivo desta classe é estender a CAccountInfo com um método personalizado para recuperar o número total de tipos específicos de ordens na conta de trading, como ordens buy ou sell limit/stop. Essa função adicional será usada na classe de gerenciamento de trades para ajudar a garantir que o expert respeite o limite de ordens da conta.

Por exemplo: se o limite de ordens da conta for 200, isso significa que a conta do usuário não pode ultrapassar 200 ordens, incluindo abertas e pendentes. Portanto, se quisermos abrir uma buy-stop e uma sell-stop, mas a conta do usuário já tiver 199 ordens, o expert identificará que não há ordens suficientes disponíveis para abrir ambas, e nesse cenário nenhuma ordem adicional será adicionada à conta do usuário.

Cabeçalho e Inclusões:

O código abaixo inclui o arquivo AccountInfo.mqh da biblioteca padrão do MQL5. Esse arquivo contém funções e estruturas predefinidas para acessar informações da conta de trading.

#include <Trade/AccountInfo.mqh>

Definição da Classe CAccountProperties:

Herança: A classe CAccountProperties herda publicamente de CAccountInfo. Ao herdar, a CAccountProperties ganha acesso às funções e membros de dados de CAccountInfo.

CAccountInfo fornece dados essenciais da conta, como saldo, patrimônio, margem livre etc.

Objetivo da classe: A classe CAccountProperties adiciona um método (numOrders) que conta tipos específicos de ordens.

class CAccountProperties: public CAccountInfo

Função numOrders:

A função numOrders() é onde ocorre a maior parte da ação. Ela conta o número de tipos específicos de ordens (limit e stop) que estão atualmente abertas na conta de trading.

  • Tipo de retorno: a função retorna um inteiro.
  • Inicialização: A variável num é inicializada em 0. Ela armazenará a contagem das ordens que correspondem aos tipos desejados.

int CAccountProperties::numOrders(void)
{
   int num=0;

Iteração das Ordens:

  • OrdersTotal() é uma função MQL5 que retorna o número total de ordens.
  • Um loop é usado para iterar por todas as ordens, do índice 0 até OrdersTotal() - 1.

for(int i=0; i<OrdersTotal(); i++)

Validação das Ordens:

  • OrderGetTicket(i) é uma função MQL5 que recupera o número do ticket da ordem no índice i. Cada ordem tem um número de ticket único.
  • Se o número do ticket for maior que 0, significa que a ordem é válida, e o código prossegue para verificar seu tipo.

if(OrderGetTicket(i)>0)

Checando o Tipo da Ordem:

  • OrderGetInteger(ORDER_TYPE) recupera o tipo da ordem no índice i. Esse valor corresponde a um inteiro que representa vários tipos de ordens (buy limit, sell stop etc.).
  • A instrução switch verifica o tipo de cada ordem e compara com constantes predefinidas de tipos de ordens.
switch(int(OrderGetInteger(ORDER_TYPE)))

Tratando Tipos Específicos de Ordens:

  • Tipos de ordem:
    • ORDER_TYPE_BUY_LIMIT: Uma ordem de compra limitada.
    • ORDER_TYPE_BUY_STOP: Uma ordem de compra stop..
    • ORDER_TYPE_BUY_STOP_LIMIT: Uma ordem de compra stop limitada.
    • ORDER_TYPE_SELL_LIMIT: Uma ordem de venda limitada.
    • ORDER_TYPE_SELL_STOP: Uma ordem de venda stop.
    • ORDER_TYPE_SELL_STOP_LIMIT: Uma ordem de venda stop limitada.

Para cada tipo de ordem reconhecido, o contador num é incrementado. Se a ordem for de qualquer outro tipo, o caso padrão é acionado e nenhuma ação é tomada.

case ORDER_TYPE_BUY_LIMIT:
    num++;
    break;
case ORDER_TYPE_BUY_STOP:
    num++;
    break;
case ORDER_TYPE_BUY_STOP_LIMIT:
    num++;
    break;
case ORDER_TYPE_SELL_LIMIT:
    num++;
    break;
case ORDER_TYPE_SELL_STOP:
    num++;
    break;
case ORDER_TYPE_SELL_STOP_LIMIT:
    num++;
    break;
default:
    break;

Retornando a contagem:

  • Após iterar por todas as ordens e contar as válidas, a função retorna a contagem total armazenada em num.

   return num;
}



Classe de Gerenciamento de Risco

Essa classe garante que a exposição do trader ao risco de mercado seja controlada, limitando perdas potenciais enquanto permite espaço para ganhos. Dito isso, pequenas atualizações foram feitas nesta classe. O código abaixo define uma enumeração OrderTypeSelection, usada para representar diferentes tipos de classificação de ordens. O usuário poderá escolher com quais desses tipos de ordens prefere negociar.
//-- Enumeration for Order type
enum OrderTypeSelection
  {
   MarketPositionType,//MARKET POSITION
   StopOrdersType,//STOP ORDERS
   StopOrderType,//SINGLE STOP ORDER
  } myOrderSelection;

Enumeração: OrderTypeSelection

A enumeração OrderTypeSelection consiste em três valores diferentes:

MarketPositionType:

  • Representa uma ordem de posição de mercado.
  • Esse tipo abre com base no preço atual do mercado, sendo executado imediatamente ao preço corrente.
  • Requer impacto de evento.

StopOrdersType:

  • Representa ordens stop.
  • As ordens stop são ordens condicionais que executam apenas quando o preço atinge determinado nível. Tanto ordens de compra-stop quanto de venda-stop são abertas.
  • Não requer impacto de evento.

StopOrderType:

  • Representa uma ordem stop única.
  • Uma ordem individual de compra-stop ou venda-stop é aberta.
  • Requer impacto de evento.

Declaração de Variável: myOrderSelection

  • myOrderSelection é uma variável que armazenará o tipo de ordem atual selecionado pelo trader.

Normalização do Tamanho do Lote

Na função abaixo, o limite de volume mudará dependendo do OrderTypeSelection. Quando myOrderSelection é StopOrdersType (STOP ORDERS), o limite de volume é reduzido pela metade para acomodar tanto a ordem de compra-stop quanto a ordem de venda-stop, pois ambas precisam ser abertas ao mesmo tempo. Já MarketPositionType (MARKET POSITION) e StopOrderType (SINGLE STOP ORDER) abrem apenas ordens individuais.

void CRiskManagement::NormalizeLotsize(double &Lotsize)
{
    // Adjust lot size to match symbol's step size or minimum size
    if (Lotsize <= 0.0) return;
    double VolumeLimit = (myOrderSelection != StopOrdersType) ? CSymbol.LotsLimit() : CSymbol.LotsLimit() / 2;
    // Check and adjust if volume exceeds limits
    // ...
}



Classe de Sessões

O código abaixo define uma classe CSessions, responsável por gerenciar e rastrear os horários de sessão de negociação de um determinado símbolo de trading. Ela usa métodos de uma classe base CTimeManagement (incluída via Timemanagement.mqh) para determinar se uma sessão começou, terminou e para obter o horário de encerramento da sessão. No contexto, precisamos saber quando a sessão terminará para encerrar operações antes e definir datas de expiração de ordens, evitando assim negociações durante a noite.

Por que evitar negociações overnight?

Negociação Overnight

Aumento do risco de mercado devido à volatilidade

Os mercados podem ser altamente voláteis durante a noite, especialmente em resposta a eventos econômicos, desenvolvimentos geopolíticos ou notícias de outros mercados globais. Como grandes eventos podem ocorrer fora do horário normal, posições mantidas overnight ficam expostas a movimentos imprevisíveis de preços. Esses movimentos podem causar:

  • Gaps significativos no preço na abertura do dia seguinte, resultando em ganhos ou perdas substanciais.
  • Capacidade limitada de resposta a mudanças rápidas, já que a liquidez pode ser baixa e a modificação ou saída de posições pode ser dificultada.

Liquidez limitada

A liquidez tende a ser menor durante sessões noturnas porque há menos participantes ativos. Isso pode levar a:

  • Spreads maiores entre preço de compra e venda, aumentando os custos de transação.
  • Slippage (execução em preço diferente do esperado) devido à falta de profundidade de mercado.
  • Dificuldade em fechar grandes posições sem mover o mercado, causando execução desfavorável.

Maior risco de gaps

A negociação durante a noite pode expor os comerciantes a lacunas de preços, onde o preço na abertura do mercado é significativamente diferente do fechamento do dia anterior. Lacunas podem ocorrer devido a comunicados de notícias ou outros eventos e podem resultar em:

  • Perdas maiores que o esperado, se o preço se mover contra a posição.
  • Stop-loss ineficazes, já que gaps podem ultrapassar níveis definidos, executando ordens em preços piores.

Cobrança de juros (Swap Fees)

Para certos instrumentos como Forex, manter posições durante a noite pode resultar em taxas de swap ou encargos de juros, dependendo da diferença de taxa de juros entre as moedas envolvidas. Esses custos podem se acumular ao longo do tempo e reduzir a lucratividade. As taxas de swap podem:

  • Transformar operações lucrativas em perdas, especialmente se mantidas por períodos prolongados.
  • Variam dependendo das condições de mercado, tornando-as mais difíceis de prever e planejar.

Controle Reduzido Sobre a Execução das Operações

Durante a noite, especialmente em mercados com horários limitados ou irregulares, a execução das operações pode ser mais lenta ou menos precisa devido a:

  • Horário de funcionamento da corretora: algumas corretoras podem não suportar certas ações ou modificações de negociação fora do seu horário regular, reduzindo sua capacidade de responder às condições do mercado.

//+------------------------------------------------------------------+
//|                                                      NewsTrading |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                            https://www.mql5.com/en/users/kaaiblo |
//+------------------------------------------------------------------+
#include "Timemanagement.mqh"
//+------------------------------------------------------------------+
//|Sessions Class                                                    |
//+------------------------------------------------------------------+
class CSessions:CTimeManagement
  {
public:
                     CSessions(void) {}
                    ~CSessions(void) {}
   //--- Check if trading Session has began
   bool              isSessionStart(int offsethour=0,int offsetmin=0);
   //--- Check if trading Session has ended
   bool              isSessionEnd(int offsethour=0,int offsetmin=45);
   //--- Get Session End datetime
   datetime          SessionEnd(int offsethour=0,int offsetmin=45);
  };
//+------------------------------------------------------------------+
//|Check if trading Session has started                              |
//+------------------------------------------------------------------+
bool CSessions::isSessionStart(int offsethour=0,int offsetmin=0)
  {
//--- Declarations
   datetime datefrom,dateto,DateFrom[],DateTo[];

//--- Find all session times
   for(int i=0; i<10; i++)
     {
      //--- Get the session dates for the current symbol and Day of week
      if(SymbolInfoSessionTrade(Symbol(),DayOfWeek(TimeTradeServer()),i,datefrom,dateto))
        {
         //--- Check if the end date's hour is at midnight
         if(ReturnHour(dateto)==00||ReturnHour(dateto)==24)
           {
            //--- Adjust the date to one minute before midnight
            dateto = Time(TimeTradeServer(),23,59);
           }
         //--- Re-adjust DateFrom Array size
         ArrayResize(DateFrom,int(ArraySize(DateFrom))+1,int(ArraySize(DateFrom))+2);
         //--- Assign the last array index datefrom value
         DateFrom[int(ArraySize(DateFrom))-1] = datefrom;
         //--- Re-adjust DateTo Array size
         ArrayResize(DateTo,int(ArraySize(DateTo))+1,int(ArraySize(DateTo))+2);
         //--- Assign the last array index dateto value
         DateTo[int(ArraySize(DateTo))-1] = dateto;
        }
     }

//--- Check if there are session times
   if(DateFrom.Size()>0)
     {
      /* Adjust DateFrom index zero date as the first index date will be the earliest date
       from the whole array, we add the offset to this date only*/
      DateFrom[0] = TimePlusOffset(DateFrom[0],MinutesS(offsetmin));
      DateFrom[0] = TimePlusOffset(DateFrom[0],HoursS(offsethour));
      //--- Iterate through the whole array
      for(uint i=0; i<DateFrom.Size(); i++)
        {
         //--- Check if the current time is within the trading session
         if(TimeIsInRange(Time(Today(ReturnHour(DateFrom[i]),ReturnMinute(DateFrom[i])))
                          ,Time(Today(ReturnHour(DateTo[i]),ReturnMinute(DateTo[i])))))
           {
            return true;
           }
        }
     }
   else
     {
      //--- If there are no trading session times
      return true;
     }
   return false;
  }

//+------------------------------------------------------------------+
//|Check if trading Session has ended                                |
//+------------------------------------------------------------------+
bool CSessions::isSessionEnd(int offsethour=0,int offsetmin=45)
  {
//--- Declarations
   datetime datefrom,dateto,DateTo[],lastdate=0,sessionend;

//--- Find all session times
   for(int i=0; i<10; i++)
     {
      //--- Get the session dates for the current symbol and Day of week
      if(SymbolInfoSessionTrade(Symbol(),DayOfWeek(TimeTradeServer()),i,datefrom,dateto))
        {
         //--- Check if the end date's hour is at midnight
         if(ReturnHour(dateto)==00||ReturnHour(dateto)==24)
           {
            //--- Adjust the date to one minute before midnight
            dateto = Time(TimeTradeServer(),23,59);
           }
         //--- Re-adjust DateTo Array size
         ArrayResize(DateTo,int(ArraySize(DateTo))+1,int(ArraySize(DateTo))+2);
         //--- Assign the last array index dateto value
         DateTo[int(ArraySize(DateTo))-1] = dateto;
        }
     }

//--- Check if there are session times
   if(DateTo.Size()>0)
     {
      //--- Assign lastdate a default value
      lastdate = DateTo[0];
      //--- Iterate through the whole array
      for(uint i=0; i<DateTo.Size(); i++)
        {
         //--- Check for the latest date in the array
         if(DateTo[i]>lastdate)
           {
            lastdate = DateTo[i];
           }
        }
     }
   else
     {
      //--- If there are no trading session times
      return false;
     }
   /* get the current time and modify the hour and minute time to the lastdate variable
   and assign the new datetime to sessionend variable*/
   sessionend =  Time(Today(ReturnHour(lastdate),ReturnMinute(lastdate)));
//--- Re-adjust the sessionend dates with the minute and hour offsets
   sessionend = TimeMinusOffset(sessionend,MinutesS(offsetmin));
   sessionend = TimeMinusOffset(sessionend,HoursS(offsethour));

//--- Check if sessionend date is more than the current time
   if(TimeTradeServer()<sessionend)
     {
      return false;
     }
   return true;
  }

//+------------------------------------------------------------------+
//|Get Session End datetime                                          |
//+------------------------------------------------------------------+
datetime CSessions::SessionEnd(int offsethour=0,int offsetmin=45)
  {
//--- Declarations
   datetime datefrom,dateto,DateTo[],lastdate=0,sessionend;

//--- Find all session times
   for(int i=0; i<10; i++)
     {
      //--- Get the session dates for the current symbol and Day of week
      if(SymbolInfoSessionTrade(Symbol(),DayOfWeek(TimeTradeServer()),i,datefrom,dateto))
        {
         //--- Check if the end date's hour is at midnight
         if(ReturnHour(dateto)==00||ReturnHour(dateto)==24)
           {
            //--- Adjust the date to one minute before midnight
            dateto = Time(TimeTradeServer(),23,59);
           }
         //--- Re-adjust DateTo Array size
         ArrayResize(DateTo,int(ArraySize(DateTo))+1,int(ArraySize(DateTo))+2);
         //--- Assign the last array index dateto value
         DateTo[int(ArraySize(DateTo))-1] = dateto;
        }
     }

//--- Check if there are session times
   if(DateTo.Size()>0)
     {
      //--- Assign lastdate a default value
      lastdate = DateTo[0];
      //--- Iterate through the whole array
      for(uint i=0; i<DateTo.Size(); i++)
        {
         //--- Check for the latest date in the array
         if(DateTo[i]>lastdate)
           {
            lastdate = DateTo[i];
           }
        }
     }
   else
     {
      //--- If there are no trading session times
      return 0;
     }
   /* get the current time and modify the hour and minute time to the lastdate variable
   and assign the new datetime to sessionend variable*/
   sessionend = Time(Today(ReturnHour(lastdate),ReturnMinute(lastdate)));
//--- Re-adjust the sessionend dates with the minute and hour offsets
   sessionend = TimeMinusOffset(sessionend,MinutesS(offsetmin));
   sessionend = TimeMinusOffset(sessionend,HoursS(offsethour));
//--- return sessionend date
   return sessionend;
  }
//+------------------------------------------------------------------+

Explicação dos Componentes-Chave

Definição da Classe: CSessions

  • Herança:
    • A classe CSessions herda de CTimeManagement, portanto tem acesso a quaisquer métodos e atributos relacionados à gestão de tempo definidos nessa classe base.
  • Métodos:
    • isSessionStart(int offsethour=0, int offsetmin=0):
      • Determina se uma sessão de negociação foi iniciada, verificando o horário atual do servidor em relação aos horários de início da sessão. Também permite a aplicação de deslocamentos opcionais de tempo.
    • isSessionEnd(int offsethour=0, int offsetmin=45):
      • Determina se uma sessão de negociação terminou, verificando o horário atual do servidor em relação aos horários de término da sessão. Assim como isSessionStart, aceita deslocamentos opcionais (padrão: 45 minutos).
    • SessionEnd(int offsethour=0, int offsetmin=45):
      • Retorna o valor datetime do final da sessão de negociação atual, ajustando com os deslocamentos fornecidos (padrão: 45 minutos).

Detalhes dos Métodos

isSessionStart(int offsethour=0, int offsetmin=0)

Este método verifica se a sessão de negociação começou, com base no horário do servidor e no cronograma da sessão do ativo.

Variáveis:

  • datefrom, dateto: usados para armazenar os horários de início e término da sessão em cada dia de negociação.
  • DateFrom[], DateTo[]: arrays para armazenar os horários de início e término da sessão após ajustes.

Lógica:

  • Recuperação da Sessão:
    • A função SymbolInfoSessionTrade recupera os horários de início (datefrom) e término (dateto) da sessão de negociação para o ativo atual e o dia da semana (obtido por DayOfWeek(TimeTradeServer())).
    • Se o horário de término da sessão (dateto) for à meia-noite (00:00 ou 24:00), o tempo é ajustado para um minuto antes da meia-noite (23:59).
  • Manipulação de Arrays:
    • Os horários de início das sessões (datefrom) são armazenados no array DateFrom[], e os horários de término (dateto) no array DateTo[].
  • Aplicação de Deslocamento:
    • O método ajusta o horário de início da primeira sessão pelo offsethour e offsetmin fornecidos, usando as funções auxiliares MinutesS() e HoursS().
  • Verificação do Horário Atual:
    • O método percorre os horários de sessão em DateFrom[] e DateTo[] e verifica se o horário atual do servidor (TimeTradeServer()) está dentro de algum intervalo de sessão.
    • Se uma sessão válida for encontrada, retorna verdadeiro, indicando que a sessão começou. Caso contrário, retorna falso.

isSessionEnd(int offsethour=0, int offsetmin=45)

Este método verifica se a sessão de negociação terminou.

Variáveis:

  • Semelhante ao isSessionStart(), mas focado nos horários de término (dateto).
  • lastdate: armazena o último horário de término da sessão para comparação.
  • sessionend: armazena o horário final da sessão, calculado com os deslocamentos aplicados.

Lógica:

  • Recuperação da Sessão:
    • Recupera os horários de sessão (datefrom, dateto), assim como em isSessionStart().
    • Verifica se existem horários válidos em DateTo[] e identifica o último horário de término da sessão (lastdate).
  • Aplicação de Deslocamento:
    • Ajusta o horário de término da sessão aplicando os deslocamentos (offsethour e offsetmin).
  • Comparação com o Horário do Servidor:
    • Se o horário atual for antes do horário ajustado de término da sessão, retorna falso, indicando que a sessão ainda está em andamento. Se a sessão já terminou (horário atual depois de sessionend), retorna verdadeiro.

SessionEnd(int offsethour=0, int offsetmin=45)

Este método retorna o valor datetime para o término da sessão atual, aplicando os deslocamentos de tempo fornecidos.

Lógica:

  • Semelhante ao isSessionEnd(), recupera os horários da sessão, aplica deslocamentos e retorna o horário final ajustado da sessão (sessionend).
Resumo das Desvantagens da Negociação Noturna:
  • Maior volatilidade e movimentos de mercado imprevisíveis.
  • Baixa liquidez, levando a spreads mais amplos e custos mais altos.
  • Risco de gaps de preço, potencialmente resultando em grandes perdas.
  • Exposição a eventos globais e seus impactos no mercado.
  • Cobrança de juros ou taxas de swap nos mercados de Forex.
  • Controle reduzido sobre a execução e a tomada de decisão das operações.


Classe de Gestão de Operações

A classe CTradeManagement estende CRiskManagement e contém funcionalidades para gerenciar negociações, como envio de ordens de compra/venda, tratamento de stop-loss e take-profit, e gerenciamento de ordens stop.

Fluxograma para abertura de ordem de compra ou venda:

+---------------------------+
| Receive Trade Signal      |
+---------------------------+
              |
              V
+---------------------------+
| Check for Available Margin|
+---------------------------+
              |
              V
+---------------------------+
| Place Buy/Sell Order      |
+---------------------------+
              |
              V
+----------------------------+
| Set Stop Loss & Take Profit|
+----------------------------+
              |
              V
+----------------------------+
| Monitor Open Position      |
+----------------------------+
              |
        If conditions met:
              |
              V
+----------------------------+
| Adjust SL/TP or Close Trade|
+----------------------------+
//+------------------------------------------------------------------+
//|                                                      NewsTrading |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                            https://www.mql5.com/en/users/kaaiblo |
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>
#include <Trade\OrderInfo.mqh>
#include <Trade\SymbolInfo.mqh>
#include "RiskManagement.mqh"
#include "TimeManagement.mqh"
#include "Sessions.mqh"

//+------------------------------------------------------------------+
//|TradeManagement class                                             |
//+------------------------------------------------------------------+
class CTradeManagement:CRiskManagement
  {
private:
   CTrade            Trade;//Trade class object
   CSymbolProperties CSymbol;//SymbolProperties class object
   CTimeManagement   CTime;//TimeManagement class object
   CSessions         CTS;//Sessions class object
   bool              TradeResult;//boolean to store trade result
   double            mySL;//double variable to store Stoploss
   double            myTP;//double variable to store Takeprofit
   uint              myDeviation;//store price deviation for stop orders
   double            myOpenPrice;//store open price for stop orders
   //--- Will retrieve if there are any open trades
   bool              OpenTrade(ENUM_POSITION_TYPE Type,ulong Magic,string COMMENT=NULL);
   //--- Will retrieve if there are any deals
   bool              OpenedDeal(ENUM_DEAL_TYPE Type,ulong Magic,string COMMENT=NULL);
   //--- Will retrieve if there are any open orders
   bool              OpenOrder(ENUM_ORDER_TYPE Type,ulong Magic,string COMMENT=NULL);
   //--  Check if trade is valid
   bool              Valid_Trade(ENUM_POSITION_TYPE Type,double Price,double SL,double TP);
   //-- Check if stop order is valid
   bool              Valid_Order(ENUM_ORDER_TYPE Type,double Price,double SL,double TP);
   //--- Will attempt to open buy trade
   bool              Buy(double SL,double TP,ulong Magic,string COMMENT=NULL);
   //--- Will attempt to open sell trade
   bool              Sell(double SL,double TP,ulong Magic,string COMMENT=NULL);

   //--- class to set and retrieve an order's properties
   class OrderSettings
     {
   private:
      struct TradeProperties
        {
         //store open-price,take-profit,stop-loss for stop orders
         double         Open,Take,Stop;
        } myTradeProp;
   public:
                     OrderSettings() {}
      //--- Set order properties
      void           Set(double myOpen,double myTake,double myStop)
        {
         //--- Set open-price
         myTradeProp.Open=myOpen;
         //--- Set take-profit
         myTradeProp.Take=myTake;
         //--- Set stop-loss
         myTradeProp.Stop=myStop;
        }
      TradeProperties Get()
        {
         //--- retrieve order properties
         return myTradeProp;
        }
     };

   //--- Declare variables for different order types
   OrderSettings     myBuyStop,mySellStop,myBuyTrade,mySellTrade;

   //--- Will set buy-stop order properties
   void              SetBuyStop(int SL,int TP);
   //--- Will set buy position properties
   void              SetBuyTrade(int SL,int TP,double OP);
   //--- Will set sell-stop order properties
   void              SetSellStop(int SL,int TP);
   //--- Will set sell position properties
   void              SetSellTrade(int SL,int TP,double OP);

public:
   //--- Class constructor
                     CTradeManagement(uint deviation,string SYMBOL=NULL)
                     :myDeviation(deviation)//Assign deviation value
     {
      //--- Set symbol name
      CSymbol.SetSymbolName(SYMBOL);
     }
   //--- Class destructor
                    ~CTradeManagement(void)
     {
     }
   //--- Will attempt to open buy trade
   bool              Buy(int SL,int TP,ulong Magic,string COMMENT=NULL);
   //--- Will attempt to open sell trade
   bool              Sell(int SL,int TP,ulong Magic,string COMMENT=NULL);
   /*This function will delete a pending order if the previous opposing pending order is
   opened into a position, this function is used when trading with StopOrdersType(STOP ORDERS)*/
   void              FundamentalMode(string COMMENT_COMMON);
   /* Function will attempt to re-adjust stop-losses or take-profit values that have
   been changed due to slippage on an order when opening.
   */
   void              SlippageReduction(int SL,int TP,string COMMENT_COMMON);
   //--- This function will open both buy-stop and sell-stop orders for StopOrdersType(STOP ORDERS)
   bool              OpenStops(int SL,int TP,ulong Magic,string COMMENT=NULL);
   //--- Will attempt to open a sell-stop order
   bool              OpenSellStop(int SL,int TP,ulong Magic,string COMMENT=NULL);
   //--- Will attempt to open a buy-stop order
   bool              OpenBuyStop(int SL,int TP,ulong Magic,string COMMENT=NULL);
   //--- Function will attempt to close all trades depending on the position comment
   void              CloseTrades(string COMMENT_COMMON);
  };
// ...

Membros Privados:

  • Objetos e variáveis:
    • CTrade Trade: Gerencia a execução de operações (ordens de compra/venda) etc.
    • CSymbolProperties CSymbol: Gerencia as propriedades do símbolo.
    • CTimeManagement CTime: Lida com a lógica relacionada ao tempo.
    • CSessions CTS: Gerencia sessões, relacionadas aos horários de negociação.
    • bool TradeResult: Um indicador booleano para o resultado de uma operação (sucesso/falha).
    • double mySL: Valor de stop-loss.
    • double myTP: Valor de take-profit.
    • uint myDeviation;: Desvio de preço para ordens stop.
    • double myOpenPrice: Armazena o preço de abertura para ordens stop.

Classe Interna OrderSettings:

class OrderSettings
{
private:
   struct TradeProperties
   {
      double Open, Take, Stop;
   } myTradeProp;
public:
   OrderSettings() {}
   void Set(double myOpen, double myTake, double myStop)
   {
      myTradeProp.Open = myOpen;
      myTradeProp.Take = myTake;
      myTradeProp.Stop = myStop;
   }
   TradeProperties Get()
   {
      return myTradeProp;
   }
};

  • Propósito: esta classe interna encapsula as propriedades da operação (preço de abertura, take-profit, stop-loss). Ela permite definir e recuperar facilmente essas propriedades.
    • myTradeProp: Um struct para armazenar propriedades da operação.
    • Set(): Método para definir os valores de abertura, take-profit e stop-loss.
    • Get(): Recupera as propriedades armazenadas da operação.
  • Variáveis usando OrderSettings:

OrderSettings myBuyStop, mySellStop, myBuyTrade, mySellTrade;

    • Esses objetos armazenam as propriedades para diferentes tipos de ordens (buy-stop, sell-stop, buy-trade, sell-trade).

A função FundamentalMode no código abaixo foi projetada para excluir uma ordem stop pendente quando sua ordem oposta tiver sido executada e aberta como uma posição. Essa funcionalidade é relevante para estratégias que utilizam ordens buy-stop e sell-stop (como estratégias de straddle) para entrar em posições em mercados voláteis. Uma vez que uma das ordens stop é acionada e uma posição é aberta, a ordem oposta restante (agora redundante) é excluída para evitar operações desnecessárias.

Exemplo:

Buy-stop é aberto em 1.13118 e Sell-stop é aberto em 1.12911, o Buy-stop é executado primeiro com a mensagem de diário 'deal performed [#2 buy 0.01 EURUSD at 1.13134]'. Portanto, neste caso, a função irá então excluir/cancelar a ordem sell-stop restante com a mensagem de diário 'order canceled [#3 sell stop 0.01 EURUSD at 1.12911]' conforme indicado na imagem abaixo. 

Ordem Cancelada devido ao FundamentalMode

//+------------------------------------------------------------------+
//|This function will delete a pending order if the previous opposing|
//|pending order is opened into a position, this function is used    |
//|when trading with StopOrdersType(STOP ORDERS)                     |
//+------------------------------------------------------------------+
void CTradeManagement::FundamentalMode(string COMMENT_COMMON)
  {
//--- Iterate through all open positions if Orders are more than zero
   for(int P=0; P<PositionsTotal()&&OrdersTotal()>0; P++)
     {
      //--- Check if Position ticket is above zero
      if(PositionGetTicket(P)>0)
        {
         //--- Check if the Position's Symbol,Magic,Type,Comment is correct
         if(PositionGetString(POSITION_SYMBOL)==CSymbol.GetSymbolName()&&
            StringFind(PositionGetString(POSITION_COMMENT),COMMENT_COMMON)>=0)
           {
            //--- Iterate through all open orders
            for(int O=0; O<OrdersTotal(); O++)
              {
               //--- Check if Order ticket is above zero
               if(OrderGetTicket(O)>0)
                 {
                  //--- Check if the Order's Symbol,Magic,Comment is correct
                  if(OrderGetString(ORDER_SYMBOL)==CSymbol.GetSymbolName()
                     &&OrderGetInteger(ORDER_MAGIC)==PositionGetInteger(POSITION_MAGIC)
                     &&StringFind(OrderGetString(ORDER_COMMENT),COMMENT_COMMON)>=0
                     &&OrderGetString(ORDER_COMMENT)==PositionGetString(POSITION_COMMENT))
                    {
                     //--- Identify Position type
                     switch(int(PositionGetInteger(POSITION_TYPE)))
                       {
                        /* In the case that the Position type is a buy and if the corresponding order type is
                        a sell-stop then delete this order*/
                        case  POSITION_TYPE_BUY:
                           if(OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_SELL_STOP)
                             {
                              //--- Delete the sell-stop order
                              Trade.OrderDelete(OrderGetTicket(O));
                             }
                           break;
                        /* In the case that the Position type is a sell and if the corresponding order type is
                        a buy-stop then delete this order*/
                        case POSITION_TYPE_SELL:
                           if(OrderGetInteger(ORDER_TYPE)==ORDER_TYPE_BUY_STOP)
                             {
                              //--- Delete the sell-stop order
                              Trade.OrderDelete(OrderGetTicket(O));
                             }
                           break;
                        default:
                           break;
                       }
                    }
                 }
              }
           }
        }
     }
  }

Propósito da Função:

A função garante que, quando uma ordem pendente (ex.: buy-stop ou sell-stop) for aberta como operação, a ordem oposta (ex.: sell-stop ou buy-stop) seja excluída. Isso evita a execução de ambas as ordens, o que poderia levar à abertura de posições indesejadas.

void CTradeManagement::FundamentalMode(string COMMENT_COMMON)

  • FundamentalMode: esta função tenta remover uma ordem stop pendente se a posição oposta tiver sido aberta.
  • COMMENT_COMMON: Um parâmetro string usado para identificar operações/ordens com base no comentário associado a elas.

Loop Sobre Posições Abertas:

for(int P = 0; P < PositionsTotal() && OrdersTotal() > 0; P++)

  • PositionsTotal(): Retorna o número total de posições abertas.
  • OrdersTotal(): Retorna o número total de ordens pendentes.
  • Este for loop percorre todas as posições abertas e garante que haja ordens pendentes para processar.

Validação de Ticket da Posição:

if(PositionGetTicket(P) > 0)

  • PositionGetTicket(P): Recupera o número do ticket da posição no índice P.
  • Garante que o ticket da posição seja válido (isto é, maior que zero).

Verificação de Propriedades da Posição:

if(PositionGetString(POSITION_SYMBOL) == CSymbol.GetSymbolName() &&
   StringFind(PositionGetString(POSITION_COMMENT), COMMENT_COMMON) >= 0)

  • PositionGetString(POSITION_SYMBOL): Recupera o símbolo da posição aberta.
  • CSymbol.GetSymbolName(): Recupera o nome do símbolo definido no construtor.
  • PositionGetString(POSITION_COMMENT): Recupera o comentário associado à posição.
  • StringFind(PositionGetString(POSITION_COMMENT), COMMENT_COMMON): Verifica se a substring COMMENT_COMMON está presente no comentário da posição. Isso garante que a posição pertença à estratégia/expert.

Loop Sobre Ordens Abertas:

for(int O = 0; O < OrdersTotal(); O++)

  • Percorre todas as ordens pendentes abertas.

Validação de Ticket da Ordem:

if(OrderGetTicket(O) > 0)

  • OrderGetTicket(O): Recupera o número do ticket da ordem no índice O.
  • Garante que o ticket da ordem seja válido.

Verificação de Propriedades da Ordem:

if(OrderGetString(ORDER_SYMBOL) == CSymbol.GetSymbolName() &&
   OrderGetInteger(ORDER_MAGIC) == PositionGetInteger(POSITION_MAGIC) &&
   StringFind(OrderGetString(ORDER_COMMENT), COMMENT_COMMON) >= 0 &&
   OrderGetString(ORDER_COMMENT) == PositionGetString(POSITION_COMMENT))

  • OrderGetString(ORDER_SYMBOL): Recupera o símbolo associado à ordem.
  • OrderGetInteger(ORDER_MAGIC): Recupera o número mágico da ordem (que ajuda a identificar ordens para cada evento).
  • PositionGetInteger(POSITION_MAGIC): Recupera o número mágico da posição para compará-lo com o da ordem.
  • OrderGetString(ORDER_COMMENT): Recupera o comentário da ordem.
  • Garante que o símbolo, número mágico e comentário da ordem correspondam às propriedades da posição. Isso garante que a ordem pendente esteja relacionada à posição aberta.

Identificação e Exclusão de Ordens Opostas:

switch(int(PositionGetInteger(POSITION_TYPE)))
{
   case POSITION_TYPE_BUY:
      if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_STOP)
      {
         Trade.OrderDelete(OrderGetTicket(O));
      }
      break;
   case POSITION_TYPE_SELL:
      if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP)
      {
         Trade.OrderDelete(OrderGetTicket(O));
      }
      break;
   default:
      break;
}

  • PositionGetInteger(POSITION_TYPE): Recupera o tipo da posição aberta (POSITION_TYPE_BUY ou POSITION_TYPE_SELL).
  • OrderGetInteger(ORDER_TYPE): Recupera o tipo da ordem pendente (ORDER_TYPE_BUY_STOP ou ORDER_TYPE_SELL_STOP).

Switch Case:

  • Se a posição for de compra (POSITION_TYPE_BUY), a função verifica se existe uma ordem pendente de venda (ORDER_TYPE_SELL_STOP). Se encontrada, essa ordem sell-stop é excluída, pois não é mais necessária.
  • De forma semelhante, se a posição for de venda (POSITION_TYPE_SELL), a função verifica se existe uma ordem pendente de compra (ORDER_TYPE_BUY_STOP). Se encontrada, essa ordem buy-stop é excluída.

Trade.OrderDelete(OrderGetTicket(O)): este método exclui a ordem pendente usando seu número de ticket, removendo efetivamente a ordem oposta desnecessária após a abertura da posição correspondente.

A função SlippageReduction foi projetada para garantir que os níveis de stop-loss (SL) e take-profit (TP) de uma posição aberta estejam corretamente definidos conforme os valores esperados. Se o slippage (a diferença entre o preço esperado e o preço real da execução da ordem) tiver causado desvio nos valores de SL e TP quando a ordem foi executada, a função ajusta a posição para refletir os valores esperados.

Exemplo: um trader deseja abrir ordens buy-stop e sell-stop para negociar NFP. O trader define um desvio de preço para ambas as ordens de 100 pips em relação ao preço atual, além de uma razão risco/retorno de 1:6, exigindo um stop-loss de 100 pips e um take-profit de 600 pips. Neste caso, conforme a imagem abaixo, o buy-stop é colocado em 1.13118, o SL em 1.13018 e o TP em 1.13718, mantendo o ROI de 1:6. Devido à volatilidade do evento NFP, a ordem de compra foi executada em um preço desfavorável de 1.13134, indicado pela mensagem de diário 'order performed buy 0.01 at 1.13134 [#2 buy stop 0.01 EURUSD at 1.13118]'.

Slippage sofrido pela ordem buy-stop:

O slippage para o preço de abertura será calculado como: [Preço real - Preço esperado]/Point

Preço esperado: 1.13118 | Preço real: 1.13134 | Slippage: (1.13134 - 1.13118)/0.00001 -> 16 pips (diferença de preço)

Portanto, para manter o ROI e o stop-loss, tanto os valores de SL quanto de TP serão ajustados em 16 pips.

Slippage Reduction em ação

//+------------------------------------------------------------------+
//|Function will attempt to re-adjust stop-losses or take-profit     |
//|values that have been changed due to slippage on an order when    |
//|opening.                                                          |
//+------------------------------------------------------------------+
void CTradeManagement::SlippageReduction(int SL,int TP,string COMMENT_COMMON)
  {
//--- Iterate through all open positions
   for(int i=0; i<PositionsTotal(); i++)
     {
      ulong ticket = PositionGetTicket(i);
      //--- Check if Position ticket is above zero
      if(ticket>0)
        {
         //--- Check if the Position's Symbol,Comment is correct
         if(PositionGetString(POSITION_SYMBOL)==CSymbol.GetSymbolName()
            &&StringFind(PositionGetString(POSITION_COMMENT),COMMENT_COMMON)>=0)
           {
            //--- Identify Position type
            switch(int(PositionGetInteger(POSITION_TYPE)))
              {
               case  POSITION_TYPE_BUY:
                  //--- set expect buy trade properties
                  SetBuyTrade(SL,TP,PositionGetDouble(POSITION_PRICE_OPEN));
                  //--- assign sl price
                  mySL = PositionGetDouble(POSITION_SL);
                  //--- assign tp price
                  myTP = PositionGetDouble(POSITION_TP);
                  //--- Normalize sl price
                  CSymbol.NormalizePrice(mySL);
                  mySL = double(DoubleToString(mySL,CSymbol.Digits()));
                  //--- Normalize tp price
                  CSymbol.NormalizePrice(myTP);
                  myTP = double(DoubleToString(myTP,CSymbol.Digits()));
                  //--- check if expected properties match actual trade properties
                  if((myBuyTrade.Get().Stop!=mySL||
                      myBuyTrade.Get().Take!=myTP)
                     &&Valid_Trade(POSITION_TYPE_BUY,myBuyTrade.Get().Open,
                                   myBuyTrade.Get().Stop,myBuyTrade.Get().Take))
                    {
                     //--- Modify position to respect expected properties
                     Trade.PositionModify(ticket,myBuyTrade.Get().Stop,myBuyTrade.Get().Take);
                    }
                  break;
               case POSITION_TYPE_SELL:
                  //--- set expect sell trade properties
                  SetSellTrade(SL,TP,PositionGetDouble(POSITION_PRICE_OPEN));
                  //--- assign sl price
                  mySL = PositionGetDouble(POSITION_SL);
                  //--- assign tp price
                  myTP = PositionGetDouble(POSITION_TP);
                  //--- Normalize sl price
                  CSymbol.NormalizePrice(mySL);
                  mySL = double(DoubleToString(mySL,CSymbol.Digits()));
                  //--- Normalize tp price
                  CSymbol.NormalizePrice(myTP);
                  myTP = double(DoubleToString(myTP,CSymbol.Digits()));
                  //--- check if expected properties match actual trade properties
                  if((mySellTrade.Get().Stop!=mySL||
                      mySellTrade.Get().Take!=myTP)
                     &&Valid_Trade(POSITION_TYPE_SELL,mySellTrade.Get().Open,
                                   mySellTrade.Get().Stop,mySellTrade.Get().Take))
                    {
                     //--- Modify position to respect expected properties
                     Trade.PositionModify(ticket,mySellTrade.Get().Stop,mySellTrade.Get().Take);
                    }
                  break;
               default:
                  break;
              }
           }
        }
     }
  }

Propósito da Função:

O objetivo desta função é:

  1. Verificar cada posição em aberto.
  2. Confirmar se os valores de stop-loss e take-profit da posição correspondem aos valores esperados.
  3. Se não corresponderem devido a slippage, a posição é modificada para refletir os valores corretos de SL e TP.

void CTradeManagement::SlippageReduction(int SL, int TP, string COMMENT_COMMON)

  • SlippageReduction: o nome da função reflete seu propósito — ajustar SL e TP caso tenham sido impactados por slippage durante a execução da ordem.

Parâmetros:

  • SL: Valor esperado de stop-loss.
  • TP: Valor esperado de take-profit.
  • COMMENT_COMMON: Uma string usada para filtrar e identificar as operações que pertencem a este Expert.

Percorrer Posições Abertas:

for (int i = 0; i < PositionsTotal(); i++)
{
    ulong ticket = PositionGetTicket(i);

  • PositionsTotal(): Esta função retorna o número de posições abertas.
  • PositionGetTicket(i): Recupera o número do ticket da posição no índice i. Um ticket identifica de forma única uma posição aberta.

Validação de Ticket da Posição:

if (ticket > 0)

  • Garante que a posição tenha um ticket válido antes de prosseguir para as próximas etapas.

Verificação de Propriedades da Posição:

if (PositionGetString(POSITION_SYMBOL) == CSymbol.GetSymbolName() &&
    StringFind(PositionGetString(POSITION_COMMENT), COMMENT_COMMON) >= 0)

  • PositionGetString(POSITION_SYMBOL): Recupera o símbolo associado à posição aberta.
  • CSymbol.GetSymbolName(): Obtém o nome do símbolo para a estratégia de negociação (por exemplo, “EURUSD”).
  • PositionGetString(POSITION_COMMENT): Recupera o comentário anexado à posição aberta.
  • StringFind(): Verifica se COMMENT_COMMON faz parte do comentário da posição, garantindo que a função processe apenas posições relacionadas à estratégia atual.

Identificar e Tratar Tipos de Posição (Compra ou Venda):

Caso 1: Posição de Compra (Buy)

case POSITION_TYPE_BUY:

  • A função trata posições do tipo BUY.

Definir Propriedades Esperadas da Operação de Compra:

SetBuyTrade(SL, TP, PositionGetDouble(POSITION_PRICE_OPEN));

  • SetBuyTrade(SL, TP, PositionGetDouble(POSITION_PRICE_OPEN)): define o stop-loss, take-profit e preço de abertura esperados para a operação de compra. A função SetBuyTrade atribui esses valores esperados ao objeto myBuyTrade.

Atribuir Valores Reais de SL e TP:

mySL = PositionGetDouble(POSITION_SL);
myTP = PositionGetDouble(POSITION_TP);

  • PositionGetDouble(POSITION_SL): Recupera o valor real de stop-loss da posição aberta.
  • PositionGetDouble(POSITION_TP): Recupera o valor real de take-profit da posição aberta.

Normalizar Valores de SL e TP:

CSymbol.NormalizePrice(mySL);
mySL = double(DoubleToString(mySL, CSymbol.Digits()));

CSymbol.NormalizePrice(myTP);
myTP = double(DoubleToString(myTP, CSymbol.Digits()));

  • NormalizePrice(mySL): normaliza o valor do stop-loss para o número correto de casas decimais (com base nas propriedades do símbolo; por exemplo, pares de moedas podem ter 4 ou 5 casas).
  • DoubleToString(mySL, CSymbol.Digits()): converte o SL normalizado em string e depois de volta para double para garantir precisão.
  • O mesmo processo é aplicado ao valor de take-profit (myTP).

Comparar SL/TP Esperados e Reais:

if ((myBuyTrade.Get().Stop != mySL || myBuyTrade.Get().Take != myTP) &&
    Valid_Trade(POSITION_TYPE_BUY, myBuyTrade.Get().Open, myBuyTrade.Get().Stop, myBuyTrade.Get().Take))
{
    Trade.PositionModify(ticket, myBuyTrade.Get().Stop, myBuyTrade.Get().Take);
}

  • myBuyTrade.Get().Stop: recupera o valor esperado de stop-loss.
  • mySL: o valor real de stop-loss recuperado da posição.
  • Se os valores reais de SL e TP não corresponderem aos esperados, a função chama Trade.PositionModify para atualizar a posição e definir os valores corretos de stop-loss e take-profit.
  • Valid_Trade(): verifica se os parâmetros da operação (preço, SL, TP) são válidos para modificação antes de tentar modificar a posição.

Modificar a Posição:

Trade.PositionModify(ticket, myBuyTrade.Get().Stop, myBuyTrade.Get().Take);

  • Esta função modifica a posição associada ao ticket para refletir os valores corretos de stop-loss e take-profit com base nos valores esperados.

Caso 2: Posição de Venda (Sell)

  • O processo é semelhante ao de posições de compra.

A função Valid_Trade verifica se os parâmetros de uma operação (como preço, níveis de stop-loss e take-profit) são válidos com base no tipo de operação (compra ou venda) e nas regras que regem os níveis de SL e TP em relação às propriedades do símbolo. A função retorna true se a operação for válida e false caso não seja.

//+------------------------------------------------------------------+
//|Check if a trade is valid                                         |
//+------------------------------------------------------------------+
bool CTradeManagement::Valid_Trade(ENUM_POSITION_TYPE Type,double Price,double SL,double TP)
  {
//--- Identify Position type
   switch(Type)
     {
      case  POSITION_TYPE_BUY:
         if((Price<TP||TP==0)&&(Price>SL||SL==0)&&
            ((int((Price-SL)/CSymbol.Point())>=CSymbol.StopLevel())
             ||(SL==0))&&
            ((int((TP-Price)/CSymbol.Point())>=CSymbol.StopLevel())
             ||(TP==0))&&
            Price>0
           )
           {
            //--- Trade properties are valid.
            return true;
           }
         break;
      case POSITION_TYPE_SELL:
         if((Price>TP||TP==0)&&(Price<SL||SL==0)&&
            ((int((Price-TP)/CSymbol.Point())>=CSymbol.StopLevel())
             ||(TP==0))&&
            ((int((SL-Price)/CSymbol.Point())>=CSymbol.StopLevel())
             ||(SL==0))&&
            Price>0
           )
           {
            //--- Trade properties are valid.
            return true;
           }
         break;
      default://Unknown
         return false;
         break;
     }
//--- Trade properties are not valid.
   Print("Something went wrong, SL/TP/Open-Price is incorrect!");
   return false;
  }

Propósito da Função:

O propósito desta função é:

  1. Validar os parâmetros da operação (preço, SL e TP) para posições de compra ou venda.
  2. Garantir que os níveis de stop-loss e take-profit estejam corretamente definidos em relação ao preço de abertura e que atendam aos requisitos de stop level do símbolo.

Parâmetros:

bool CTradeManagement::Valid_Trade(ENUM_POSITION_TYPE Type, double Price, double SL, double TP)

  • Type: O tipo de posição, POSITION_TYPE_BUY (compra) ou POSITION_TYPE_SELL (venda).
  • Price: O preço de abertura da operação.
  • SL: O nível de stop-loss da operação.
  • TP: O nível de take-profit da operação.

Instrução switch:

A função usa um switch para tratar diferentes tipos de posição (compra ou venda) e aplica lógicas de validação distintas para cada caso.

Caso 1: Posição de Compra (Buy)

case POSITION_TYPE_BUY:

A lógica para uma posição de compra verifica as seguintes condições:

Validação do Take-Profit (TP):

if ((Price < TP || TP == 0)

  • O nível de take-profit deve ser maior que o preço de abertura (Price < TP) ou pode ser zero (sem take-profit).

Validação do Stop-Loss (SL):

(Price > SL || SL == 0)

  • O nível de stop-loss deve ser menor que o preço de abertura (Price > SL) ou pode ser zero (sem stop-loss).

Validação do Stop Level do Símbolo:

  • O stop level do símbolo define a distância mínima entre o preço e o stop-loss/take-profit.
  • Os níveis de stop-loss e take-profit devem estar a uma distância mínima (maior ou igual ao stop level) do preço de abertura.

Validação da Distância do Stop-Loss:

((int((Price - SL) / CSymbol.Point()) >= CSymbol.StopLevel()) || SL == 0)

  • A diferença entre o preço e o stop-loss deve ser pelo menos o stop level do símbolo (em points). Se o stop-loss for zero, essa condição é ignorada.

Validação da Distância do Take-Profit:

((int((TP - Price) / CSymbol.Point()) >= CSymbol.StopLevel()) || TP == 0)

  • A diferença entre o take-profit e o preço também deve atender ao requisito de stop level.

Validação Final:

&& Price > 0

  • O preço deve ser maior que zero.

Se todas essas condições forem satisfeitas, a operação é considerada válida e a função retorna true.

Caso 2: Posição de Venda (Sell)

Para uma posição de venda, a lógica é semelhante, porém invertida.

Caso padrão:

default:
    return false;

Se o tipo de posição não for nem POSITION_TYPE_BUY nem POSITION_TYPE_SELL, a função retorna false, indicando que a operação não é válida.

Propriedades da Operação Inválidas:

Se algum dos testes de validação falhar, a função registra uma mensagem de erro e retorna false.

Print("Something went wrong, SL/TP/Open-Price is incorrect!");
return false;

Esta mensagem indica que o stop-loss, o take-profit ou o preço de abertura estão incorretos.

O código abaixo define um método, Valid_Order, que verifica se uma ordem stop (BUY STOP ou SELL STOP) é válida, checando as condições de stop-loss (SL), take-profit (TP), preço e desvio da ordem (deviation). A função retorna true se a ordem for válida e false caso contrário.

//+------------------------------------------------------------------+
//|Check if stop order is valid                                      |
//+------------------------------------------------------------------+
bool CTradeManagement::Valid_Order(ENUM_ORDER_TYPE Type,double Price,double SL,double TP)
  {
//--- Identify Order type
   switch(Type)
     {
      case  ORDER_TYPE_BUY_STOP:
         if((Price<TP||TP==0)&&(Price>SL||SL==0)&&(Price>CSymbol.Ask())&&
            ((int((Price-SL)/CSymbol.Point())>=CSymbol.StopLevel())
             ||(SL==0))&&
            ((int((TP-Price)/CSymbol.Point())>=CSymbol.StopLevel())
             ||(TP==0))&&
            myDeviation>=uint(CSymbol.StopLevel())
           )
           {
            //--- Order properties are valid.
            return true;
           }
         break;
      case ORDER_TYPE_SELL_STOP:
         if((Price>TP||TP==0)&&(Price<SL||SL==0)&&(Price<CSymbol.Bid())&&
            ((int((Price-TP)/CSymbol.Point())>=CSymbol.StopLevel())
             ||(TP==0))&&
            ((int((SL-Price)/CSymbol.Point())>=CSymbol.StopLevel())
             ||(SL==0))&&
            myDeviation>=uint(CSymbol.StopLevel())
           )
           {
            //--- Order properties are valid.
            return true;
           }
         break;
      default://Other
         return false;
         break;
     }
//--- Order properties are not valid.
   Print("Something went wrong, SL/TP/Deviation/Open-Price is incorrect!");
   return false;
  }

Visão geral:

A função realiza a validação com base no tipo de ordem stop:

  1. BUY STOP: uma ordem de compra stop é colocada acima do preço de mercado atual (preço ask) e é acionada quando o preço de mercado atinge ou excede esse nível.
  2. SELL STOP: uma ordem de venda stop é colocada abaixo do preço de mercado atual (preço bid) e é acionada quando o preço de mercado cai até ou abaixo desse nível.

Parâmetros:

bool CTradeManagement::Valid_Order(ENUM_ORDER_TYPE Type, double Price, double SL, double TP)

  • Tipo: O tipo de ordem stop (ORDER_TYPE_BUY_STOP ou ORDER_TYPE_SELL_STOP).
  • Price: O preço no qual a ordem stop é definida.
  • SL: O preço de stop-loss associado à ordem stop.
  • TP: O preço de take-profit associado à ordem stop.

Instrução switch:

A instrução switch trata tipos de ordem diferentes e aplica regras de validação específicas para cada um.Caso 1: Ordem BUY STOP

Caso 1: Ordem BUY STOP

case ORDER_TYPE_BUY_STOP:

Para uma ordem BUY STOP, as seguintes condições devem ser satisfeitas:

Validação do Take-Profit (TP):

(Price < TP || TP == 0)

O preço de take-profit deve ser maior que o preço da ordem (Price < TP), ou pode ser zero (sem take-profit).

Validação do Stop-Loss (SL):

(Price > SL || SL == 0)

O preço de stop-loss deve ser menor que o preço da ordem (Price > SL), ou pode ser zero (sem stop-loss).

Preço Acima do Ask:

(Price > CSymbol.Ask())

O preço da ordem deve ser maior que o ask atual, condição essencial para BUY STOP.

Validação do Stop Level do Símbolo — Distância do Stop-Loss:

((int((Price - SL) / CSymbol.Point()) >= CSymbol.StopLevel()) || SL == 0)

A diferença entre o preço da ordem e o stop-loss deve atender ou exceder o stop level do símbolo, que é a distância mínima permitida (em points) entre o preço da ordem e o nível de stop-loss. Se o stop-loss for zero, esta condição é ignorada.

Validação da Distância do Take-Profit:

((int((TP - Price) / CSymbol.Point()) >= CSymbol.StopLevel()) || TP == 0)

A diferença entre o take-profit e o preço da ordem também deve atender ao requisito de stop level (ou o take-profit pode ser zero).

Validação do Desvio de Preço (Deviation):

myDeviation >= uint(CSymbol.StopLevel())

O desvio de preço (tolerância a slippage) deve ser maior ou igual ao stop level do símbolo. O deviation permite que a ordem seja executada mesmo que o preço de mercado avance levemente além do nível definido.

Se todas essas condições forem satisfeitas, a ordem BUY STOP é considerada válida e a função retorna true.

Caso 2: Ordem SELL STOP

Para uma ordem SELL STOP, a lógica de validação é a inversa da BUY STOP.

Caso padrão:

default:
    return false;

Se o tipo de ordem não for nem ORDER_TYPE_BUY_STOP nem ORDER_TYPE_SELL_STOP, a função retorna false, indicando que a ordem não é válida.

Tratamento de Erros:

Se as condições falharem e a função não puder validar a ordem, ela registra uma mensagem de erro:

Print("Something went wrong, SL/TP/Deviation/Open-Price is incorrect!");

Esta mensagem informa que há algo errado com o stop-loss, take-profit, desvio de preço ou preço da ordem, tornando-a inválida.

O código abaixo define a função SetBuyStop, responsável por configurar as propriedades de uma ordem buy-stop. Ela calcula os preços de stop-loss (SL) e take-profit (TP) com base nas entradas fornecidas e os atribui à ordem. A função executa as etapas:

  1. Calcula o preço de abertura da ordem buy-stop.
  2. Calcula e define os preços de stop-loss e take-profit relativos ao preço de abertura.
  3. Normaliza os preços para garantir alinhamento com a precisão do símbolo (número de casas decimais).

//+------------------------------------------------------------------+
//|Will set buy-stop order properties                                |
//+------------------------------------------------------------------+
void CTradeManagement::SetBuyStop(int SL,int TP)
  {
//-- Get Open-price
   myOpenPrice=CSymbol.Ask()+myDeviation*CSymbol.Point();
   CSymbol.NormalizePrice(myOpenPrice);
   NormalizeDouble(myOpenPrice,CSymbol.Digits());
//--- Get SL value
   mySL=SL*CSymbol.Point();
   mySL=myOpenPrice-mySL;
//--- Normalize the SL Price
   CSymbol.NormalizePrice(mySL);
   NormalizeDouble(mySL,CSymbol.Digits());
//--- Get TP value
   myTP=TP*CSymbol.Point();
   myTP+=myOpenPrice;
//--- Normalize the TP Price
   CSymbol.NormalizePrice(myTP);
   NormalizeDouble(myTP,CSymbol.Digits());
//--- Set BuyStop properties
   myBuyStop.Set(myOpenPrice,myTP,mySL);
  }

Parâmetros:

  • SL: O valor de stop-loss em points.
  • TP: O valor de take-profit em points.

void CTradeManagement::SetBuyStop(int SL, int TP)

Tanto SL quanto TP são valores inteiros que representam a quantidade de points (incrementos de preço) entre o preço de abertura e o nível de stop-loss ou take-profit.

Etapa 1: Calculando o Preço de Abertura da Ordem Buy-Stop

myOpenPrice = CSymbol.Ask() + myDeviation * CSymbol.Point();

  • CSymbol.Ask() recupera o preço ask atual do símbolo (par de moedas ou ativo).
  • myDeviation * CSymbol.Point() adiciona um desvio (margem de preço), em points, para garantir que o preço de abertura fique acima do ask atual. CSymbol.Point() retorna o tamanho de um point (menor variação de preço) para o símbolo.

Normalização:

CSymbol.NormalizePrice(myOpenPrice);
NormalizeDouble(myOpenPrice, CSymbol.Digits());

  • CSymbol.NormalizePrice(myOpenPrice) ajusta o preço para alinhá-lo à precisão do símbolo (ou seja, para um formato de preço válido).
  • NormalizeDouble(myOpenPrice, CSymbol.Digits()) garante que o preço seja arredondado para o número correto de casas decimais definido pela precisão do símbolo (CSymbol.Digits()).

Etapa 2: Calculando e Normalizando o Preço de Stop-Loss (SL)

mySL = SL * CSymbol.Point();
mySL = myOpenPrice - mySL;

  • SL * CSymbol.Point() converte o valor inteiro de stop-loss (em points) em uma diferença de preço.
  • myOpenPrice - mySL calcula o preço de stop-loss subtraindo o valor de stop-loss (em points) do preço de abertura. Isso porque um stop-loss para uma ordem buy-stop é colocado abaixo do preço de abertura.

Normalização:

CSymbol.NormalizePrice(mySL);
NormalizeDouble(mySL, CSymbol.Digits());

  • O preço de stop-loss é normalizado e arredondado para a precisão correta, conforme explicado acima.

Etapa 3: Calculando e Normalizando o Preço de Take-Profit (TP)

myTP = TP * CSymbol.Point();
myTP += myOpenPrice;

  • TP * CSymbol.Point() converte o valor inteiro de take-profit (em points) em uma diferença de preço.
  • myTP += myOpenPrice adiciona esse valor ao preço de abertura porque o take-profit para uma ordem buy-stop é colocado acima do preço de abertura.

Normalização:

CSymbol.NormalizePrice(myTP);
NormalizeDouble(myTP, CSymbol.Digits());

  • O preço de take-profit é normalizado e arredondado, de forma semelhante aos preços de stop-loss e de abertura.

Etapa 4: Atribuindo os Valores Calculados à Ordem Buy-Stop

myBuyStop.Set(myOpenPrice, myTP, mySL);

  • myBuyStop.Set(myOpenPrice, myTP, mySL) atribui o preço de abertura, o take-profit e o stop-loss calculados ao objeto de ordem myBuyStop.
  • O objeto myBuyStop passará então a conter as propriedades necessárias para enviar a ordem buy-stop ao mercado.

A função SetBuyTrade define as propriedades para uma posição de compra (buy). Ela calcula e atribui o preço de abertura correto, o stop-loss (SL) e o take-profit (TP) da operação. Essa função é usada para configurar os parâmetros de uma posição de compra (não uma ordem pendente como buy-stop). Uma posição de compra é aberta ao preço de mercado atual, com níveis de stop-loss e take-profit especificados em relação ao preço de abertura.

Parâmetros:

  • SL: O valor de stop-loss em points (incrementos de preço).
  • TP: O valor de take-profit em points.
  • OP: O preço de abertura da operação (o preço no qual a posição é aberta).

Etapa 1: Definindo o Preço de Abertura

myOpenPrice = OP;
CSymbol.NormalizePrice(myOpenPrice);
myOpenPrice = double(DoubleToString(myOpenPrice, CSymbol.Digits()));

  • myOpenPrice = OP: a função recebe o preço de abertura fornecido (OP) e o atribui a myOpenPrice.
  • CSymbol.NormalizePrice(myOpenPrice): normaliza o preço de abertura de acordo com a precisão do símbolo, garantindo o número correto de casas decimais.
  • myOpenPrice = double(DoubleToString(myOpenPrice, CSymbol.Digits())): o preço é convertido para string e de volta para double com o número correto de casas decimais (precisão) do símbolo. Isso garante consistência no tratamento de valores de preço, evitando problemas de precisão de ponto flutuante.

Etapa 2: Calculando e Normalizando o Preço de Stop-Loss (SL)

mySL = SL * CSymbol.Point();
mySL = myOpenPrice - mySL;

  • SL * CSymbol.Point(): Converte o valor de stop-loss de points para uma diferença real de preço. CSymbol.Point() retorna o tamanho de um point (o menor incremento de preço possível para o símbolo).
  • myOpenPrice - mySL: o preço de stop-loss é definido subtraindo o valor calculado de stop-loss do preço de abertura. Em uma posição de compra, o stop-loss é colocado abaixo do preço de abertura para proteger a operação contra perdas excessivas.

Normalização:

CSymbol.NormalizePrice(mySL);
mySL = double(DoubleToString(mySL, CSymbol.Digits()));

  • O preço de stop-loss é normalizado para garantir a precisão correta e, em seguida, arredondado para o número apropriado de casas decimais.

Etapa 3: Calculando e Normalizando o Preço de Take-Profit (TP)

myTP = TP * CSymbol.Point();
myTP += myOpenPrice;

  • TP * CSymbol.Point(): converte o valor de take-profit de points para uma diferença de preço.
  • myTP += myOpenPrice: o preço de take-profit é somado ao preço de abertura, pois, para uma posição de compra, o take-profit fica acima do preço de abertura.

Normalização:

CSymbol.NormalizePrice(myTP);
myTP = double(DoubleToString(myTP, CSymbol.Digits()));

  • O preço de take-profit é normalizado e arredondado para corresponder à precisão do símbolo.

Etapa 4: Atribuir os Valores Calculados à Posição de Compra

myBuyTrade.Set(myOpenPrice, myTP, mySL);

  • myBuyTrade.Set(myOpenPrice, myTP, mySL): o preço de abertura, o stop-loss e o take-profit calculados são atribuídos ao objeto myBuyTrade. Esse objeto agora mantém todas as propriedades relevantes da posição de compra que será aberta ou modificada.

A função OpenBuyStop tenta abrir uma ordem buy-stop com stop-loss (SL), take-profit (TP), magic number e comentário opcional especificados.

Parâmetros:

  • SL: valor de stop-loss em points.
  • TP: valor de take-profit em points.
  • Magic: Magic number exclusivo para identificar a ordem, normalmente usado por experts advisors.
  • COMMENT: (Opcional) Um comentário em string para anexar à ordem para identificação.

//+------------------------------------------------------------------+
//|Will attempt to open a buy-stop order                             |
//+------------------------------------------------------------------+
bool CTradeManagement::OpenBuyStop(int SL,int TP,ulong Magic,string COMMENT=NULL)
  {
   SetBuyStop(SL,TP);
//--- Set the order type for Risk management calculation
   SetOrderType(ORDER_TYPE_BUY);
//--- Set open price for Risk management calculation
   OpenPrice = myBuyStop.Get().Open;
//--- Set close price for Risk management calculation
   ClosePrice = myBuyStop.Get().Stop;
//--- Set Trade magic number
   Trade.SetExpertMagicNumber(Magic);
//--- Check if there are any open trades or opened deals or canceled deals already
   if(!OpenOrder(ORDER_TYPE_BUY_STOP,Magic,COMMENT)&&!OpenedDeal(DEAL_TYPE_BUY,Magic,COMMENT)
//--- Check if the buy-stop properties are valid
      &&Valid_Order(ORDER_TYPE_BUY_STOP,myBuyStop.Get().Open,myBuyStop.Get().Stop,myBuyStop.Get().Take))
     {
      //--- Iterate through the Lot-sizes if they're more than max-lot
      for(double i=Volume();i>=CSymbol.LotsMin()&&
          /* Check if current number of orders +1 more orders is less than
                 account orders limit.*/
          (PositionsTotal()+Account.numOrders()+1)<Account.LimitOrders()
          ;i-=CSymbol.LotsMax())
        {
         //--- normalize Lot-size
         NormalizeLotsize(i);
         /* Open buy-stop order with a Lot-size not more than max-lot and set order expiration
         to the Symbol's session end time for the current day.
         */
         if(!Trade.BuyStop((i>CSymbol.LotsMax())?CSymbol.LotsMax():i,myBuyStop.Get().Open,
                           CSymbol.GetSymbolName(),myBuyStop.Get().Stop,myBuyStop.Get().Take,
                           ORDER_TIME_SPECIFIED,CTS.SessionEnd(),COMMENT))
           {
            //--- Order failed to open
            return false;
           }
        }
     }
   else
     {
      //--- Order failed
      return false;
     }
//--- Return trade result.
   return true;
  }

Etapa 1: Definir Propriedades do Buy-Stop

SetBuyStop(SL, TP);

  • Esta linha chama o método SetBuyStop (explicado anteriormente) para calcular e definir o preço de abertura, stop-loss e take-profit da ordem buy-stop.
  • O resultado é armazenado em myBuyStop, que guarda as propriedades-chave da ordem (abertura, SL e TP).

Etapa 2: Definir o Tipo de Ordem para Gestão de Risco

SetOrderType(ORDER_TYPE_BUY);

  • Isso define internamente o tipo de ordem como ORDER_TYPE_BUY. Embora seja uma ordem buy-stop, ela é, fundamentalmente, uma ordem de compra; essa informação é usada para cálculos de risco como stop-loss, take-profit e position sizing.

Etapa 3: Definir Preços de Abertura e Fechamento para Gestão de Risco

OpenPrice = myBuyStop.Get().Open;
ClosePrice = myBuyStop.Get().Stop;

  • OpenPrice: recebe o preço de abertura calculado da buy-stop (myBuyStop.Get().Open).
  • ClosePrice: recebe o preço de stop-loss calculado da buy-stop (myBuyStop.Get().Stop).

Etapa 4: Defina o número mágico

Trade.SetExpertMagicNumber(Magic);

  • Define o magic number da ordem usando Trade.SetExpertMagicNumber. O magic number identifica a ordem de forma única, útil para gerenciar operações abertas por um expert advisor.

Etapa 5: Verificar Ordens ou Negócios Abertos

if (!OpenOrder(ORDER_TYPE_BUY_STOP, Magic, COMMENT) && !OpenedDeal(DEAL_TYPE_BUY, Magic, COMMENT)

  • OpenOrder: verifica se já existe uma ordem buy-stop pendente com o mesmo magic number e comentário. Se existir, a função não abre uma nova ordem.
  • OpenedDeal: verifica se já existe uma posição de compra aberta usando o mesmo magic number e comentário. Se existir, a função evita abrir uma nova.

Etapa 6: Validar Propriedades da Ordem Buy-Stop

&& Valid_Order(ORDER_TYPE_BUY_STOP, myBuyStop.Get().Open, myBuyStop.Get().Stop, myBuyStop.Get().Take))

  • Isso verifica se as propriedades calculadas da buy-stop são válidas usando Valid_Order (explicado antes). O método checa se abertura, SL e TP estão corretos e em conformidade com as regras do símbolo (ex.: stop level mínimo, valor de point, etc.).

Etapa 7: Iterar pelos Tamanhos de Lote

for (double i = Volume(); i >= CSymbol.LotsMin() && (PositionsTotal() + Account.numOrders() + 1) < Account.LimitOrders(); i -= CSymbol.LotsMax())

  • Volume(): obtém o volume atual (tamanho do lote) da ordem.
  • O loop começa no volume atual (i = Volume()) e, enquanto:

    1. O lote for maior ou igual ao mínimo (CSymbol.LotsMin()).
    2. A soma de posições + ordens existentes for menor que o limite da conta (Account.LimitOrders()).

Ele reduz o lote em incrementos de CSymbol.LotsMax() a cada iteração para respeitar limites de volume.

Etapa 8: Normalizar o Tamanho do Lote

NormalizeLotsize(i);

  • O lote (i) é normalizado para atender às regras de precisão do símbolo.

Etapa 9: Tentar Abrir a Ordem Buy-Stop

if (!Trade.BuyStop((i > CSymbol.LotsMax()) ? CSymbol.LotsMax() : i, myBuyStop.Get().Open, CSymbol.GetSymbolName(), 
myBuyStop.Get().Stop, myBuyStop.Get().Take, ORDER_TIME_SPECIFIED, CTS.SessionEnd(), COMMENT))

  • Trade.BuyStop(): tenta enviar a ordem buy-stop com os seguintes parâmetros:

    1. Tamanho do lote: O tamanho do lote é limitado a CSymbol.LotsMax() (o tamanho máximo de lote permitido para o símbolo). Se i exceder o máximo, usa-se o máximo; caso contrário, usa-se i.
    2. Preço de abertura: o preço em que a buy-stop deve ser executada.
    3. Nome do símbolo: O nome do símbolo de negociação (par de moedas etc.).
    4. Stop-loss: o preço de stop-loss calculado para a ordem.
    5. Take-profit: o preço de take-profit calculado.
    6. Tempo de expiração: definido para o fim da sessão de negociação do símbolo no dia atual (CTS.SessionEnd()).
    7. Comentário: o comentário opcional informado.

Se a ordem não for aberta, a função retornará falso, indicando que a ordem buy-stop não foi colocada com sucesso.

Etapa 10: Retornar o Resultado

return true;

  • Se a ordem for aberta com sucesso, a função retorna true, indicando que a ordem de buy-stop foi colocada com êxito.

Função OpenSellStop

Para a função OpenSellStop, a lógica é semelhante à explicada anteriormente na função OpenBuyStop.

A função OpenStops tenta abrir tanto ordens buy-stop quanto sell-stop. 

//+------------------------------------------------------------------+
//|This function will open both buy-stop and sell-stop orders for    |
//|StopOrdersType(STOP ORDERS)                                       |
//+------------------------------------------------------------------+
bool CTradeManagement::OpenStops(int SL,int TP,ulong Magic,string COMMENT=NULL)
  {
//--- Set buy-stop properties
   SetBuyStop(SL,TP);
//--- Set sell-stop properties
   SetSellStop(SL,TP);
//--- Set the order type for Risk management calculation
   SetOrderType(ORDER_TYPE_BUY);
//--- Set open price for Risk management calculation
   OpenPrice = myBuyStop.Get().Open;
//--- Set close price for Risk management calculation
   ClosePrice = myBuyStop.Get().Stop;
//--- Set Trade magic number
   Trade.SetExpertMagicNumber(Magic);
//--- Check if there are any open trades or opened deals or canceled deals already
   if(!OpenOrder(ORDER_TYPE_BUY_STOP,Magic,COMMENT)&&!OpenedDeal(DEAL_TYPE_BUY,Magic,COMMENT)
      &&!OpenedDeal(DEAL_TYPE_BUY_CANCELED,Magic,COMMENT)
//--- Check if the buy-stop properties are valid
      &&Valid_Order(ORDER_TYPE_BUY_STOP,myBuyStop.Get().Open,myBuyStop.Get().Stop,myBuyStop.Get().Take)
      &&!OpenOrder(ORDER_TYPE_SELL_STOP,Magic,COMMENT)
      &&!OpenedDeal(DEAL_TYPE_SELL,Magic,COMMENT)&&!OpenedDeal(DEAL_TYPE_SELL_CANCELED,Magic,COMMENT)
//--- Check if the sell-stop properties are valid
      &&Valid_Order(ORDER_TYPE_SELL_STOP,mySellStop.Get().Open,mySellStop.Get().Stop,mySellStop.Get().Take))
     {
      //--- Iterate through the Lot-sizes if they're more than max-lot
      for(double i=Volume();i>=CSymbol.LotsMin()&&
          /* Check if current number of orders +2 more orders is less than
             account orders limit.*/
          (PositionsTotal()+Account.numOrders()+2)<Account.LimitOrders()
          ;i-=CSymbol.LotsMax())
        {
         //--- normalize Lot-size
         NormalizeLotsize(i);
         /* Open orders with a Lot-size not more than max-lot and set order expiration
         to the Symbol's session end time for the current day.
         */
         if(!Trade.BuyStop((i>CSymbol.LotsMax())?CSymbol.LotsMax():i,myBuyStop.Get().Open,
                           CSymbol.GetSymbolName(),myBuyStop.Get().Stop,myBuyStop.Get().Take,
                           ORDER_TIME_SPECIFIED,CTS.SessionEnd(),COMMENT)
            ||!Trade.SellStop((i>CSymbol.LotsMax())?CSymbol.LotsMax():i,mySellStop.Get().Open,
                              CSymbol.GetSymbolName(),mySellStop.Get().Stop,mySellStop.Get().Take,
                              ORDER_TIME_SPECIFIED,CTS.SessionEnd(),COMMENT))
           {
            //--- one or more orders failed to open.
            return false;
           }
        }
     }
   else
     {
      //--- Orders failed
      return false;
     }
//--- Return trade result.
   return true;
  }

Etapa 1: Definir Propriedades de Buy-Stop e Sell-Stop

SetBuyStop(SL, TP);
SetSellStop(SL, TP);

  • SetBuyStop: Este método calcula e define o preço de abertura, stop-loss e take-profit para a ordem de buy-stop. Esses valores são armazenados no objeto myBuyStop.
  • SetSellStop: De forma semelhante, este método calcula e define o preço de abertura, stop-loss e take-profit para a ordem de sell-stop, armazenados no objeto mySellStop.

Etapa 2: Definir o Tipo de Ordem para Gestão de Risco

SetOrderType(ORDER_TYPE_BUY);

  • Isso define o tipo interno de ordem para o cálculo de gerenciamento de risco como uma ordem de compra, mesmo que ordens buy-stop e sell-stop estejam sendo colocadas. Essa configuração é usada posteriormente para avaliar o risco com base no stop-loss e take-profit da ordem de compra.

Etapa 3: Definir Preços de Abertura e Fechamento para Gestão de Risco

OpenPrice = myBuyStop.Get().Open;
ClosePrice = myBuyStop.Get().Stop;

  • OpenPrice: O preço de abertura calculado para a ordem de buy-stop.
  • ClosePrice: O preço de stop-loss calculado para a ordem de buy-stop. Esses preços são usados para cálculos internos de gerenciamento de risco.

Etapa 4: Defina o número mágico

Trade.SetExpertMagicNumber(Magic);

  • Isso atribui o número mágico à negociação, que identifica de forma exclusiva as ordens gerenciadas pelo expert advisor (EA).

Etapa 5: Verificar Ordens ou Negociações Existentes

if(!OpenOrder(ORDER_TYPE_BUY_STOP, Magic, COMMENT) && !OpenedDeal(DEAL_TYPE_BUY, Magic, COMMENT)
   && !OpenedDeal(DEAL_TYPE_BUY_CANCELED, Magic, COMMENT)

  • OpenOrder: Verifica se já existe uma ordem buy-stop aberta com o mesmo número mágico e comentário. Se existir, nenhuma nova ordem buy-stop será aberta.
  • OpenedDeal: Verifica se já existe uma posição de compra ativa ou cancelada com o mesmo número mágico e comentário. Se existir, nenhuma nova ordem buy-stop será colocada.

Etapa 6: Validar Propriedades da Ordem Buy-Stop

&& Valid_Order(ORDER_TYPE_BUY_STOP, myBuyStop.Get().Open, myBuyStop.Get().Stop, myBuyStop.Get().Take)

  • Valid_Order: Valida as propriedades da ordem buy-stop (preço de abertura, stop-loss, take-profit) para garantir que elas estejam em conformidade com as regras do símbolo (ex.: nível mínimo de stop). Se a validação passar, o processo segue para verificar a ordem sell-stop.

Etapa 7: Verificar Ordens ou Negociações de Venda Existentes

&& !OpenOrder(ORDER_TYPE_SELL_STOP, Magic, COMMENT) && !OpenedDeal(DEAL_TYPE_SELL, Magic, COMMENT)
&& !OpenedDeal(DEAL_TYPE_SELL_CANCELED, Magic, COMMENT)

  • Semelhante às verificações de buy-stop, essas condições verificam se já existe uma ordem sell-stop, uma negociação de venda ativa ou cancelada com o mesmo número mágico e comentário. Se existir, a função evita colocar uma nova ordem sell-stop.

Etapa 8: Validar Propriedades da Ordem Sell-Stop

&& Valid_Order(ORDER_TYPE_SELL_STOP, mySellStop.Get().Open, mySellStop.Get().Stop, mySellStop.Get().Take))

  • Valid_Order: Valida as propriedades da ordem sell-stop (preço de abertura, stop-loss, take-profit). Se a validação passar, prossegue-se para abrir as ordens buy-stop e sell-stop.

Etapa 9: Iterar pelos Tamanhos de Lote

for (double i = Volume(); i >= CSymbol.LotsMin() && (PositionsTotal() + Account.numOrders() + 2) < Account.LimitOrders(); i -= CSymbol.LotsMax())

  • Volume(): Recupera o volume de negociação atual (tamanho do lote).
  • O loop começa com o volume total (i = Volume()) e reduz o tamanho do lote (i -= CSymbol.LotsMax()) se ele exceder o tamanho máximo permitido (CSymbol.LotsMax()).
  • Garante que o número total de posições abertas e ordens pendentes esteja dentro do limite da conta (Account.LimitOrders()).

O loop garante que, se o tamanho do lote exceder o limite máximo permitido pelo símbolo, ele dividirá as ordens em várias menores.

Etapa 10: Normalizar o Tamanho do Lote

NormalizeLotsize(i);

  • O tamanho do lote (i) é normalizado para estar em conformidade com a precisão permitida do símbolo.

Etapa 11: Tentar Abrir Ordens Buy-Stop e Sell-Stop

if(!Trade.BuyStop((i > CSymbol.LotsMax()) ? CSymbol.LotsMax() : i, myBuyStop.Get().Open,
                  CSymbol.GetSymbolName(), myBuyStop.Get().Stop, myBuyStop.Get().Take,
                  ORDER_TIME_SPECIFIED, CTS.SessionEnd(), COMMENT)
   || !Trade.SellStop((i > CSymbol.LotsMax()) ? CSymbol.LotsMax() : i, mySellStop.Get().Open,
                     CSymbol.GetSymbolName(), mySellStop.Get().Stop, mySellStop.Get().Take,
                     ORDER_TIME_SPECIFIED, CTS.SessionEnd(), COMMENT))

  • Trade.BuyStop: Tenta colocar uma ordem buy-stop com os seguintes parâmetros:
    • Tamanho do lote: Se o tamanho atual do lote (i) exceder o máximo permitido (CSymbol.LotsMax()), a ordem é colocada com o tamanho máximo permitido.
    • Preço de abertura: O preço calculado de abertura para a ordem buy-stop.
    • Nome do símbolo: O nome do instrumento de negociação.
    • Stop-loss: O preço de stop-loss da ordem buy-stop.
    • Take-profit: O preço de take-profit da ordem buy-stop.
    • Tempo de expiração: Definido para o final da sessão de negociação do símbolo no dia atual (CTS.SessionEnd()).
    • Comentário: Um comentário opcional para descrever a ordem.
  • Trade.SellStop: Da mesma forma, tenta colocar uma ordem sell-stop com a mesma lógica da ordem buy-stop.

Se qualquer uma das ordens falhar em abrir, a função retorna false.

Etapa 12: Retornar Resultado

return true;

  • Se ambas as ordens buy-stop e sell-stop forem abertas com sucesso, a função retorna true. Se qualquer parte do processo falhar, a função retorna false.

A função CloseTrades é projetada para fechar todas as posições abertas que correspondam a um comentário especificado (COMMENT_COMMON). 

//+------------------------------------------------------------------+
//|Function will attempt to close all trades depending on the        |
//|position comment                                                  |
//+------------------------------------------------------------------+
void CTradeManagement::CloseTrades(string COMMENT_COMMON)
  {
//--- Iterate through all open positions
   for(int i=0; i<PositionsTotal(); i++)
     {
      ulong ticket = PositionGetTicket(i);
      //--- Check if Position ticket is above zero
      if(ticket>0)
        {
         //--- Check if the Position's Symbol,Comment is correct
         if(PositionGetString(POSITION_SYMBOL)==CSymbol.GetSymbolName()
            &&StringFind(PositionGetString(POSITION_COMMENT),COMMENT_COMMON)>=0)
           {
            //--- close trade.
            Trade.PositionClose(ticket);
           }
        }
     }
  }

Etapa 1: Iterar por Todas as Posições Abertas

for (int i = 0; i < PositionsTotal(); i++)

  • PositionsTotal(): Retorna o número total de posições abertas.
  • Este loop percorre todas as posições atualmente abertas. A variável i é o índice da posição, variando de 0 a PositionsTotal() - 1.

Etapa 2: Obter o Número do Ticket da Posição

ulong ticket = PositionGetTicket(i);

  • PositionGetTicket(i): Recupera o número do ticket da posição aberta no índice i. O número do ticket é um identificador exclusivo para cada posição.
  • O número do ticket é armazenado na variável ticket.

Etapa 3: Verificar se o Ticket é Válido

if (ticket > 0)

  • Verifica se o número do ticket é maior que zero, garantindo que o ticket recuperado seja válido antes de prosseguir. Um número de ticket igual a 0 indicaria que não existe posição no índice fornecido, o que não seria um estado válido.

Etapa 4: Validar Símbolo e Comentário da Posição

if (PositionGetString(POSITION_SYMBOL) == CSymbol.GetSymbolName() 
    && StringFind(PositionGetString(POSITION_COMMENT), COMMENT_COMMON) >= 0)

  • PositionGetString(POSITION_SYMBOL): Recupera o nome do símbolo da posição no índice i (por exemplo, par de moedas).
  • CSymbol.GetSymbolName(): Recupera o nome do símbolo associado ao objeto CSymbol.
  • A primeira condição verifica se o símbolo da posição corresponde ao símbolo gerenciado por CSymbol.
  • PositionGetString(POSITION_COMMENT): Recupera o comentário anexado à posição aberta.
  • StringFind(PositionGetString(POSITION_COMMENT), COMMENT_COMMON): Verifica se a string especificada COMMENT_COMMON está presente no comentário da posição.
    • Se o comentário contiver COMMENT_COMMON, a função retorna um índice onde a correspondência começa.
    • A condição >= 0 garante que só passa se o comentário contiver a substring.

Isso assegura que apenas posições com o símbolo e comentário correspondentes sejam selecionadas para fechamento.

Etapa 5: Fechar a Negociação

Trade.PositionClose(ticket);

  • Trade.PositionClose(ticket): Tenta fechar a posição aberta identificada pelo número do ticket.
  • Se a posição corresponder às condições (símbolo correto e comentário contendo o especificado), ela será fechada usando este método.


Conclusão

Neste artigo, implementamos o código para abrir ordens stop e verificar a validade de negociações e ordens antes de abri-las. Criamos uma função chamada FundamentalMode que lida com um modo especial de negociação, gerenciando ordens stop opostas. Além disso, foi implementada a redução de slippage para ordens stop, mitigando o risco de derrapagem de preço durante condições de mercado voláteis causadas por anúncios de notícias.

Pontos-Chave:

  • Precisão na Execução: A Trade Management Class lida com todos os aspectos de colocação, modificação e fechamento de negociações, garantindo que a execução seja precisa, mesmo em mercados voláteis.
  • Ajustes em Tempo Real: A capacidade de ajustar dinamicamente stop-loss e take-profit garante que o EA responda às mudanças de mercado em tempo real, permitindo melhor gerenciamento de risco.
  • Gestão de Slippage: Ao considerar slippage e implementar lógica para ajustar dinamicamente os parâmetros da negociação, a Trade Management Class garante que as operações sejam executadas o mais próximo possível das condições planejadas, reduzindo perdas potenciais.

Obrigado pelo seu tempo, estou ansioso para trazer mais valor no próximo artigo :) 

Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/16169

Arquivos anexados |
NewsTrading_Part5.zip (598.37 KB)
Últimos Comentários | Ir para discussão (6)
Kabelo Frans Mampa
Kabelo Frans Mampa | 7 nov. 2024 em 13:30
Hamid Rabia #:

Olá, Kabelo,

muito interessante!!!

Infelizmente, o arquivo zip(NewsTrading_Part5.zip )é o mesmo do artigo 4(NewsTrading_Part4.zip )???

Olá Hamid, Infelizmente, não posso colocar todo o código em um único artigo. A parte 5 do News tem mais código do que a parte 4, mas não está completa. Na parte 6, o código restante será implementado para que tudo funcione em conjunto.

Obrigado por seu tempo e compreensão.

Hamid Rabia
Hamid Rabia | 26 nov. 2024 em 19:02

Olá,

Existe alguma maneira simples de exibir antes das notícias o tipo de ordem, compra, venda ou NAN?

Obrigado pela atenção

Kabelo Frans Mampa
Kabelo Frans Mampa | 26 nov. 2024 em 21:38
Hamid Rabia tipo de ordem, compra, venda ou NAN?

Obrigado pela atenção

Olá, Hamid Rabia, obrigado pela sugestão. Vou implementar uma solução e lhe enviarei uma mensagem privada assim que ela for concluída.

Veeral10
Veeral10 | 3 dez. 2024 em 22:27

Este é um artigo fascinante que você criou.


Estou ansioso pela parte 6 e por ver o código completo.

Kabelo Frans Mampa
Kabelo Frans Mampa | 4 dez. 2024 em 13:59
Veeral10 #:

Este é um artigo fascinante que você criou.


Estou ansioso pela parte 6 e por ver o código completo.

Olá, Veeral10, obrigado por suas palavras gentis!

Engenharia de Recursos com Python e MQL5 (Parte II): Ângulo de Preço Engenharia de Recursos com Python e MQL5 (Parte II): Ângulo de Preço
Existem muitas postagens no Fórum MQL5 pedindo ajuda para calcular a inclinação das mudanças de preço. Este artigo demonstrará uma forma possível de calcular o ângulo formado pelas variações de preço em qualquer mercado que você deseje negociar. Além disso, responderemos se desenvolver esse novo recurso vale o esforço e o tempo adicionais investidos. Vamos explorar se a inclinação do preço pode melhorar a precisão de algum dos nossos modelos de IA ao prever o par USDZAR no M1.
Simulação de mercado: Position View (IX) Simulação de mercado: Position View (IX)
Neste artigo, que será um artigo divisor de águas. Vamos começar a explorar de maneira um pouco mais profunda a interação entre as aplicações que estão sendo desenvolvidas para dar suporte total ao sistema de replay/simulação. Aqui vamos analisar um problema. Este tem de um lado, algo bastante chato, mas de outro algo muito interessante de explicar como resolver. E o problema é: Como fazer para adicionar as linhas de take profit e stop loss, depois que elas foram removidas? Isto sem usar o terminal, mas sim fazendo a operação direto no gráfico. Bem isto de fato é algo, a primeira vista simples. Porém existem alguns percalços a serem superados.
Reimaginando Estratégias Clássicas (Parte XI): Cruzamento de Médias Móveis (II) Reimaginando Estratégias Clássicas (Parte XI): Cruzamento de Médias Móveis (II)
As médias móveis e o oscilador estocástico podem ser usados para gerar sinais de negociação de tendência. No entanto, esses sinais só serão observados após a ação do preço ter ocorrido. Podemos superar efetivamente essa defasagem inerente dos indicadores técnicos usando IA. Este artigo ensinará como criar um Expert Advisor totalmente autônomo com IA, de forma a melhorar qualquer uma de suas estratégias de negociação existentes. Até mesmo a estratégia de negociação mais antiga possível pode ser aprimorada.
Do básico ao intermediário: Filas, Listas e Árvores (I) Do básico ao intermediário: Filas, Listas e Árvores (I)
Neste artigo começaremos a explorar uma pequena série de conceitos, que é de suma importância para quem realmente deseja aprender a programar da maneira correta. Com se trata de algo que a principio pode ser muito complicado. Apesar de usar coisas simples. Iremos ver isto aos poucos. Então aqui iremos começar a ver o que seria filas de dados.