English Русский 中文 Español Deutsch 日本語
Receitas MQL5 – Obtendo as propriedades de uma posição de cobertura aberta

Receitas MQL5 – Obtendo as propriedades de uma posição de cobertura aberta

MetaTrader 5Exemplos | 11 dezembro 2018, 07:50
3 225 0
Denis Kirichenko
Denis Kirichenko

Introdução

Relativamente recentemente no terminal de negociação MetaTrader 5 surgiu a capacidade oportunidade de abrir ordens multidirecionais. Esse sistema de registro de ordens é chamado de cobertura (em inglês, 'hedge'). Esse sistema de ordens permite que você transfira facilmente os algoritmos de negociação do MetaTrader 4 para a quinta versão do terminal, aproveitando ao máximo sus recursos. Você pode saber mais sobre a cobertura do MetaTrader 5 no artigo "Agora a plataforma MetaTrader 5 possui um sistema de cobertura de registro de posições".

Esse artigo fala sobre as propriedades da posição agregada, tratada no sistema de cobertura.


1. Tipos de posição de cobertura

Posição de cobertura (cumulativa) é uma posição de mercado formada por várias ordens de mercado. Num sentido restrito, uma posição de cobertura ('hedge') inclui ordens multidirecionais (compra e venda). No entanto, também proponho usar o termo "hedge" num sentido amplo. Além disso, a posição de cobertura generalizará as ordens indo numa só direção. Essa abordagem é devida aos recursos do terminal MetaTrader 5, uma vez que podemos abrir ordens tanto numa direção quanto em diferentes sentidos.

Para classificar a posição cumulativa, podemos usar vários métodos. Talvez o critério mais popular seja esse que distingue as posições pelo tipo de ordens de mercado formando certa posição cumulativa. Assim, com quais ordens essa posição pode ser preenchida? A Tabela 1 abaixo mostra várias combinações.

Tipo Descrição
1 Hedge buy Apenas compras
2 Hedge netting buy Compra "líquida"
3 Hedge sell Apenas vendas
4 Hedge netting sell Venda "líquida"
5 Hedge locked Bloqueio (cobertura total)

Tabela 1. Tipos de cobertura

Explicarei brevemente esses tipos. Se na posição cumulativa houver (em termos do MetaTrader 4) ordens somente para compra ou apenas para venda, assumimos que essa posição é de 'hedge buy' ou de 'hedge sell'. Se na posição houver ordens mistas (compras e vendas), veremos de que tipo de ordens há maior quantidade. Se houver mais ordens de compra, a posição será 'hedge netting buy'. Já se houver mais ordens de venda, então - 'hedge netting sell'. Para ser mais preciso, não é necessário falar sobre o número de ordens, mas, sim, sobre seus volumes. Suponhamos que numa posição haja 1 ordem para a compra de 1,25 lotes e duas ordens de venda de 0,5 e 0,6 lotes. Como resultado, haverá uma posição líquida de compra ('hedge netting buy') de 0,15 lotes:

1,25 – (0,5 + 0,6) = 0,15.

O bloqueio é um tipo especial de posição mista, nele as compras e as vendas se equilibram em termos de volume de negociação.

Na listagem a seguir formalizamos os tipos de cobertura descritos:

//+------------------------------------------------------------------+
//| Hedge type                                                       |
//+------------------------------------------------------------------+
enum ENUM_HEDGE_TYPE
  {
   HEDGE_BUY=0,          // buy
   HEDGE_SELL=1,         // sell   
   HEDGE_NETTING_BUY=2,  // netting buy   
   HEDGE_NETTING_SELL=3, // netting sell
   HEDGE_LOCKED=4,       // lock
  };


Ao usar o sistema de cobertura, posições cumulativas, por definição, podem pertencer a um tipo - buy ou sell. O identificador é um dos valores de enumeração ENUM_POSITION_TYPE:

1) POSITION_TYPE_BUY;

2) POSITION_TYPE_SELL.

No sistema de cobertura, obtemos 5 tipos de posição cumulativa.

Na próxima seção, criaremos uma classe para manipular as propriedades da posição de cobertura.


2. Classe CHedgePositionInfo

Repare que na Biblioteca padrão existe uma classe CPositionInfo fornecendo acesso às propriedades de posições de mercado abertas. No nosso caso, essa classe é apenas parcialmente útil, uma vez que a posição processada por ela será apresentada como uma ordem de mercado separada (em termos do MetaTrader 4). Precisamos de uma classe que processe todas as posições que formam a posição cumulativa ('hedge').

Vamos usar ferramentas de POO e criar uma classe CHedgePositionInfo:

