English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
Guia Prático MQL5: Ordens ОСО

Guia Prático MQL5: Ordens ОСО

MetaTrader 5Exemplos | 12 junho 2015, 16:00
14 617 1
Denis Kirichenko
Denis Kirichenko

Introdução

Este artigo foca em como lidar com o tipos de pares de ordens tal como o OCO. Esse mecanismo é implementado em alguns terminais de negociação concorrentes do MetaTrader 5. Eu busquei dois objetivos através do exemplo de criação de um EA com um painel para o processamento de ordens OCO. Por um lado, eu gostaria de descrever as características da Biblioteca Padrão, por outro lado, eu gostaria de estender o conjunto de ferramentas do trader.


1. Essência da Ordem OCO

As ordens OCO (ordem uma-cancela-a-outra) representam um par de duas ordens pendentes.

Elas estão ligadas por uma função de cancelamento mútuo: se a primeira disparar, a segunda é removida, e vice-versa.

Fig. 1 Par de ordens OCO

Fig. 1 Par de ordens OCO

Fig.1 mostra um esquema simples da interdependência da ordem. Ela reflete uma definição essencial: o par existirá enquanto ambas as ordens existirem. Em termos de lógica, qualquer [uma] ordem do par é uma condição essencial, mas não suficiente para a existência do par.

Algumas fontes dizem que o par deve ter uma ordem limite e uma ordem de stop, além disso as ordens devem ter uma direção (de compra ou venda). Em minha cabeça, tal restrição não pode ajudar na criação de estratégias de negociação flexíveis. Eu sugiro que várias ordens OCO devem ser analisadas no par, e mais importante ainda, nós vamos tentar programar este par.


2. Programação do Par de Ordens

Em meu pensamento, o conjunto de ferramentas POO se adequa da melhor maneira possível para as tarefas de programação relacionadas ao controle sobre as ordens OCO.

As seções seguintes são dedicadas aos novos tipos de dados que servirão para o nosso propósito. A classe CiOcoObject vem em primeiro lugar.


2.1. Classe CiOcoObject

Então, nós precisamos inventar algum objeto do programa responsável pelo controle das duas ordens interligadas.

Tradicionalmente, vamos criar um novo objeto com base na classe abstrata CObject.

Esta nova classe será da seguinte maneira:

//+------------------------------------------------------------------+
//| Classe CiOcoObject                                               |
//| Objetivo: uma classe para ordens OCO 			     |            
//+------------------------------------------------------------------+
class CiOcoObject : public CObject
  {
   //--- === Os membros de dados === --- 
private:
   //--- Tickets do par
   ulong             m_order_tickets[2];
   //--- Flag de inicialização
   bool              m_is_init;
   //--- Id
   uint              m_id;

   //--- === Métodos === --- 
public:
   //--- Construtor/destrutor
   void              CiOcoObject(void){m_is_init=false;};
   void             ~CiOcoObject(void){};
   //--- Construtor de cópia
   void              CiOcoObject(const CiOcoObject &_src_oco);
   //--- Operador de atribuição
   void              operator=(const CiOcoObject &_src_oco);

   //--- Inicialização/desinicialização
   bool              Init(const SOrderProperties &_orders[],const uint _bunch_cnt=1);
   bool              Deinit(void);
   //--- Obter o id
   uint              Id(void) const {return m_id;};

private:
   //--- Tipos de ordens
   ENUM_ORDER_TYPE   BaseOrderType(const ENUM_ORDER_TYPE _ord_type);
   ENUM_BASE_PENDING_TYPE PendingType(const ENUM_PENDING_ORDER_TYPE _pend_type);
   //--- Definir o id
   void              Id(const uint _id){m_id=_id;};
  };

Cada par de ordens OCO vai ter o seu próprio identificador. O seu valor é ajustado por meio do gerador de números aleatórios (objeto da classe Crandom).

Métodos de inicialização e desinicialização do par são de preocupação no contexto da interface. A primeira cria (inicializa) o par, e a segunda remove (desinicializa) ele.

