English Русский 中文 Español Deutsch 日本語
preview
Observador Connexus (Parte 8): Adicionando Request Observer (Observador de requisições)

Observador Connexus (Parte 8): Adicionando Request Observer (Observador de requisições)

MetaTrader 5Exemplos |
116 3
joaopedrodev
joaopedrodev

Introdução

Este artigo é a continuação da série em que criamos uma biblioteca chamada Connexus. No primeiro artigo entendemos os fundamentos da função WebRequest, destrinchamos cada um de seus parâmetros e também criamos um exemplo de código que mostra como usar essa função e as dificuldades associadas. No artigo anterior, desenvolvemos a camada cliente, uma classe simples e intuitiva responsável por enviar requisições, receber o objeto de requisição (CHttpRequest) e retornar a resposta (CHttpResponse), que contém informações como código de status, duração, corpo e cabeçalho da resposta. Também fizemos a separação da classe por meio da função WebRequest, tornando a biblioteca mais flexível ao criar uma nova camada chamada CHttpTransport.

Neste oitavo artigo da série, vamos explorar e implementar o Observer na biblioteca, para facilitar o gerenciamento de múltiplas requisições do cliente. Vamos nessa!

Só para relembrar o estado atual da biblioteca, aqui está o diagrama:

Diagrama1


O que é o Observador?

Imagine o Observador como aquele amigo que, meio escondido, apenas observa de longe, atento a tudo, mas sem interferir. No mundo da programação, o padrão Observer (Observador) faz algo muito parecido: ele permite que certos objetos recebam "notificações" quando algo muda, sem precisar saber exatamente quem causou essa mudança. É quase como um toque mágico: alguém move uma peça, e quem precisa saber disso no momento já está ciente. Esse padrão é um dos clássicos para garantir que a lógica de negócio e a interface trabalhem lado a lado. Assim, o sistema ganha fluidez, onde alguns componentes se ajustam automaticamente aos eventos.

A ideia nasceu para resolver um daqueles problemas incômodos que surgem em sistemas muito rígidos, onde um objeto depende de outro e "gruda" nele, sem dar espaço para respirar. A solução? Separar, deixar mais leve. Muito antes de o Observador ganhar nome e sobrenome, os programadores já buscavam tornar os sistemas mais flexíveis. Isso remonta a 1994, no trabalho dos autores Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides "Design Patterns: Elements of Reusable Object-Oriented Software" (1994), onde eles apresentaram o Observer como uma forma ideal de manter vários objetos informados sobre mudanças em um objeto, sem criar correntes de dependência rígida.


Por que usar o padrão Observador?

O Observador é perfeito quando precisamos de desacoplamento, quando é necessário que as partes sejam mais independentes umas das outras. O Sujeito não precisa saber quem está observando, só precisa gritar: "Mudança à vista!" — e seguir em frente. Isso também é útil para atualizações em tempo real; sistemas que exigem atualização instantânea, como interfaces interativas ou notificações automáticas, funcionam de forma muito mais ágil com o Observador.


Componentes do padrão Observador

  1. Sujeito (Subject): É o "dono da peça", cujo estado muda e que deve notificar os observadores sobre essas mudanças. Ele mantém uma lista de observadores e possui métodos para adicionar ou remover elementos dessa lista.
  2. Observador (Observer): Cada Observador é como um "ouvinte", sempre pronto para reagir às mudanças no Sujeito. Ele implementa o método update(), que o Sujeito chama sempre que ocorre uma alteração.

Abaixo está um diagrama que mostra como o padrão Observador funciona:

Diagrama 2

  1. Classes principais
    • Sujeito (Subject): Esta classe mantém uma coleção de observadores (observerCollection) e oferece métodos para gerenciá-los. Sua função é notificar os observadores sempre que o estado mudar.
      • Métodos:
        • registerObserver(observer): Adiciona um observador à coleção.
        • unregisterObserver(observer): Remove um observador da coleção.
        • notifyObservers(): Notifica todos os observadores, chamando o método update() de cada observador em observerCollection.
    • Observador (Observer): É uma interface ou classe abstrata que define o método update(). Todas as implementações concretas do Observador devem implementar esse método, que é chamado quando o Sujeito notifica sobre mudanças.
  2. Classes concretas
    • ConcreteObserverA e ConcreteObserverB: São implementações específicas da interface Observador. Cada uma delas define o método update(), que determina a reação concreta à mudança ocorrida no Sujeito.
  3. Relações entre Sujeito e Observador
    • O Sujeito mantém uma lista de Observadores e os notifica chamando observer.update() para cada um da coleção.
    • Os Observadores concretos reagem às mudanças que ocorrem no Sujeito de acordo com sua implementação específica do método update().

Como isso será útil na biblioteca Connexus? Nós vamos usar esse padrão para informar o código cliente quando uma requisição for enviada, quando uma resposta for recebida ou até mesmo quando ocorrer um erro inesperado. Com esse padrão, o cliente será notificado de que isso aconteceu. Isso simplifica o uso da biblioteca, pois evita a necessidade de criar condições no código do tipo "se ocorrer um erro, faça isso", "se uma requisição for feita, faça aquilo", "se a resposta for recebida, faça isso".


Mão no código

Primeiro, vou mostrar o diagrama que representa como vamos adicionar esse padrão no contexto da biblioteca:

Diagrama 3

Vamos entender melhor como será feita a implementação

  1. Note que o diagrama tem a mesma estrutura do diagrama de referência.
  2. Adicionei dois métodos que ficarão disponíveis para os observadores:
  3. OnSend() → Quando a requisição for enviada.
  4. OnRecv() → Quando a resposta for recebida.
  5. IHttpObserver não será uma classe abstrata, mas sim uma interface.


Criação da interface IHttpClient

Primeiro, vamos criar a interface IHttpClient, cujo caminho será <Connexus/Interface/IHttpClient.mqh>. Nela, definimos duas funções de notificação.

//+------------------------------------------------------------------+
//|                                                IHttpObserver.mqh |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
#include "../Core/HttpRequest.mqh"
#include "../Core/HttpResponse.mqh"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
interface IHttpObserver
  {
   void OnSend(CHttpRequest *request);
   void OnRecv(CHttpResponse *response);
  };
//+------------------------------------------------------------------+


Criação da lista de observadores em CHttpClient

Agora adicionamos a importação da interface.

#include "../Interface/IHttpObserver.mqh"
Depois, criamos um array de observadores em um campo privado da classe. Lembre-se de que esse array precisa armazenar ponteiros, portanto, é necessário adicionar "*" antes do nome da variável. Também criamos métodos públicos para adicionar, remover e notificar todos os observadores armazenados no array.
//+------------------------------------------------------------------+
//|                                                   HttpClient.mqh |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "HttpRequest.mqh"
#include "HttpResponse.mqh"
#include "../Constants/HttpMethod.mqh"
#include "../Interface/IHttpTransport.mqh"
#include "../Interface/IHttpObserver.mqh"
#include "HttpTransport.mqh"
//+------------------------------------------------------------------+
//| class : CHttpClient                                              |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CHttpClient                                        |
//| Heritage    : No heritage                                        |
//| Description : Class responsible for linking the request and      |
//|               response object with the transport layer.          |
//|                                                                  |
//+------------------------------------------------------------------+
class CHttpClient
  {
private:
   IHttpObserver     *m_observers[];                     // Array of observers
   
public:
   //--- Observers
   void              RegisterObserver(IHttpObserver *observer);
   void              UnregisterObserver(IHttpObserver *observer);
   void              OnSendNotifyObservers(CHttpRequest *request);
   void              OnRecvNotifyObservers(CHttpResponse *response);
  };
//+------------------------------------------------------------------+
//| Add observer pointer to observer list                            |
//+------------------------------------------------------------------+
void CHttpClient::RegisterObserver(IHttpObserver *observer)
  {
   int size = ArraySize(m_observers);
   ArrayResize(m_observers,size+1);
   m_observers[size] = observer;
  }