//+------------------------------------------------------------------+
//| Class CHedgePositionInfo                                         |
//| Purpose: Class for access to a hedge position info.              |  
//|              Derives from class CObject.                         |
//+------------------------------------------------------------------+
class CHedgePositionInfo : public CObject
  {
   //--- === Data members === --- 
private:
   ENUM_HEDGE_TYPE   m_type;
   double            m_volume;
   double            m_price;
   double            m_stop_loss;
   double            m_take_profit;
   ulong             m_magic;
   //--- objects
   CArrayLong        m_tickets;
   CSymbolInfo       m_symbol;
   CPositionInfo     m_pos_info;

   //--- === Methods === --- 
public:
   //--- constructor/destructor
   void              CHedgePositionInfo(void){};
   void             ~CHedgePositionInfo(void){};
   //--- initialization
   bool              Init(const string _symbol,const ulong _magic=0);
   //--- get methods
   CSymbolInfo      *Symbol(void)       {return GetPointer(m_symbol);};
   CArrayLong       *HedgeTickets(void) {return GetPointer(m_tickets);};
   CPositionInfo    *PositionInfo(void) {return GetPointer(m_pos_info);};
   ulong             Magic(void) const  {return m_magic;};
   //--- fast access methods to the integer hedge properties
   datetime          Time(void);
   ulong             TimeMsc(void);
   datetime          TimeUpdate(void);
   ulong             TimeUpdateMsc(void);
   ENUM_HEDGE_TYPE   HedgeType(void);
   //--- fast access methods to the double hedge properties
   double            Volume(double &_buy_volume,double &_sell_volume);
   double            PriceOpen(const ENUM_TRADE_TYPE_DIR _dir_type=TRADE_TYPE_ALL);
   double            StopLoss(const ENUM_TRADE_TYPE_DIR _dir_type=TRADE_TYPE_ALL);
   double            TakeProfit(const ENUM_TRADE_TYPE_DIR _dir_type=TRADE_TYPE_ALL);
   double            PriceCurrent(const ENUM_TRADE_TYPE_DIR _dir_type=TRADE_TYPE_ALL);
   double            Commission(const bool _full=false);
   double            Swap(void);
   double            Profit(void);
   double            Margin(void);
   //--- fast access methods to the string hedge properties
   string            TypeDescription(void);
   //--- info methods
   string            FormatType(string &_str,const uint _type) const;
   //--- select
   bool              Select(void);
   //--- state
   void              StoreState(void);
   bool              CheckState(void);

private:
   //--- calculation methods
   bool              AveragePrice(
                                  const SPositionParams &_pos_params,
                                  double &_avg_pr,
                                  double &_base_volume,
                                  double &_quote_volume
                                  );
   int               CheckLoadHistory(ENUM_TIMEFRAMES period,datetime start_date);
  };
//+------------------------------------------------------------------+


Algumas palavras sobre os dados-membros de classe.

Em primeiro lugar, existe um símbolo único. Em outras palavras, uma posição de cobertura pode incluir qualquer posição de um símbolo. A instância da classe CSymbolInfo, isto é, o campo m_symbol é responsável pelo símbolo.

Em segundo lugar, é possível definir o número mágico (m_magic) como um filtro das ordens necessárias. Assim, é possível criar uma posição que seja atendida por um único EA. Nesse caso, num símbolo, podemos criar várias 'hedges'.

Há também uma matriz dinâmica para registro de ordens (m_tickets). Ela conterá os bilhetes das ordens das posições de cobertura.

As funções para obter as propriedades de qualquer uma das posições selecionadas (ordem de mercado em termos de MetaTrader 4) são atribuídas a uma instância da classe CPositionInfo (m_pos_info).

As propriedades restantes de cobertura são necessárias para avaliar seu status:

  • tipo (m_type);
  • volume (m_volume);
  • preço de abertura (m_price);
  • preço de stop-loss (m_stop_loss);
  • preço de take-profit (m_take_profit).

Repare que a lógica da classe CPositionInfo foi tomada para construir a classe. Isso é bem natural. Portanto, na nova classe existem métodos que retornam propriedades inteiras, propriedades duplas, etc. Mas é claro que existem métodos que são específicos.


2.1 Método de inicialização

Antes de usar os recursos da classe, precisamos inicializar a instância correspondente. O método verifica que, em primeiro lugar, o EA funciona exatamente dentro do sistema de cobertura, em segundo lugar, o símbolo desejado é selecionado e também, talvez, o número mágico é definido.

//+------------------------------------------------------------------+
//| Initialization                                                   |
//+------------------------------------------------------------------+
bool CHedgePositionInfo::Init(const string _symbol,const ulong _magic=0)
  {
//--- account margin mode
   ENUM_ACCOUNT_MARGIN_MODE margin_mode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE);
   if(margin_mode!=ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
     {
      Print(__FUNCTION__+": no retail hedging!");
      return false;
     }
   if(!m_symbol.Name(_symbol))
     {
      Print(__FUNCTION__+": a symbol not selected!");
      return false;
     }
   ENUM_SYMBOL_CALC_MODE  symbol_calc_mode=(ENUM_SYMBOL_CALC_MODE)SymbolInfoInteger(_symbol,SYMBOL_TRADE_CALC_MODE);
   if(symbol_calc_mode!=SYMBOL_CALC_MODE_FOREX)
     {
      Print(__FUNCTION__+": only for Forex mode!");
      return false;
     }
   m_magic=_magic;
//---
   return true;
  }
//+------------------------------------------------------------------+

Esse método é obrigatório para o uso subsequente dos recursos da classe de cobertura. Note que o método verifica o modo de cálculo da margem. Se não corresponder ao 'hedge', o método retornará false. Também é verificado o método de cálculo do valor do contrato. Vamos trabalhar apenas com contratos forex.


2.2 Propriedades inteiras

O acesso a propriedades inteiras é realizado através dos métodos:

  1. datetime                   Time(void);
  2. ulong                        TimeMsc(void);
  3. datetime                   TimeUpdate(void);
  4. ulong                        TimeUpdateMsc(void);
  5. ENUM_HEDGE_TYPE   HedgeType(void).