O método CiOcoObject::Init() aceita arrays de estruturas do tipo SOrderProperties como argumento. Este tipo de estrutura representa as propriedades da ordem do par, ou seja, ordem OCO.


2.2 Estrutura SOrderProperties

Vamos considerar os campos da estrutura acima mencionada.

//+------------------------------------------------------------------+
//| Estrutura de propriedades da ordem                               |
//+------------------------------------------------------------------+
struct SOrderProperties
  {
   double                  volume;           // volume da ordem   
   string                  symbol;           // Símbolo
   ENUM_PENDING_ORDER_TYPE order_type;       // Tipo de ordem 
   uint                    price_offset;     // desvio para o preço de execução, em pontos
   uint                    limit_offset;     // desvio para o preço limite, em pontos
   uint                    sl;               // stop loss, em pontos
   uint                    tp;               // take profit, em pontos
   ENUM_ORDER_TYPE_TIME    type_time;        // Tipo de expiração
   datetime                expiration;       // Expiração
   string                  comment;          // comentário
  }

Assim, para realizar o método de trabalho de inicialização nós devemos preencher previamente o array de estruturas compostas por dois elementos. Em palavras simples, é preciso explicar ao programa quais ordens que ele estará colocando.

A enumeração do tipo ENUM_PENDING_ORDER_TYPE é usada na estrutura:

//+------------------------------------------------------------------+
//| Tipo da ordem pendente                                           |
//+------------------------------------------------------------------+
enum ENUM_PENDING_ORDER_TYPE
  {
   PENDING_ORDER_TYPE_BUY_LIMIT=2,       // Buy Limit
   PENDING_ORDER_TYPE_SELL_LIMIT=3,      // Sell Limit
   PENDING_ORDER_TYPE_BUY_STOP=4,        // Buy Stop
   PENDING_ORDER_TYPE_SELL_STOP=5,       // Sell Stop
   PENDING_ORDER_TYPE_BUY_STOP_LIMIT=6,  // Buy Stop Limit
   PENDING_ORDER_TYPE_SELL_STOP_LIMIT=7, // Sell Stop Limit
  };

De um modo geral, ele parece o mesmo que a enumeração padrão ENUM _ORDER_TYPE, mas ele permite selecionar apenas as ordens pendentes, ou, mais verdadeiramente, os tipos de tais ordens.

Ele protege de erros ao selecionar o tipo de ordem correspondente nos parâmetros de entrada (Fig.2).

Fig. 2. O campo "Type" com uma lista suspensa dos tipos de ordens disponíveis

Fig. 2. O campo "Type" com uma lista suspensa dos tipos de ordens disponíveis

Se, no entanto, usarmos a enumeração padão ENUM _ORDER_TYPE, então poderíamos definir o tipo de uma ordem a mercado (ORDER_TYPE_BUY ou ORDER_TYPE_SELL), que não é necessária já que estamos lidando apenas com ordens pendentes.


2.3. Inicialização do Par

Como observado acima, o método CiOcoObject::Init() está envolvido com a inicialização do par da ordem

Na verdade, ele mesmo coloca o par de ordens e registra se o par foi colocado com sucesso ou houve alguma falha. Devo dizer que este é um método ativo, já que ele executa as operações de negociação por si só. Nós podemos criar um método passivo também. Ela simplesmente se conecta a um par de ordens pendentes já ativos, que tenham sido colocados de forma independente.

Eu não irei fornecer o código de todo o método. Mas eu gostaria de salientar que é importante calcular todos os preços (abertura, stop, lucro, limite), de modo que o método da classe de negociação CTrade::OrderOpen() possa executar uma ordem de negociação. Para esse fim, devemos considerar duas coisas: a direção da ordem (compra ou venda) e a posição do preço de execução da ordem em relação ao preço atual (acima ou abaixo).