//+------------------------------------------------------------------+
//| Remove observer pointer to observer list                         |
//+------------------------------------------------------------------+
void CHttpClient::UnregisterObserver(IHttpObserver *observer)
  {
   int size = ArraySize(m_observers);
   for(int i=0;i<size;i++)
     {
      if(GetPointer(m_observers[i]) == GetPointer(observer))
        {
         ArrayRemove(m_observers,i,1);
         break;
        }
     }
  }
//+------------------------------------------------------------------+
//| Notifies observers that a request has been made                  |
//+------------------------------------------------------------------+
void CHttpClient::OnSendNotifyObservers(CHttpRequest *request)
  {
   int size = ArraySize(m_observers);
   for(int i=0;i<size;i++)
     {
      m_observers[i].OnSend(request);
     }
  }
//+------------------------------------------------------------------+
//| Notifies observers that a response has been received             |
//+------------------------------------------------------------------+
void CHttpClient::OnRecvNotifyObservers(CHttpResponse *response)
  {
   int size = ArraySize(m_observers);
   for(int i=0;i<size;i++)
     {
      m_observers[i].OnRecv(response);
     }
  }
//+------------------------------------------------------------------+
Por fim, chamamos a função de notificação dentro da função que envia a requisição, para que os observadores sejam de fato informados:
//+------------------------------------------------------------------+
//| class : CHttpClient                                              |
//|                                                                  |
//| [PROPERTY]                                                       |
//| Name        : CHttpClient                                        |
//| Heritage    : No heritage                                        |
//| Description : Class responsible for linking the request and      |
//|               response object with the transport layer.          |
//|                                                                  |
//+------------------------------------------------------------------+
class CHttpClient
  {
private:
   
   IHttpObserver     *m_observers[];                     // Array of observers
   
public:
   //--- Basis function
   bool              Send(CHttpRequest &request, CHttpResponse &response);
  };
//+------------------------------------------------------------------+
//| Basis function                                                   |
//+------------------------------------------------------------------+
bool CHttpClient::Send(CHttpRequest &request, CHttpResponse &response)
  {
   //--- Request
   uchar body_request[];
   request.Body().GetAsBinary(body_request);
   
   //--- Response
   uchar body_response[];
   string headers_response;
   
   //--- Notify observer of request
   this.OnSendNotifyObservers(GetPointer(request));
   
   //--- Send
   ulong start = GetMicrosecondCount();
   int status_code = m_transport.Request(request.Method().GetMethodDescription(),request.Url().FullUrl(),request.Header().Serialize(),request.Timeout(),body_request,body_response,headers_response);
   ulong end = GetMicrosecondCount();
   
   //--- Notify observer of response
   this.OnRecvNotifyObservers(GetPointer(response));
   
   //--- Add data in Response
   response.Clear();
   response.Duration((end-start)/1000);
   response.StatusCode() = status_code;
   response.Body().AddBinary(body_response);
   response.Header().Parse(headers_response);
   
   //--- Return is success
   return(response.StatusCode().IsSuccess());
  }
//+------------------------------------------------------------------+

Trabalho feito, e bem mais simples do que parece quando colocamos o código em prática, não é mesmo? Com isso, finalizamos toda a implementação na biblioteca. Agora precisamos criar os observadores, ou seja, as classes concretas que implementam IHttpObserver. Faremos isso na próxima parte, dedicada aos testes.


Testes

Tudo o que precisamos fazer é usar a biblioteca. Para isso, vou criar um novo arquivo de teste chamado TestObserver.mq5, com o caminho: <Experts/Connexus/Tests/TestObserver.mq5>. Importamos a biblioteca e deixamos apenas o evento OnInit().

//+------------------------------------------------------------------+
//|                                                 TestObserver.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
#include <Connexus/Core/HttpClient.mqh>
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

Logo após a importação, vou criar uma classe concreta que implementa a interface IHttpClient. Ela simplesmente exibirá no console do terminal os dados que foram enviados e recebidos usando a biblioteca:

//+------------------------------------------------------------------+
//|                                                 TestObserver.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
#include <Connexus/Core/HttpClient.mqh>
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CMyObserver : public IHttpObserver
  {
public:
                     CMyObserver(void);
                    ~CMyObserver(void);
   
   void              OnSend(CHttpRequest *request);
   void              OnRecv(CHttpResponse *response);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CMyObserver::CMyObserver(void)
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CMyObserver::~CMyObserver(void)
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CMyObserver::OnSend(CHttpRequest *request)
  {
   Print("-----------------------------------------------");
   Print("Order sent notification received in CMyObserver");
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CMyObserver::OnRecv(CHttpResponse *response)
  {
   Print("-----------------------------------------------");
   Print("Response notification received in CMyObserver");
  }
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- Create objects
   CHttpRequest request;
   CHttpResponse response;
   CHttpClient client;
   CMyObserver *my_observer = new CMyObserver();
   
   //--- Configure request
   request.Method() = HTTP_METHOD_GET;
   request.Url().Parse("https://httpbin.org/get");
   
   //--- Adding observer
   client.RegisterObserver(my_observer);
   
   //--- Send
   client.Send(request,response);
   
   //--- Delete pointer
   delete my_observer;
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

Ao visualizar isso no gráfico, obtemos o seguinte resultado:

Isso mostra que as funções da classe CMyObserver foram chamadas dentro da biblioteca. Isso muda tudo, até porque estamos enriquecendo a biblioteca e alcançando o objetivo principal: torná-la flexível.

O mais interessante é que podemos ter vários observadores em diferentes partes do código. Se tivermos um EA dividido em várias classes, podemos fazer com que cada uma delas crie sua própria implementação de IHttpObserver e pronto! Seremos notificados assim que uma requisição for enviada ou uma resposta recebida.

Agora, com essas inclusões do observador, este é o diagrama atual da biblioteca:

Diagrama 4



Refatoração de pastas

Atualmente, o diretório de todos os arquivos da biblioteca está estruturado da seguinte forma:

|--- Connexus
|--- |--- Constants
|--- |--- |--- HttpMethod.mqh
|--- |--- |--- HttpStatusCode.mqh
|--- |--- Core
|--- |--- |--- HttpClient.mqh
|--- |--- |--- HttpRequest.mqh
|--- |--- |--- HttpResponse.mqh
|--- |--- |--- HttpTransport.mqh
|--- |--- Data
|--- |--- |--- Json.mqh
|--- |--- Header
|--- |--- |--- HttpBody.mqh
|--- |--- |--- HttpHeader.mqh
|--- |--- Interface
|--- |--- |--- IHttpObserver.mqh
|--- |--- |--- IHttpTransport.mqh
|--- |--- URL
|--- |--- |--- QueryParam.mqh
|--- |--- |--- URL.mqh

Faremos dois ajustes: mover os arquivos da pasta URL para a pasta Data e renomeá-la para Utils, simplificando assim ambas as pastas que contêm arquivos com finalidades semelhantes. Também adicionaremos a pasta interfaces dentro da pasta Core, já que as interfaces fazem parte do núcleo da biblioteca. No final, a estrutura de pastas da biblioteca ficará assim:

|--- Connexus
|--- |--- Constants
|--- |--- |--- HttpMethod.mqh
|--- |--- |--- HttpStatusCode.mqh
|--- |--- Core
|--- |--- |--- Interface
|--- |--- |--- |--- IHttpObserver.mqh
|--- |--- |--- |--- IHttpTransport.mqh
|--- |--- |--- HttpClient.mqh
|--- |--- |--- HttpRequest.mqh
|--- |--- |--- HttpResponse.mqh
|--- |--- |--- HttpTransport.mqh
|--- |--- Utils
|--- |--- |--- Json.mqh
|--- |--- |--- QueryParam.mqh
|--- |--- |--- URL.mqh
|--- |--- Header
|--- |--- |--- HttpBody.mqh
|--- |--- |--- HttpHeader.mqh


Renomeando alguns métodos

Quando falamos em escrever código que seja fácil de entender, manter e melhorar, adotar um estilo de codificação padrão é essencial. Ter um padrão único na criação de bibliotecas vai muito além da estética; ele garante clareza, previsibilidade e uma base sólida para todos que venham a usar ou colaborar com o código, seja hoje ou no futuro. Esse estilo unificado não é apenas uma questão de organização; é um investimento em qualidade, confiabilidade e no crescimento saudável da biblioteca ao longo do tempo. Embora, à primeira vista, possa parecer um detalhe simples, acaba se tornando o fio condutor que torna o código seguro e mais preparado para evoluir.


Por que é tão importante seguir um estilo padrão?

  • Consistência e legibilidade: um código bem estruturado e com estilo unificado torna a leitura mais fluida e compreensível para qualquer desenvolvedor. Com um padrão claramente definido, as pessoas não precisam perder tempo decifrando variações ou inconsistências; em vez disso, podem focar no que realmente importa: a lógica do código. Aspectos como espaçamento, indentação e nomenclatura são detalhes que, juntos, criam uma experiência prática mais intuitiva e clara. Tudo fica consistente, o que facilita a navegação e reduz os obstáculos causados pela diversidade e desconexão de estilos.
  • Facilidade de manutenção e expansão: Bibliotecas raramente permanecem estáticas; novas demandas surgem e, naturalmente, exigem ajustes. Com um estilo de codificação padronizado, a manutenção se torna mais simples e menos propensa a erros. Isso não apenas economiza tempo na resolução de problemas, mas também ajuda novos desenvolvedores a compreenderem rapidamente o código e colaborarem de forma eficiente. E, claro, uma biblioteca que já nasceu bem estruturada é muito mais fácil de escalar, pois cada nova função encontra um ambiente previsível e organizado para ser integrada.

Dito isso, vamos definir alguns padrões no código, especialmente na parte de nomenclatura de funções. Alguns outros já foram aplicados, por exemplo:

  • Todas as classes usam o prefixo "C" antes do nome
  • Todas as interfaces usam o prefixo "I" antes do nome
  • Variáveis privadas usam o prefixo "m_"
  • Métodos sempre começam com letra maiúscula
  • Valores ENUM devem ser escritos em maiúsculas

Todos esses padrões já foram aplicados na biblioteca durante o desenvolvimento, mas vamos acrescentar outros, como:

  • Métodos para definir/obter atributos da classe devem usar o prefixo Get ou Set
  • Métodos que retornam o tamanho de um array devem ter o nome "Size"
  • Métodos que resetam atributos da classe devem ter o nome "Clear"
  • Métodos para conversão em string devem ter o nome "ToString"
  • Evitar redundância de nomes em classes contextuais. Por exemplo, a classe CQueryParam tem o método AddParam(), que não faz sentido. O ideal seria apenas Add(), já que já estamos no contexto de parâmetros.

Mesmo assim, não vou listar todos os métodos da biblioteca que foram renomeados, nem fornecer o código-fonte, já que não alterei a implementação dos métodos, apenas seus nomes. Mas, considerando as mudanças, deixo abaixo um diagrama que mostra todas as classes da biblioteca com os nomes atualizados dos métodos e suas relações.

Diagrama 5


Conclusão

Com este último artigo, encerramos a série sobre a criação da biblioteca Connexus, desenvolvida para simplificar a interação HTTP. Foi uma jornada desafiadora: começamos pelos fundamentos, avançamos para técnicas mais sofisticadas de design e refino de código e exploramos o padrão Observador (Observer), dando ao Connexus a reatividade necessária em sistemas dinâmicos e flexíveis. Implementamos esse padrão na prática para que diferentes partes do aplicativo possam reagir automaticamente às mudanças, criando uma estrutura robusta e adaptável.

Além do Observador, estruturamos toda a arquitetura de arquivos e pastas, tornando o código modular e intuitivo. Também renomeamos métodos para aumentar a clareza e tornar o uso da biblioteca mais simples e consistente — detalhes que fazem toda a diferença quando falamos em código limpo e manutenção a longo prazo.

O Connexus foi criado para tornar a integração HTTP o mais simples e intuitiva possível, e esperamos que esta série tenha mostrado todos os pontos essenciais do processo, revelando as escolhas de design que permitiram isso. Espero que, com este artigo final, o Connexus não apenas facilite sua integração com HTTP, mas também inspire melhorias contínuas. Muito obrigado por embarcar nessa jornada comigo, e espero que o Connexus seja um aliado em seus projetos!

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

Últimos Comentários | Ir para discussão (3)
Reset_index
Reset_index | 30 set. 2025 em 11:40

Olá! Copiei todos os arquivos deste artigo + arquivos adicionais do artigo anterior para a pasta MQL5. Aqui está o que obtive ao tentar compilar Connexus\Test\TestRequest.mq5:


Rashid Umarov
Rashid Umarov | 30 set. 2025 em 12:39
Kristian Kafarov #:

Olá! Copiei todos os arquivos deste artigo + arquivos adicionais do artigo anterior para a pasta MQL5. Aqui está o que obtive ao tentar compilar o Connexus\Test\TestRequest.mq5:


Flash para o primeiro erro, corrija-o e tudo funcionará
Rashid Umarov
Rashid Umarov | 30 set. 2025 em 13:41

Em resumo, a conversão implícita de tipo de matriz assinada/não assinada não é mais permitida.

Algumas alterações precisam ser feitas no código.

Do básico ao intermediário: Filas, Listas e Árvores (II) Do básico ao intermediário: Filas, Listas e Árvores (II)
Este é um artigo do qual você meu caro leitor, deverá estudar com muita calma. Isto devido ao tipo de coisa que será explicado nele. Apesar de termos procurando manter as coisas o mais simples e didáticas quanto foi possível ser feito. O conteúdo apresentado aqui, é sem sobra de dúvida algo muito complicado para quem está iniciando na programação. Mas isto não é motivo para que você venha a desanimar ou ignorar o que está sendo explicado aqui. Já que este artigo fará um elo, entre dois assuntos completamente diferentes, porém intimamente ligados.
Migrando para o MQL5 Algo Forge (Parte 2): Trabalhando com múltiplos repositórios Migrando para o MQL5 Algo Forge (Parte 2): Trabalhando com múltiplos repositórios
Vamos analisar uma das possíveis abordagens para organizar o armazenamento do código-fonte de um projeto em um repositório público. Utilizando a distribuição em diferentes branches, criaremos regras claras e práticas para o desenvolvimento do projeto.
Simulação de mercado: Position View (X) Simulação de mercado: Position View (X)
Precisamos de fato, de algum meio para conseguir lidar com os objetos gráficos que serão criados. A proposta mostrada no artigo anterior, se encaixa perfeitamente bem, em alguns cenários. No entanto, aqui, precisamos de algo um pouco mais elaborado. Isto devido a natureza do problema com que estamos lidando. Assim sendo, não tentaremos de maneira alguma substituir os mecanismos que estão presentes no MetaTrader 5. Isto para conseguir lidar com o ZOrder, além é claro, verificar qual objeto está em primeiro plano ou encoberto por outro objeto. Vamos fazer algo completamente diferente. Aqui vou mostrar quais as modificações que precisam ser feitas no código a fim de conseguir, tirar de alguma forma, proveito do que o MetaTrader 5, já faz para nos.
Técnicas do Assistente MQL5 que você deve conhecer (Parte 46): Ichimoku Técnicas do Assistente MQL5 que você deve conhecer (Parte 46): Ichimoku
O Ichimuko Kinko Hyo é um renomado indicador japonês que serve como um sistema de identificação de tendência. Examinamos isso, padrão por padrão, como foi o caso em artigos semelhantes anteriores, e também avaliamos suas estratégias e relatórios de teste com a ajuda das classes e montagem da biblioteca wizard do MQL5.