Vejamos, por exemplo, o código do método CHedgePositionInfo::Time():

//+------------------------------------------------------------------+
//| Get  the hedge open time                                         |
//+------------------------------------------------------------------+
datetime CHedgePositionInfo::Time(void)
  {
   datetime hedge_time=WRONG_VALUE;
   int hedge_pos_num=m_tickets.Total();
//--- if any positions
   if(hedge_pos_num>0)
     {
      //--- find the first opened position
      for(int pos_idx=0;pos_idx<hedge_pos_num;pos_idx++)
        {
         ulong curr_pos_ticket=m_tickets.At(pos_idx);
         if(curr_pos_ticket<LONG_MAX)
            if(m_pos_info.SelectByTicket(curr_pos_ticket))
              {
               datetime curr_pos_time=m_pos_info.Time();
               if(curr_pos_time>0)
                 {
                  if(hedge_time==0)
                     hedge_time=curr_pos_time;
                  else
                    {
                     if(curr_pos_time<hedge_time)
                        hedge_time=curr_pos_time;
                    }
                 }
              }
        }
     }
//---
   return hedge_time;
  }
//+------------------------------------------------------------------+

Para obter o tempo de abertura da cobertura, e na verdade a primeira posição da cobertura, precisamos passar por todas as suas posições e encontrar a mais antiga.

Mas para obter o tempo para mudar a cobertura, e de fato a posição que foi alterada pela última, precisamos modificar um pouco o método anterior:

//+------------------------------------------------------------------+
//| Get  the hedge update time                                       |
//+------------------------------------------------------------------+
datetime CHedgePositionInfo::TimeUpdate(void)
  {
   datetime hedge_time_update=0;
   int hedge_pos_num=m_tickets.Total();
//--- if any positions
   if(hedge_pos_num>0)
     {
      //--- find the first opened position
      for(int pos_idx=0;pos_idx<hedge_pos_num;pos_idx++)
        {
         ulong curr_pos_ticket=m_tickets.At(pos_idx);
         if(curr_pos_ticket<LONG_MAX)
            if(m_pos_info.SelectByTicket(curr_pos_ticket))
              {
               //--- get the current position update time
               datetime curr_pos_time_update=m_pos_info.TimeUpdate();
               if(curr_pos_time_update>0)
                  if(curr_pos_time_update>hedge_time_update)
                     hedge_time_update=curr_pos_time_update;
              }
        }
     }
//---
   return hedge_time_update;
  }
//+------------------------------------------------------------------+

O método para determinar o tipo de cobertura é codificado da seguinte forma:

//+------------------------------------------------------------------+
//| Get  the hedge type                                              |
//+------------------------------------------------------------------+
ENUM_HEDGE_TYPE CHedgePositionInfo::HedgeType(void)
  {
   ENUM_HEDGE_TYPE curr_hedge_type=WRONG_VALUE;
   int hedge_pos_num=m_tickets.Total();
//--- if any positions
   if(hedge_pos_num>0)
     {
      //--- get the volumes      
      double total_vol,buy_volume,sell_volume;
      buy_volume=sell_volume=0.;
      total_vol=this.Volume(buy_volume,sell_volume);
      //--- define a hedge type
      if(buy_volume>0. && sell_volume>0.)
        {
         if(buy_volume>sell_volume)
            curr_hedge_type=HEDGE_NETTING_BUY;
         else if(buy_volume<sell_volume)
            curr_hedge_type=HEDGE_NETTING_SELL;
         else
            curr_hedge_type=HEDGE_LOCKED;
        }
      else if(buy_volume>0. && sell_volume==0.)
         curr_hedge_type=HEDGE_BUY;
      else if(buy_volume==0. && sell_volume>0.)
         curr_hedge_type=HEDGE_SELL;
     }
//---
   return curr_hedge_type;
  };
//+------------------------------------------------------------------+

O tipo de cobertura depende da diferença no volume de compras e vendas. Primeiro verificamos se a cobertura é realmente assim num sentido estrito. Se o volume de compras e vendas for igual, a cobertura estará completa. Se houver uma desigualdade, estaremos lidando com uma cobertura parcial.

Em seguida, verificamos se a cobertura não é representada apenas por compras ou vendas.


2.3 Propriedades double

O acesso às propriedades double é realizado pelos métodos:

  1.    double            Volume(double &_buy_volume,double &_sell_volume);
  2.    double            PriceOpen(void);
  3.    double            StopLoss(void);
  4.    double            TakeProfit(void);
  5.    double            PriceCurrent(void);
  6.    double            Commission(void);
  7.    double            Swap(void);
  8.    double            Profit(void);
  9.    double            Margin(void).

É fácil ver que o método para determinar o volume de cobertura tem parâmetros na forma de links. Essa implementação permite que obter imediatamente tanto o valor da cobertura quanto de seus componentes (compras e vendas).