Este método chama alguns métodos privados: BaseOrderType() e PendingType(). A primeira define a direção da ordem, a segunda determina o tipo da ordem pendente.

Se a ordem foi colocada, o seu ticket é registrado no array m_order_tickets[].

Eu usei um script simples Init_OCO.mq5 para testar este método.

#property script_show_inputs
//---
#include "CiOcoObject.mqh"
//+------------------------------------------------------------------+
//| Entradas 							     |
//+------------------------------------------------------------------+
sinput string Info_order1="+===--Order 1--====+";   // +===--Ordem 1--====+
input ENUM_PENDING_ORDER_TYPE InpOrder1Type=PENDING_ORDER_TYPE_SELL_LIMIT; // Type
input double InpOrder1Volume=0.02;                  // Volume
input uint InpOrder1PriceOffset=125;                // Desvio para o preço de execução, em pontos
input uint InpOrder1LimitOffset=50;                 // Desvio para o preço limite, em pontos
input uint InpOrder1SL=250;                         // Stop loss, em pontos
input uint InpOrder1TP=455;                         // Lucro, em pontos
input string InpOrder1Comment="OCO Order 1";        // Comentários
//---
sinput string Info_order2="+===--Order 2--====+";   // +===--Ordem 2--====+
input ENUM_PENDING_ORDER_TYPE InpOrder2Type=PENDING_ORDER_TYPE_SELL_STOP; // Tipo
input double InpOrder2Volume=0.04;                  // Volume    
input uint InpOrder2PriceOffset=125;                // Desvio do preço de execução, em pontos
input uint InpOrder2LimitOffset=50;                 // Desvio do preço limite, em pontos
input uint InpOrder2SL=275;                         // Stop loss, em pontos
input uint InpOrder2TP=300;                         // Lucro, em pontos
input string InpOrder2Comment="OCO Order 2";        // Comentário

//--- Globais
CiOcoObject myOco;
SOrderProperties gOrdersProps[2];
//+------------------------------------------------------------------+
//| Script da função de início do programa 			     |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- Propriedade da 1ª ordem
   gOrdersProps[0].order_type=InpOrder1Type;
   gOrdersProps[0].volume=InpOrder1Volume;
   gOrdersProps[0].price_offset=InpOrder1PriceOffset;
   gOrdersProps[0].limit_offset=InpOrder1LimitOffset;
   gOrdersProps[0].sl=InpOrder1SL;
   gOrdersProps[0].tp=InpOrder1TP;
   gOrdersProps[0].comment=InpOrder1Comment;

//--- Propriedade da 2ª ordem
   gOrdersProps[1].order_type=InpOrder2Type;
   gOrdersProps[1].volume=InpOrder2Volume;
   gOrdersProps[1].price_offset=InpOrder2PriceOffset;
   gOrdersProps[1].limit_offset=InpOrder2LimitOffset;
   gOrdersProps[1].sl=InpOrder2SL;
   gOrdersProps[1].tp=InpOrder2TP;
   gOrdersProps[1].comment=InpOrder2Comment;

//--- Inicialização do par
   if(myOco.Init(gOrdersProps))
      PrintFormat("Id do novo par OCO: %I32u",myOco.Id());
   else
      Print("Erro ao colocar o par OCO!");
  }

Aqui você pode definir várias propriedades dos futuros pares de ordens. O MetaTrader 5 tem seis diferentes tipos de ordens pendentes.

Com este contexto, pode haver 15 variantes (combinações) de pares (desde que existam diferentes ordens no par).

C(k,N) = C(2,6) = 15

Todas as variantes foram testadas com o auxílio do script. Vou dar um exemplo para o par Buy Stop - Buy Stop Limit.

Os tipos de ordens devem ser especificados nos parâmetros do script (Fig.3).


Fig. 3. Par de ordens "Buy Stop" com "Buy Limit Stop"

Fig. 3. Par de ordens "Buy Stop" com "Buy Limit Stop"

A seguinte informação aparece no registo "Experts":