//+------------------------------------------------------------------+
//| Get  the hedge volume                                            |
//+------------------------------------------------------------------+
double CHedgePositionInfo::Volume(double &_buy_volume,double &_sell_volume)
  {
   double total_vol=0.;
   int hedge_pos_num=m_tickets.Total();
//--- if any positions
   if(hedge_pos_num>0)
     {
      _buy_volume=_sell_volume=0.;
      //--- get the buy\sell volumes      
      for(int pos_idx=0;pos_idx<hedge_pos_num;pos_idx++)
        {
         ulong curr_pos_ticket=m_tickets.At(pos_idx);
         if(curr_pos_ticket<LONG_MAX)
            if(m_pos_info.SelectByTicket(curr_pos_ticket))
              {
               ENUM_POSITION_TYPE curr_pos_type=m_pos_info.PositionType();
               double curr_pos_vol=m_pos_info.Volume();
               if(curr_pos_vol>0.)
                 {
                  //--- for a buy position
                  if(curr_pos_type==POSITION_TYPE_BUY)
                     _buy_volume+=curr_pos_vol;
                  //--- else for a sell position
                  else if(curr_pos_type==POSITION_TYPE_SELL)
                     _sell_volume+=curr_pos_vol;
                 }
              }
        }
      total_vol=_buy_volume-_sell_volume;
     }
//---
   return total_vol;
  }
//+------------------------------------------------------------------+

O método auxiliar CHedgePositionInfo::AveragePrice() foi criado para trabalhar com propriedades de preço. Apresentarei um bloco de código em que ele calcula o preço médio da cobertura dependendo do tipo de nível de preço:

//--- if the hedge volumes calculated
if(hedge_base_volume!=0. && hedge_quote_volume!=0.)
  {
   _avg_pr=fabs(hedge_quote_volume/hedge_base_volume);
   _base_volume=hedge_base_volume;
   _quote_volume=hedge_quote_volume;
   return true;
  }

Além disso, é usada a abordagem do valor - a razão entre o valor total da cobertura na moeda cotada e o valor total da cobertura na moeda base.

Mais tarde, veremos um cálculo específico ao trabalhar com um exemplo.

Os métodos para obter o swap e o lucro resumem os indicadores correspondentes de cada posição da cobertura e retornam o valor total. O método para obter a comissão analisa os trades que participaram da abertura de posição. Podemos escolher através do parâmetro, como calcular o tamanho da comissão. Se quisermos obtê-lo somente para os trades de entrada, deixaremos a configuração padrão. Se for necessário calcular a comissão para entrada e saída, o parâmetro deve ser igual a true. Note que o último método é de natureza aproximada por várias razões. Em primeiro lugar, podemos fechar as posições selecionadas usando opostas. Nesse caso, aparecerão trades do tipo DEAL_ENTRY_OUT_BY. Para elas não é cobrada comissão. Em segundo lugar, se a moeda da conta não coincide com a moeda base, ao alterar as taxas, o custo de entrada e saída pode ser diferente.

//+------------------------------------------------------------------+
//| Get  the hedge commission                                        |
//+------------------------------------------------------------------+
double CHedgePositionInfo::Commission(const bool _full=false)
  {
   double hedge_commission=0.;
   int hedge_pos_num=m_tickets.Total();
//--- if any positions
   if(hedge_pos_num>0)
      for(int pos_idx=0;pos_idx<hedge_pos_num;pos_idx++)
        {
         ulong curr_pos_ticket=m_tickets.At(pos_idx);
         if(curr_pos_ticket<LONG_MAX)
            if(m_pos_info.SelectByTicket(curr_pos_ticket))
              {
               long curr_pos_id=m_pos_info.Identifier();
               if(curr_pos_id>0)
                  //--- retrieve the history of deals associated with the selected position 
                  if(HistorySelectByPosition(curr_pos_id))
                    {
                     CDealInfo curr_deal;
                     int deals_num=HistoryDealsTotal();
                     for(int deal_idx=0;deal_idx<deals_num;deal_idx++)
                        if(curr_deal.SelectByIndex(deal_idx))
                          {
                           ENUM_DEAL_ENTRY curr_deal_entry=curr_deal.Entry();
                           if(curr_deal_entry==DEAL_ENTRY_IN)
                             {
                              double curr_deal_commission=NormalizeDouble(curr_deal.Commission(),2);
                              if(curr_deal_commission!=0.)
                                {
                                 double fac=1.;
                                 if(_full) fac=2.;
                                 hedge_commission+=(fac*curr_deal_commission);
                                }
                             }
                          }

                    }
              }
        }
//---
   return hedge_commission;
  }
//+------------------------------------------------------------------+

Repare que a classe tem um método CHedgePositionInfo::Margin() que permite determinar a margem para a posição de cobertura. Na verdade, esse método foi o mais difícil de programar. De maneira simples, podemos dedicar um artigo inteiro a como determinar corretamente o tamanho da garantia adicional para posições abertas e ordens pendentes.


2.3.1 Garantia para a posição de cobertura

Como indica o desenvolvedor, na presença de posições multidirecionais, existem 2 maneiras de calcular a margem, que são determinadas pela corretora. O primeiro método é baseado no cálculo básico, enquanto o segundo é implementado no lado maior.

Confesso que apesar de nunca me ter deparado com o segundo método de cálculo, vamos programá-lo. Mas, primeiro, proponho considerar o primeiro método. Ele terá um algoritmo mais complexo incluindo o cálculo da margem:

  1. Para volume não coberto;
  2. Para o volume coberto (se estiver indicado o tamanho da margem de cobertura);
  3. Para ordens pendentes.

A margem nesse artigo é calculada para o modelo Retail Forex, Futures. O cálculo de margem para ordens pendentes não é considerado.

A fim de obter um cálculo de margem completo para uma posição de cobertura, precisamos de informações sobre os seguintes parâmetros:

  1. Moeda de depósito. Normalmente, as contas são denominadas em dólares estadunidenses (USD), euros (EUR), libras (GBP), francos (CHF).
  2. Moeda de margem. Normalmente, essa é a moeda base do símbolo. Por exemplo, para o par EURUSD, esse será o euro (EUR) e para o par AUDNZD — o dólar australiano (AUD).
  3. Tamanho de alavancagem.

Além disso, repare que na linha de saldo na aba “Negociação” do terminal, o valor da margem será indicado na moeda de depósito. Portanto, o resultado do cálculo deve ser o valor da margem na moeda de depósito.

Como a moeda de margem pode não coincidir com a moeda de depósito, existem várias variantes do algoritmo de cálculo:

  1. Quando a moeda de depósito estiver presente no símbolo da posição de cobertura como moeda base. Digamos que você esteja negociando USDCHF numa conta de dólares.
  2. Quando a moeda de depósito estiver presente no símbolo da posição de cobertura como moeda cotada. Suponhamos que você esteja negociando EURUSD numa conta de dólares.
  3. Quando a moeda de depósito não estiver no símbolo da posição de cobertura. Digamos que você esteja negociando AUDNZD numa conta de dólares.

A primeira opção será a mais fácil de calcular e a última - a mais difícil. Vamos fazer a contabilidade e considerar exemplos para cada opção.

Primeira opção

Assumamos que temos uma conta de dólares (depósito), em que 5 posições estão abertas para o símbolo USDCHF (Fig. 1).


Posições de mercado no par USDCHF

Fig.1 Posições de mercado no par USDCHF


Parâmetros básicos:

Moeda da conta - USD.

Moeda de margem - USD.

Tamanho de alavancagem - 1:100.

Existem 3 posições de compra. O volume total de posições é de 5,55 lotes, o que, em termos de valor, é $ 555 000. Adicionalmente, há 2 posições de venda. O volume total de posições é de 7,5 lotes, o que, em termos de valor, é $ 750 000.

А) cálculo para o volume não coberto

O volume não coberto é de 1,95 lotes ou de $ 195 000. Ele tem a ver com as vendas, porque foi vendido mais do que comprado. Embora, nesse caso, isso não seja muito importante - compra ou venda, porque não precisamos calcular o preço médio ponderado.

A margem desse montante é tomada levando em conta alavancagem:

$195 000 / 100 = $1 950.

B) cálculo para o volume coberto

O volume coberto é de 5,55 lotes ou de $ 555 000.

A margem desse montante é tomada levando em conta alavancagem:

$555 000 / 100 = $5 550.

Nesse caso, a margem é calculada como a soma da margem para o volume coberto e para o não coberto.

$1 950 + $5 550 = $7 500.

É esse valor que vemos - no terminal de negociação - para indicador "Margem".

Segunda opção

Assumamos que temos uma conta de dólares (depósito), em que 5 posições estão abertas para o símbolo EURUSD (Fig. 2).


Posições de mercado no par EURUSD

Fig.2 Posições de mercado no par EURUSD

Parâmetros básicos:

  • Moeda da conta - USD.
  • Moeda de margem - EUR.
  • Tamanho de alavancagem - 1:300.

Existem 3 posições de compra. O volume total de posições é de 5,55 lotes, o que, em termos de valor, é de € 645 617.20 ou $ 645 617,20. O preço médio ponderado de compra é de $ 1,163274.

Existem 2 posições de venda. O volume total de posições é de 7,50 lotes, o que, em termos de valor, é de € 750 000 ou $ 872 409. O preço de venda médio ponderado é de $ 1,163212.

Todas as posições são apresentadas na Tabela 2.

tipo Volume Price Value, $
buy 1.75 1.16329 203 575.75
buy 2.55 1.16329 296 638.95
buy 1.25 1.16322 145 402.50
sell 3.00 1.16323 348 969.00
sell 4.50 1.16320 523 440.00
Total 13.05 1.1632385 1 518 026.20

Таблица.2 Posições de mercado no par EURUSD


Existem 5 posições no total. O volume total de posições é de 13,05 lotes, o que, em termos de valor, é de € 1 305 000 ou $ 1 518 026,20. O preço médio ponderado das posições é de $ 1,16324.

А) cálculo para o volume não coberto

O volume não coberto é de 1,95 lotes ou de €195 000. Ele tem a ver com as vendas, porque foi vendido mais do que comprado. Portanto, para determinar o valor desse volume, tomamos o preço de venda médio ponderado:

$1.163212 * €195 000 = $226 826.34.

A margem desse montante é tomada levando em conta alavancagem:

$226 826.34 / 300 = $756.09.

B) cálculo para o volume coberto

O volume coberto é de 5,55 lotes ou de € 555 000. Para determinar o valor desse volume, tomamos o preço médio ponderado de todas as posições:

$1.1632385 * €555 000 = $645 597.35.

A margem desse montante é tomada levando em conta alavancagem:

$645 597.35 / 300 = $2 151,99.

Em teoria, toda a margem bruta deveria ser:

$756.09 + $2 151.99 = $2 908.08.

No entanto, no terminal, vemos o valor de $1 832,08.