QO      0       17:17:41.020    Init_OCO (GBPUSD.e,M15) Código do resultado da solicitação: 10009
JD      0       17:17:41.036    Init_OCO (GBPUSD.e,M15) Ticket da nova ordem: 24190813
QL      0       17:17:41.286    Init_OCO (GBPUSD.e,M15) Código do resultado da solicitação: 10009
JH      0       17:17:41.286    Init_OCO (GBPUSD.e,M15) Ticket da nova ordem: 24190814
MM      0       17:17:41.379    Init_OCO (GBPUSD.e,M15) Id do novo par OCO: 3782950319

Mas não podemos trabalhar com as ordens OCO ao máximo com a ajuda do script sem recorrer ao looping.


2.4. Desinicialização do Par

Este método é responsável pelo controle do par de ordens. O par irá "morrer" quando qualquer ordem sair da lista de pedidos ativos.

Eu suponho que este método deve ser colocado nos manipuladores OnTrade() ou OnTradeTransaction() do código do EA. Em tal forma, o EA será capaz de processar a ativação de qualquer par de ordens, sem atraso.

//+------------------------------------------------------------------+
//| Desinicialização do par					     |
//+------------------------------------------------------------------+
bool CiOcoObject::Deinit(void)
  {
//--- Se o par é inicializado
   if(this.m_is_init)
     {
      //--- Verificação das suas ordens 
      for(int ord_idx=0;ord_idx<ArraySize(this.m_order_tickets);ord_idx++)
        {
         //--- Ordem do par atual
         ulong curr_ord_ticket=this.m_order_tickets[ord_idx];
         //--- Outro par de ordens
         int other_ord_idx=!ord_idx;
         ulong other_ord_ticket=this.m_order_tickets[other_ord_idx];

         //---
         COrderInfo order_obj;

         //--- Se não houver ordem atual
         if(!order_obj.Select(curr_ord_ticket))
           {
            PrintFormat("Ordem #%d não foi encontrada na lista de ordens ativas.",curr_ord_ticket);
            //--- Tentativa de excluir uma outra ordem                 
            if(order_obj.Select(other_ord_ticket))
              {
               CTrade trade_obj;
               //---
               if(trade_obj.OrderDelete(other_ord_ticket))
                  return true;
              }
           }
        }
     }
//---
   return false;
  }

Eu gostaria de mencionar um detalhe. O flag de inicialização do par é verificado no corpo do método da classe. Uma tentativa de verificar as ordens não será feita se a flag estiver desmarcada. Esta abordagem evita a exclusão de uma ordem ativa quando outra não tenha sido colocado ainda.

Vamos adicionar esta funcionalidade ao script onde um par de ordens foi colocado. Para este efeito, criaremos o EA de teste Control_OCO_EA.mq5.

De um modo geral o EA vai diferir do script só pelo bloco de manipulação do evento Trade() em seu código:

//+------------------------------------------------------------------+
//| Função Trade                                                     |
//+------------------------------------------------------------------+
void OnTrade()
  {
//--- Desinicialização do par OCO
   if(myOco.Deinit())
     {
      Print("Não há mais par de ordens!");
      //--- Limpar o Par
      CiOcoObject new_oco;
      myOco=new_oco;
     }
  }

O vídeo mostra o trabalho de ambos os programas no terminal MetaTrader 5.


No entanto ambos os programas de teste têm pontos fracos.

O primeiro programa (script) só pode criar ativamente o par, mas depois ele perde o controle sobre ela.

O segundo programa (Expert Advisor), embora ele controle o par, ele não pode criar outros pares repetidamente após a criação da primeira. Para fazer o programa completo de ordem OCO (script), precisamos expandir seu conjunto de ferramentas com a oportunidade de colocar ordens. Faremos isso na próxima seção.


3. EA de Controle

Vamos criar o Painel de Gerenciamento de Ordens OCO no gráfico para colocar e ajustar os parâmetros do par de ordens.