Na verdade, para o volume coberto, é levado em consideração o valor do parâmetro "Margem de cobertura" da especificação do instrumento. Se for menor do que o tamanho do contrato, obtemos certo tipo de multiplicador. Nesse caso, a especificação para o parâmetro especificado define o valor como 50 000. Assim:

Custo do volume coberto = $1,1632385 * €555 000 / (100 000 / 50 000) = $322 798,67.

Margem para o volume coberto = $322 798,67 / 300 = $1 076,00.

Na soma: $756,09 + $1 076,00 = $1 832,08. Este valor corresponde ao do terminal.

Terceira opção

Assumamos que temos uma conta de dólares (depósito), em que 5 posições estão abertas para o símbolo AUDNZD (Fig. 3).


Posições de mercado no par AUDNZD

Fig.3 Posições de mercado no par AUDNZD

Parâmetros básicos:

  • Moeda da conta - USD.
  • Moeda de margem - AUD.
  • Tamanho de alavancagem - 1:300.

Existem 3 posições de compra. O volume total de posições é de 5,55 lotes, o que, em termos de valor, é de A$ 555 000 ou $ 400 442,35. O preço médio ponderado de compra é de $ 0,7215178.

Existem 2 posições de venda. O volume total de posições é de 7,50 lotes, o que, em termos de valor, é de A$ 750 000 ou $ 541 035,00. O preço de venda médio ponderado é de $ 0,72138.

Todas as posições são apresentadas na Tabela 3.

tipo Volume Price Value, $
buy 1.75 0.72152 126 266.00
buy 2.55 0.72152 183 987.60
buy 1.25 0.72151 90 188.75
sell 3.00 0.72144 216 432.00
sell 4.50 0.72134 324 603.00
Total 13.05 0.72144 941 477.35

Таблица.3 Posições de mercado no par AUDNZD


É fácil ver que a coluna Price mostra os preços de abertura das posições não do AUDNZD, mas, sim, do AUDUSD. Isso é feito para avaliar imediatamente o volume negociado na moeda da conta. Nesse caso, é necessário consultar o histórico de ticks e de cotações do par no qual são apresentadas a moeda da conta e a moeda da margem, portanto, os valores calculados podem diferir ligeiramente dos reais.

Existem 5 posições no total. O volume total de posições é de 13,05 lotes, o que, em termos de valor, é de A$1 305 000 ou $ 941 477,35. O preço médio ponderado das posições é de $ 0,72144.

А) cálculo para o volume não coberto

O volume não coberto é de 1,95 lotes ou de A$ 195 000. Ele tem a ver com as vendas, porque foi vendido mais do que comprado. Portanto, para determinar o valor desse volume, tomamos o preço de venda médio ponderado:

$0.72138 * A$195 000 = $140 669.10.

A margem desse montante é tomada levando em conta alavancagem:

$140 669.10 / 300 = $468.90.

B) cálculo para o volume coberto

O volume coberto é de 5,55 lotes ou de A$ 555 000. Para determinar o valor desse volume, tomamos o preço médio ponderado de todas as posições, levando em conta o valor do parâmetro 'Margem de cobertura':

$0.72144 * A$555 000 / (100 000 / 50 000) = $200 199.21.

A margem desse montante é tomada levando em conta alavancagem:

$200 199.21/ 300 = $667.33.

Na soma: $468.90 + $667,33 = $1 136,23. Verificamos de acordo com a Fig. 3 se coincide com o do terminal.


2.4 Outras propriedades

Ainda existem métodos na classe que funcionam com o estado de cobertura: StoreState() e CheckState(). Tal como acontece com a posição normal, esse estado é determinado pelos valores de tipo, do volume, do preço de abertura, do preço de stop-loss e de take-profit.

Um único método da propriedade de texto TypeDescription() retorna o tipo de cobertura como uma string.

Vale a pena prestar mais atenção ao método de seleção de posição de cobertura Select(). O código do método é apresentado abaixo:

//+------------------------------------------------------------------+
//| Selects hedge positions                                          |
//+------------------------------------------------------------------+
bool CHedgePositionInfo::Select(void)
  {
   string hedge_symbol=m_symbol.Name();
//--- clear all positions 
   m_tickets.Shutdown();
//--- collect positions
   int pos_num=PositionsTotal();
   for(int pos_idx=0;pos_idx<pos_num;pos_idx++)
      if(m_pos_info.SelectByIndex(pos_idx))
        {
         string curr_pos_symbol=m_pos_info.Symbol();
         //--- select by symbol
         if(!StringCompare(hedge_symbol,curr_pos_symbol))
           {
            //--- if to select by magic
            bool is_the_same_magic=true;
            if(m_magic>0)
              {
               long curr_pos_magic=m_pos_info.Magic();
               if(m_magic!=curr_pos_magic)
                  is_the_same_magic=false;
              }
            if(is_the_same_magic)
              {
               ulong curr_pos_ticket=m_pos_info.Ticket();
               if(curr_pos_ticket>0)
                  if(!m_tickets.Add(curr_pos_ticket))
                    {
                     PrintFormat(__FUNCTION__+": failed to add #%d ticket!",curr_pos_ticket);
                     return false;
                    }
              }
           }
        }
//---
   return m_tickets.Total()>0;
  }
//+------------------------------------------------------------------+

O principal objetivo do método é atualizar as boletas das posições que compõem a cobertura. Posições de mercado são incluídas nela se seu símbolo coincide com o símbolo da cobertura em si. Também podemos adicionar um filtro de seleção, como um magic.


3. Exemplos

Assim, criamos uma classe que trabalha com propriedades de posição de cobertura. Nessa seção, proponho trabalhar com exemplos práticos. Vamos começar com um script simples.


3.1 Script de teste

Para treinar, foi criado o script Test_hedge_properties.mq5 que registra na guia Especialistas informações sobre as propriedades da cobertura.

Na primeira versão do cálculo da garantia, tínhamos 5 posições no símbolo USDCHF (Fig. 1). Iniciamos o script e obtemos as seguintes informações no log:

2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)       ---== Hedge properties==---
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)       Symbol: USDCHF
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)       Positions total = 5
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)               1) #293972991 buy 1.75 USDCHF 0.97160000
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)               2) #293974150 buy 2.55 USDCHF 0.97142000
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)               3) #293974889 sell 3.00 USDCHF 0.97157000
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)               4) #293975329 sell 4.50 USDCHF 0.97164000
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)               5) #293976289 buy 1.25 USDCHF 0.97205000
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)       Magic: 0
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)       Time: 2018.08.29 17:15:44
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)       Time in msc: 1535562944628
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)       Update time: 2018.08.29 17:20:35
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)       Update time in msc: 1535563235034
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)       Type: HEDGE_NETTING_SELL
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)       Type description: hedge netting sell
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)       Volume: -1.95
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)       Buy volume: 5.55
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)       Sell volume: 7.50
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)       Open price: 0.97159
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)       Sl-price: -1.00000
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)       Tp-price: -1.00000
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)       Current price: 0.96956
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)       Commission: 0.00
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)       Swap: -35.79
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)       Profit: 409.77
2018.09.03 18:51:37.078 Test_hedge_properties (AUDNZD,H1)       Margin: 7500.00

Na segunda versão, processamos as propriedades das posições no símbolo EURUSD (Fig. 2). Após a inicialização, o script recebeu as seguintes informações:

2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)       ---== Hedge properties==---
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)       Symbol: EURUSD
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)       Positions total = 5
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)               1) #119213986 buy 1.75 EURUSD 1.16329000
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)               2) #119214003 buy 2.55 EURUSD 1.16329000
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)               3) #119214004 buy 1.25 EURUSD 1.16322000
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)               4) #119214011 sell 3.00 EURUSD 1.16323000
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)               5) #119214021 sell 4.50 EURUSD 1.16320000
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)       Magic: 0
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)       Time: 2018.08.31 16:38:10
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)       Time in msc: 1535733490531
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)       Update time: 2018.08.31 16:38:49
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)       Update time in msc: 1535733529678
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)       Type: HEDGE_NETTING_SELL
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)       Type description: hedge netting sell
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)       Volume: -1.95
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)       Buy volume: 5.55
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)       Sell volume: 7.50
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)       Open price: 1.16303
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)       Sl-price: -1.00000
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)       Tp-price: -1.00000
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)       Current price: 1.16198
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)       Commission: 0.00
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)       Swap: -37.20
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)       Profit: 206.60
2018.09.03 18:55:09.469 Test_hedge_properties (AUDNZD,H1)       Margin: 1832.08

Na terceira versão, o trabalho foi realizado com posições no símbolo AUDNZD (Fig. 3). O script gerou as seguintes informações no log:

2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)       ---== Hedge properties==---
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)       Symbol: AUDNZD
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)       Positions total = 5
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)               1) #119214062 buy 1.75 AUDNZD 1.08781000
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)               2) #119214068 buy 2.55 AUDNZD 1.08783000
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)               3) #119214071 buy 1.25 AUDNZD 1.08785000
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)               4) #119214083 sell 3.00 AUDNZD 1.08773000
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)               5) #119214092 sell 4.50 AUDNZD 1.08757000
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)       Magic: 0
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)       Time: 2018.08.31 16:39:41
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)       Time in msc: 1535733581113
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)       Update time: 2018.08.31 16:40:07
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)       Update time in msc: 1535733607241
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)       Type: HEDGE_NETTING_SELL
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)       Type description: hedge netting sell
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)       Volume: -1.95
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)       Buy volume: 5.55
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)       Sell volume: 7.50
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)       Open price: 1.08708
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)       Sl-price: -1.00000
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)       Tp-price: -1.00000
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)       Current price: 1.09314
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)       Commission: 0.00
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)       Swap: -21.06
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)       Profit: -779.45
2018.09.03 18:47:25.369 Test_hedge_properties (EURUSD,H1)       Margin: 1136.23

O código do script Test_hedge_properties.mq5 pode ser baixado do arquivo anexo.


3.1 Painel de propriedades de cobertura

Agora vamos complicar a tarefa. Usando a Biblioteca padrão, escrevemos o EA HedgePropertiesEA.mq5 para exibir um painel mostrando as propriedades da posição de cobertura selecionada.

Para esses propósitos, criaremos a classe CHedgeDialog, que será descendente da classe padrão CAppDialog. Com ajuda dela, nós nos livraremos da necessidade de programar tarefas típicas, como minimizar e restaurar a janela do painel, manipular mudanças nos elementos do painel, etc.