Ele será uma parte do EA de controle (Fig.4). O código fonte está localizado em Panel_OCO_EA.mq5.

Fig. 4. Painel para a criação das ordens OCO: estado inicial

Fig. 4. Painel para a criação das ordens OCO: estado inicial


Devemos selecionar o tipo da futura ordem e preencher os campos para colocar o par de ordens OCO.

Em seguida, o rótulo no único botão do painel será alterado (propriedade de texto, Fig.5).

Fig. 5. Painel para a criação das ordens OCO: novo par

Fig. 5. Painel para a criação das ordens OCO: novo par


As seguintes classes da Biblioteca Padrão foram utilizadas para construir o nosso Painel:

  • CAppDialog é o diálogo do aplicativo principal;
  • CPanel é um rótulo de retângulo;
  • CLabel é um rótulo de texto;
  • CComboBox é um campo com uma lista suspensa;
  • CEdit é um campo de entrada;
  • CButton é um botão.

Claro, os métodos da classe pai foram chamados automaticamente.

Agora vamos para o código. Tem que ser dito que a parte da Biblioteca Padrão que tem se dedicado para a criação dos painéis de indicação e os diálogos é bem grande.

Por exemplo, se você quiser pegar um evento de encerramento da lista suspensa, você terá que mergulhar profundamente na pilha de chamadas (Fig. 6).

Fig. 6. Pilha de Chamadas

Fig. 6. Pilha de Chamadas


O desenvolvedor define os macros e a notação no arquivo %MQL5\Include\Controls\Defines.mqh para os eventos específicos.

Eu criei o evento personalizado ON_OCO para criar o par de OCO.

#define ON_OCO (101) // evento de criação do par OCO

Os parâmetros das ordens futuras são preenchidas e o par é gerado no corpo do manipulador OnChartEvent(). 

//+------------------------------------------------------------------+
//| Função ChartEvent                                                |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Manipulador de todos os eventos do gráfico através do diálogo principal
   myDialog.ChartEvent(id,lparam,dparam,sparam);

//--- Manipulador da lista suspensa
   if(id==CHARTEVENT_CUSTOM+ON_CHANGE)
     {
      //--- Se é o Painel lista
      if(!StringCompare(StringSubstr(sparam,0,7),"myCombo"))
        {
         static ENUM_PENDING_ORDER_TYPE prev_vals[2];
         //--- Índice da lista
         int combo_idx=(int)StringToInteger(StringSubstr(sparam,7,1))-1;

         ENUM_PENDING_ORDER_TYPE curr_val=(ENUM_PENDING_ORDER_TYPE)(myCombos[combo_idx].Value()+2);
         //--- Lembrar a alteração do tipo da ordem
         if(prev_vals[combo_idx]!=curr_val)
           {
            prev_vals[combo_idx]=curr_val;
            gOrdersProps[combo_idx].order_type=curr_val;
           }
        }
     }