//+------------------------------------------------------------------+
//| Class CHedgeDialog                                               |
//| Purpose: Class for displaying a hedge position info.             |  
//|              Derives from class CAppDialog.                      |
//+------------------------------------------------------------------+
class CHedgeDialog : private CAppDialog
  {
   //--- === Data members === --- 
private:
   CArrayString      m_symbols_arr;
   //--- controls
   CLabel            m_labels[FIELDS_NUM+1];
   CEdit             m_edits[FIELDS_NUM];
   CComboBox         m_combo;
   bool              m_to_refresh;
   //--- === Methods === --- 
public:
   //--- constructor/destructor
   void              CHedgeDialog(void) {};
   void             ~CHedgeDialog(void) {};
   //--- initialization
   bool              Init(void);
   void              Deinit(const int _reason);
   //--- processing
   void              OnChartEvent(const int _id,
                                  const long &_lparam,
                                  const double &_dparam,
                                  const string &_sparam);
   void              OnTradeEvent(void);
   //---
private:
   int               HedgeSymbols(void);
   void              RefreshPanel(void);
  };
//+------------------------------------------------------------------+

Uma instância da classe no código do EA acionará e manipulará os eventos de inicialização, de desinicialização, de gráfico e os relacionados às transações de negociação.

O painel de propriedades da posição de cobertura é mostrado na Fig. 4.

Painel de propriedades da posição de cobertura

Fig. 4 Painel de propriedades da posição de cobertura

Um dos principais métodos é CHedgeDialog::RefreshPanel(). Isso é, por assim dizer, nosso "burro de carga". Se necessário, ele atualiza os campos de informações do painel. Durante a codificação e teste, a alteração do número de coberturas causou certas dificuldades. Nesse caso, precisamos alterar os símbolos exclusivos na lista suspensa e não entrar num ciclo infinito de chamadas do manipulador OnChartEvent(). Para isso, foi usado o limite para chamadas sucessivas a um manipulador com duração de 1 s.

//--- check the limit for refreshing
if(!m_to_refresh)
  {
   uint last_cnt=GetTickCount();
   static uint prev_cnt=0;
   uint msc_elapsed=last_cnt-prev_cnt;
   prev_cnt=last_cnt;
   if(msc_elapsed>1000)
      m_to_refresh=true;
   else
      return;
  }

O código completo do EA HedgePropertiesEA.mq5 é apresentado no arquivo anexado.


Fim do artigo

O terminal de negociação MetaTrader 5 nessa fase, não é apenas multimercado, mas também permite o uso de vários sistemas de registro de posição. Esses recursos expandem significativamente as ferramentas para a implementação e formalização de ideias de negociação.

Espero que esse artigo seja de interesse para aqueles que desejam começar a traduzir suas estratégias do MetaTrader 4 para o MetaTrader 5.


Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/4830

Arquivos anexados |
Hedge.zip (15.37 KB)
Os 100 melhores passes de otimização (parte 1). Desenvolvimento de um analisador de otimizações Os 100 melhores passes de otimização (parte 1). Desenvolvimento de um analisador de otimizações
O artigo trata do desenvolvimento de um aplicativo para selecionar os melhores passes de otimização usando várias opções possíveis. O aplicativo é capaz de ordenar os resultados de otimização por diversos fatores. Os passes de cada otimização são sempre gravadas em um banco de dados, portanto, você sempre poderá selecionar os novos parâmetros do robô sem realizar a re-otimização. Além disso, você pode ver todos os passes de otimização em um único gráfico, calcular a métrica do VaR paramétrico e construir o gráfico de distribuição normal de passes e resultados da negociação de um determinado conjunto de métricas. Além disso, os gráficos de algumas taxas calculadas são construídos dinamicamente, começando com o início da otimização (ou de uma data selecionada para outra data selecionada).
Modelo de continuação de movimento - estatísticas de desempenho e pesquisa em gráficos Modelo de continuação de movimento - estatísticas de desempenho e pesquisa em gráficos
Nesse artigo, quero descrever como funciona um dos modelos de continuação de movimento. O trabalho é baseado na definição de duas ondas — uma principal e outra corretiva. Como extremos serão usados fractais e, como eu os chamo, potenciais fractais - extremos que ainda não se formaram como fractais.
Métodos de controle remoto de EAs Métodos de controle remoto de EAs
A principal vantagem dos robôs de negociação é o fato de poderem trabalhar 24 horas por dia em servidores VPS remotos. Ás vezes, é necessário intervir em seu trabalho manualmente, porém, pode não haver acesso direto ao servidor. Será que é possível gerenciar o trabalho de EAs remotamente? Esse artigo propõe uma das maneiras para controlar robôs por meio de comandos externos.
Usando indicadores para otimização RealTime de EAs Usando indicadores para otimização RealTime de EAs
Não é segredo que o sucesso de qualquer robô de negociação depende da seleção correta de parâmetros (otimização). Mas os parâmetros que são ótimos para um intervalo de tempo nem sempre são os melhores em outros períodos. Muitas vezes, os EAs que são lucrativos nos testes se revelam não lucrativos em tempo real. Nesse momento, surge a necessidade de estar otimizando continuamente, o que se torna uma rotina, porém, sempre há alguém que procura maneiras de automatizar o trabalho. Nesse artigo, proponho uma abordagem não padrão para resolver esse problema.