//--- Manipulador dos campos de entrada
   else if(id==CHARTEVENT_OBJECT_ENDEDIT)
     {
      //--- Se é o campo de entrada do Painel
      if(!StringCompare(StringSubstr(sparam,0,6),"myEdit"))
        {
         //--- Buscar objeto
         for(int idx=0;idx<ArraySize(myEdits);idx++)
           {
            string curr_edit_obj_name=myEdits[idx].Name();
            long curr_edit_obj_id=myEdits[idx].Id();
            //--- Se os nomes coincidem
            if(!StringCompare(sparam,curr_edit_obj_name))
              {
               //--- Obter o valor atual do campo
               double value=StringToDouble(myEdits[idx].Text());
               //--- Define o índice do array gOrdersProps[]
               int order_num=(idx<gEditsHalfLen)?0:1;
               //--- Define o número do campo da estrutura gOrdersProps
               int jdx=idx;
               if(order_num)
                  jdx=idx-gEditsHalfLen;
               //--- Preenche o campo de estrutura gOrdersProps
               switch(jdx)
                 {
                  case 0: // volume
                    {
                     gOrdersProps[order_num].volume=value;
                     break;
                    }
                  case 1: // Execução
                    {
                     gOrdersProps[order_num].price_offset=(uint)value;
                     break;
                    }
                  case 2: // limite
                    {
                     gOrdersProps[order_num].limit_offset=(uint)value;
                     break;
                    }
                  case 3: // stop
                    {
                     gOrdersProps[order_num].sl=(uint)value;
                     break;
                    }
                  case 4: // lucro
                    {
                     gOrdersProps[order_num].tp=(uint)value;
                     break;
                    }
                 }
              }
           }
         //--- Criação do flag do par OCO
         bool is_to_fire_oco=true;
         //--- Verificação da estrutura de preenchimento 
         for(int idx=0;idx<ArraySize(gOrdersProps);idx++)
           {
            //--- Se o tipo da ordem está definido 
            if(gOrdersProps[idx].order_type!=WRONG_VALUE)
               //--- Se o volume está definido  
               if(gOrdersProps[idx].volume!=WRONG_VALUE)
                  //--- Se o desvio para o preço de execução está definido
                  if(gOrdersProps[idx].price_offset!=(uint)WRONG_VALUE)
                     //--- Se o desvio para o preço limite está definido
                     if(gOrdersProps[idx].limit_offset!=(uint)WRONG_VALUE)
                        //--- Se o stop loss está definido
                        if(gOrdersProps[idx].sl!=(uint)WRONG_VALUE)
                           //--- Se o take profit está definido
                           if(gOrdersProps[idx].tp!=(uint)WRONG_VALUE)
                              continue;

            //--- limpa o flag de criação do par OCO 
            is_to_fire_oco=false;
            break;
           }
         //--- Cria o par OCO?
         if(is_to_fire_oco)
           {
            //--- Completa os campos de comentários
            for(int ord_idx=0;ord_idx<ArraySize(gOrdersProps);ord_idx++)
               gOrdersProps[ord_idx].comment=StringFormat("OCO Order %d",ord_idx+1);
            //--- Altera as propriedades do botão
            myButton.Text("New pair");
            myButton.Color(clrDarkBlue);
            myButton.ColorBackground(clrLightBlue);
            //--- Responder às ações do usuário 
            myButton.Enable();
           }
        }
     }
//--- Manipulador do clique no botão
   else if(id==CHARTEVENT_OBJECT_CLICK)
     {
      //--- Se é o botão de criação do par OCO
      if(!StringCompare(StringSubstr(sparam,0,6),"myFire"))
         //--- Se é para responder às ações do usuário
         if(myButton.IsEnabled())
           {
            //--- Gerar o evento de criação do par OCO
            EventChartCustom(0,ON_OCO,0,0.0,"OCO_fire");
            Print("Foi recebido o comando para criar um novo grupo.");
           }
     }
//--- Manipulador do comando de inicialização do novo par 
   else if(id==CHARTEVENT_CUSTOM+ON_OCO)
     {
      //--- Inicialização do par OCO
      if(gOco.Init(gOrdersProps,gOcoList.Total()+1))
        {
         PrintFormat("Id do novo par OCO: %I32u",gOco.Id());
         //--- Cópia do par
         CiOcoObject *ptr_new_oco=new CiOcoObject(gOco);
         if(CheckPointer(ptr_new_oco)==POINTER_DYNAMIC)
           {
            //--- Adicionar a lista
            int node_idx=gOcoList.Add(ptr_new_oco);
            if(node_idx>-1)
               PrintFormat("Número total do grupo: %d",gOcoList.Total());
            else
               PrintFormat("Erro ao adicionar o par OCO %I32u na lista!",gOco.Id());
           }
        }
      else
         Print("Erro na colocação das ordens OCO!");

      //--- Limpa as propriedades
      Reset();
     }
  }

O código do manipulador não é pequeno. Eu gostaria de dar ênfase a vários blocos.

O primeiro manipulador de todos os eventos do gráfico é dado ao diálogo principal.

Em seguida, estão os blocos de vários eventos de manipulação:

  • Alterar as listas suspensas para definir um tipo de ordem;
  • Edição dos campos de entrada para preencher as propriedades das ordens;
  • Clique no botão para geração de eventos ON_OCO;
  • Resposta de evento ON_OCO: ordem de criação do par.

O EA não verifica se o preenchimento dos campos do painel está correto. É por isso que temos de verificar os valores por nós mesmos, caso contrário, o EA irá mostrar a colocação de ordens OCO com erro.

A necessidade de remover o par e fechar a ordem remanescente é verificada no corpo do manipulador OnTrade().


Conclusão

Eu tentei demonstrar as riquezas das classes da Biblioteca Padrão que podem ser utilizadas para a realização de algumas tarefas específicas.

Particularmente, nós estamos lidando com um problema de manipulação de ordens OCO. Eu espero que o código do EA com o Painel para manipulação de ordens OCO será um ponto de partida para a criação dos pares de ordem mais complicados.


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

Arquivos anexados |
ciocoobject.mqh (27.71 KB)
crandom.mqh (5.19 KB)
init_oco.mq5 (6.42 KB)
control_oco_ea.mq5 (7.88 KB)
panel_oco_ea.mq5 (30.25 KB)
Últimos Comentários | Ir para discussão (1)
Parlo
Parlo | 21 ago 2015 em 01:20
Infelizmente apresenta muitos erros na compilação, de modo a não ser viável a um iniciante.
Negociação Bidirecional e de cobertura de posições no MetaTrader 5 Através do Painel de HedgeTerminal, Parte 1 Negociação Bidirecional e de cobertura de posições no MetaTrader 5 Através do Painel de HedgeTerminal, Parte 1
Este artigo descreve uma nova abordagem para cobertura de posições e desenha uma linha nos debates entre os usuários do MetaTrader 4 e MetaTrader 5 sobre esta matéria. Os algoritmos que fazem essa cobertura confiável são descritos em termos leigos e ilustrado com gráficos e diagramas simples. Este artigo é dedicado ao novo painel HedgeTerminal, que é essencialmente um terminal de negociação com todos os recursos dentro do MetaTrader 5. Usando HedgeTerminal e a virtualização das operações de negociação que ele oferece, posições podem ser gerenciados de forma semelhante ao MetaTrader 4.
Traçando linhas de tendência baseadas em fractais usando MQL4 e MQL5 Traçando linhas de tendência baseadas em fractais usando MQL4 e MQL5
O artigo descreve a automação da plotagem de linhas de tendência com base no indicador Fractals usando MQL4 e MQL5. A estrutura do artigo fornece uma visão comparativa da solução para as duas linguagens. As linhas de tendência são plotados usando os dois últimos fractais conhecidos.
Guia Prático MQL5: Implementando um Array Associativo ou um Dicionário para Acesso Rápido ao Dados Guia Prático MQL5: Implementando um Array Associativo ou um Dicionário para Acesso Rápido ao Dados
Este artigo descreve um algoritmo especial que permite ter acesso aos elementos através de suas chaves únicas. Qualquer tipo de dados de base pode ser usado como uma chave. Por exemplo, ele pode ser representado como uma variável do tipo string ou inteiro. Tais contentores de dados são comumente referenciados a um dicionário ou um array associativo. Ele fornece uma maneira mais fácil e eficiente na resolução de problemas.
Construindo uma Aplicação Interativa para exibir feeds RSS no MetaTrader 5 Construindo uma Aplicação Interativa para exibir feeds RSS no MetaTrader 5
Neste artigo vamos ver a possibilidade de criar um aplicativo para a exibição de feeds RSS. O artigo irá mostrar como os aspectos da Biblioteca Padrão podem ser utilizados para a criação de programas interativos para o MetaTrader 5.