English Русский Español Deutsch 日本語
preview
Desenvolvendo um cliente MQTT para MetaTrader 5: uma abordagem TDD — Final

Desenvolvendo um cliente MQTT para MetaTrader 5: uma abordagem TDD — Final

MetaTrader 5Integração | 30 agosto 2024, 15:54
22 0
Jocimar Lopes
Jocimar Lopes
"Nosso objetivo é sempre trabalhar no mais alto nível de abstração possível, dado um problema e as restrições em sua solução." (Bjarne Stroustrup, Princípios de Programação e Práticas Usando C++)

Introdução

Como este é o último artigo desta série, talvez um breve resumo seja útil, ou pelo menos conveniente.

No primeiro artigo desta série, vimos que o MQTT é um protocolo de compartilhamento de mensagens baseado no modelo de interação de publicação/assinatura (pub/sub) que pode ser útil em um ambiente de negociação, permitindo ao usuário compartilhar qualquer tipo de dado em tempo real: transações comerciais, informações de contas, dados estatísticos para ingestão por um pipeline de aprendizado de máquina, em texto simples, XML, JSON ou dados binários, incluindo imagens. O MQTT é leve, resiliente a instabilidades ou interrupções de rede e indiferente ao conteúdo. Além disso, o protocolo é maduro, testado em batalhas e um padrão aberto mantido pela OASIS. As duas versões mais usadas, a anterior 3.1.1 e a atual 5.0, estão entre os protocolos mais utilizados para conectar um número virtualmente ilimitado de dispositivos na chamada Internet das Coisas. O MQTT pode ser usado em qualquer cenário onde seja necessário o compartilhamento de dados em tempo real entre máquinas desacopladas.

Existem muitos brokers MQTT disponíveis para desenvolvimento, teste e ambientes de produção, tanto de código aberto quanto comerciais, e muitos clientes MQTT para praticamente qualquer linguagem de programação moderna. Você pode verificá-los nesta lista de software MQTT que inclui brokers, bibliotecas e ferramentas.

No segundo artigo desta série, descrevemos nossa organização de código para este desenvolvimento de cliente e comentamos algumas escolhas iniciais de design, como o paradigma Orientado a Objetos. A maior parte desse código mudou em nossa primeira grande refatoração, mas a funcionalidade permanece a mesma. Nesse artigo, também descrevemos algumas conexões que fizemos com um broker local rodando no Subsistema do Windows para Linux (WSL), apenas para perceber que nossa classe CONNECT estava gerando pacotes incorretos. Nós a melhoramos e relatamos isso no próximo artigo.

O terceiro artigo desta série foi dedicado a fazer algumas anotações sobre a parte do comportamento operacional do protocolo e sua relação com as flags CONNECT. Descrevemos a semântica dessas flags e como as estamos configurando. Também fizemos algumas anotações sobre a prática de Desenvolvimento Orientado a Testes que estamos usando para este projeto. Finalmente, explicamos como estamos testando os métodos protegidos de nossas classes.

No quarto artigo desta série, aprofundamos a importância das Propriedades do MQTT 5.0. Comentamos cada uma delas e seus respectivos tipos de dados, ou representação de dados no jargão do MQTT. Lá, fizemos algumas anotações sobre como as Propriedades do MQTT 5.0, em particular a(s) Propriedade(s) do Usuário, podem ser usadas para estender o protocolo.

O Pacote de Controle PUBLISH e suas flags exclusivas (não reservadas) no cabeçalho fixo foram o tópico do quinto artigo desta série. Dedicamos muito espaço tentando mostrar como essas flags do cabeçalho fixo do PUBLISH operam no nível de bits. Marcamos as características dos diferentes níveis de Qualidade de Serviço do MQTT (QoS 0, QoS 1 e QoS 2) com alguns diagramas ilustrativos mostrando a troca de pacotes entre o cliente e o broker em cada um desses QoS.

Um intermezzo foi descrito em nosso sexto artigo desta série. Foi nossa primeira grande refatoração de código. Alteramos o plano de nossas classes de Pacote de Controle e removemos funções duplicadas e código de teste obsoleto. Esse artigo é basicamente uma documentação dessas mudanças com algumas anotações sobre o Pacote de Controle PUBACK. As semânticas dos Códigos de Motivo do PUBACK com suas respectivas Strings de Motivo estão anotadas nesse artigo.

Finalmente, nesta sétima e última parte, queremos compartilhar com você algum código funcional que visa atender a uma necessidade muito comum dos traders quando se trata da construção de sinais de indicadores para serem usados em Expert Advisors: a falta de um símbolo necessário para o indicador na conta de negociação.

Sugerimos uma possível solução usando símbolos personalizados e um par de clientes MQTT rodando como serviços no terminal Metatrader 5. Embora o código de demonstração seja simplificado demais e funcione em uma única instância de terminal, devido à principal característica do próprio protocolo MQTT - que é o desacoplamento entre o remetente e o receptor por uma mediação de "broker" - essa solução pode ser estendida para acomodar qualquer número de instâncias de dispositivos e símbolos.

No final do artigo, indicamos o status atual da biblioteca, nossas prioridades de desenvolvimento com um possível roadmap, e onde você pode acompanhar e contribuir para o projeto.

Nas descrições que se seguem, usamos os termos DEVE e PODE como são usados pelo Padrão OASIS, que por sua vez os usa conforme descrito no IETF RFC 2119.

Além disso, salvo indicação em contrário, todas as citações são do Padrão OASIS.


Uma Necessidade do Trader

Vamos supor que você, como trader, se especialize em criptomoedas. Você descobriu que há uma correlação negativa consistente entre o S&P 500 e um memecoin obscuro e quase desconhecido chamado AncapCoin. Você notou que quando o S&P 500 sobe, o AncapCoin desce, e vice-versa. Esse conhecimento lhe dá uma vantagem nos mercados e você tem ganhado dinheiro negociando AncapCoin seguindo sua correlação negativa com o S&P 500. Agora, para maximizar seus ganhos, você quer automatizar suas operações, eventualmente rodando seu Expert Advisor 24/7 em um VPS. Tudo o que você precisa é de um indicador básico do S&P 500 para apoiar suas decisões de compra e venda do EA.

Mas o AncapBroker também se especializa em criptomoedas. Então eles não têm o S&P 500 entre seus símbolos. E os brokers que oferecem S&P 500 não oferecem seu querido AncapCoin. Como você poderia ter seu indicador do S&P 500 rodando em sua conta de negociação fornecida pelo AncapBroker?

Embora AncapBroker e AncapCoin sejam apenas nomes fictícios, esse cenário fictício não é fictício de forma alguma. Comumente, um trader que opera índices apreciaria ter um indicador composto por ações selecionadas que não são oferecidas pelo broker que oferece os índices e vice-versa. Considere commodities disponíveis para negociação em uma Bolsa centralizada e seus respectivos CFDs disponíveis para negociação em brokers de CFD e você terá um típico desencontro onde o trader tem acesso legítimo aos dados, mas os dados vêm de provedores diferentes. Para negociação manual e discricionária, o problema não é um problema. Com um monitor separado, ou até mesmo com uma janela separada no mesmo monitor, você pode acompanhar o mercado do símbolo ausente. Mas quando se trata de automação, mesmo quando ambos os provedores oferecem Metatrader 5, é muito difícil, se não praticamente impossível para o trader de varejo médio, ter as cotações em tempo real no local onde elas são necessárias para tomar a decisão de negociação: a conta de negociação.

Como desenvolvedor, se você considerar esse cenário como um requisito do cliente, então você também pode considerar o padrão de mensagens de publicação/assinatura como um candidato para resolver esse requisito. Entre as especificações de pub/sub disponíveis, abertas e bem mantidas, o MQTT é provavelmente uma das mais simples, baratas e robustas. Para ser bem claro aqui, o MQTT foi projetado precisamente para resolver o tipo de requisito descrito acima em nosso cenário fictício, ou seja, coletar e distribuir dados de várias fontes, possivelmente geograficamente dispersas, em tempo real e com o mínimo de sobrecarga de rede.

Nas seções abaixo, veremos como você pode implementar essa solução no Metatrader 5, usando nosso cliente em seu estado atual, até o ponto em que você terá as cotações de sua conta de origem de dados fluindo em tempo real para sua conta de negociação. Lá, elas estarão disponíveis para construir aquele indicador necessário.

Na conta de negociação, iremos

  1. Criar um símbolo personalizado para representar nosso S&P 500 ausente
  2. Escrever um serviço SUBSCRIBE MQTT para receber as cotações do S&P 500 do broker MQTT
  3. Atualizar nosso símbolo personalizado que representa o S&P 500 usando funções MQL5

Na conta de origem de dados, iremos

  1. Escrever um serviço PUBLISH MQTT para coletar cotações do S&P 500 e enviá-las para um broker MQTT

Por favor, note que, para manter as coisas simples e curtas, estamos falando sobre uma conta de negociação e uma conta de origem de dados, mas o número dessas contas é teoricamente ilimitado. Em termos práticos, o número de contas conectadas em ambos os lados é limitado apenas pelos limites físicos dos dispositivos (memória, CPU, largura de banda da rede, etc.) e pelos limites impostos pelo seu broker MQTT.

Além disso, por favor, lembre-se de que nosso objetivo aqui não é fornecer uma solução pronta para produção. Em vez disso, nosso objetivo é mostrar os principais passos necessários para uma possível implementação e, claro, despertar seu interesse no potencial uso do padrão pub/sub do MQTT para suas operações de negociação ou para entregar aplicativos personalizados para seus clientes. Estamos convencidos de que isso vai muito além de copiar cotações de um memecoin.


Criar um Símbolo Personalizado

Um símbolo personalizado é um símbolo que você cria com suas especificações desejadas ou necessárias e o atualiza com as cotações que você fornece. Como você tem controle sobre suas especificações e cotações, os símbolos personalizados são úteis para criar índices compostos e para testar Expert Advisors e indicadores.

Você pode criar um símbolo personalizado usando a interface gráfica do editor do Metatrader 5, ou programaticamente através de funções MQL5 específicas. A documentação tem instruções detalhadas sobre como criar, personalizar e usar símbolos personalizados programaticamente ou via interface gráfica. Para nossos propósitos aqui, a interface gráfica é suficiente.

No MetaTrader 5 que hospeda sua conta de negociação, clique em Visualizar > Símbolos > criar símbolo personalizado.

MetaTrader 5 - Criando um Símbolo Personalizado Usando a Interface Gráfica

Fig. 01 - MetaTrader 5 - Criando um Símbolo Personalizado Usando a Interface Gráfica

Na janela que aparecerá a seguir, no campo "Copiar de:", escolha o símbolo S&P 500 para criar um símbolo personalizado baseado no índice real. Insira um nome e uma breve descrição para o seu símbolo personalizado.

Configurando as Especificações de um Símbolo Personalizado Usando a Interface Gráfica

Fig. 02 - MetaTrader 5 - Configurando as Especificações de um Símbolo Personalizado Usando a Interface Gráfica

AVISO: O leitor atento pode ter notado que estamos criando nosso símbolo personalizado na conta de negociação, mas, de acordo com nosso exemplo, essa conta não tem o símbolo S&P 500 para ser usado como modelo para nosso símbolo personalizado. Deveríamos estar na conta de origem de dados. Afinal, o que estamos fazendo aqui é precisamente porque não temos o S&P 500 disponível na conta de negociação. E você está certo! Em uma situação real, você precisará preencher essas especificações do símbolo de acordo com suas necessidades, provavelmente copiando manualmente as especificações do S&P 500. Estamos simplificando demais aqui porque criar símbolos personalizados não é nosso foco aqui. Em vez disso, estamos interessados em conectar as contas via MQTT. Quando confrontado com a necessidade de personalizar o símbolo para sua situação real, consulte a documentação vinculada acima.

Após clicar em OK, seu novo símbolo personalizado deve aparecer na lista em árvore à esquerda.

Verificando a Árvore de Símbolos Após a Criação de um Símbolo Personalizado Usando a Interface Gráfica

Fig. 03 - MetaTrader 5 - Verificando a Árvore de Símbolos Após a Criação de um Símbolo Personalizado Usando a Interface Gráfica

Em seguida, adicione-o à sua Janela de Observação do Mercado para que ele esteja disponível para visualizações de gráficos. Este passo é necessário para atualizações de ticks. 

“A função CustomTicksAdd só funciona para símbolos personalizados abertos na janela de Observação do Mercado. Se o símbolo não estiver selecionado na Observação do Mercado, então você deve adicionar ticks usando CustomTicksReplace.” (documentação de referência MQL5)

MetaTrader 5 - Verificando a Janela de Observação do Mercado Após a Criação de um Símbolo Personalizado Usando a Interface Gráfica

Fig. 04 - MetaTrader 5 - Verificando a Janela de Observação do Mercado Após a Criação de um Símbolo Personalizado Usando a Interface Gráfica

Na janela de Observação do Mercado, você notará que ele ainda não tem cotações. Então, vamos inscrever esta conta no broker MQTT que enviará cotações em tempo real para atualizar nosso novo símbolo personalizado MySPX500.


Escrever um Serviço MQTT de SUBSCRIBE

No estágio atual, nosso cliente pode se inscrever com QoS 0 e QoS 1, mas para atualizar cotações/ticks, acreditamos que o QoS 0 é suficiente, pois a perda eventual de um tick não é crítica neste contexto. Estamos enviando um tick a cada 500ms, então se um ou outro se perder, sua posição será imediatamente ocupada pelo próximo.

Iniciamos nosso código para o serviço de inscrição com parâmetros de entrada para o host e a porta do broker. Lembre-se de substituir isso pelos dados reais do seu broker. Veja na próxima seção algumas notas sobre como configurar seu ambiente de desenvolvimento/testes com um broker local.

#property service
//--- input parameters
input string   host = "172.20.106.92";
input int      port = 80;

Em seguida, declaramos algumas variáveis globais para nossos objetos das classes Connect e Subscribe. Precisaremos dessas variáveis disponíveis para exclusão (limpeza) ao parar ou ao retornar de um erro.

//--- global vars
int skt;
CConnect *conn;
CSubscribe *sub;

“Todos os objetos criados pela expressão object_pointer=new Class_name devem ser deletados pelo operador delete(object_pointer).”(Documentação de referência do MQL5)

Logo no método OnStart() do nosso serviço, configuramos um objeto de conexão para ser uma conexão Clean Start - o que significa que não temos sessão do broker para essa conexão - com um Keep Alive generoso para evitar a necessidade de enviar pedidos de ping periódicos durante o desenvolvimento, definindo nosso identificador de cliente e, finalmente, construindo nosso pacote CONNECT. Certifique-se de definir um identificador de cliente diferente daquele usado em seu serviço de publicação.

   uchar conn_pkt[];
   conn = new CConnect(host, port);
   conn.SetCleanStart(true);
   conn.SetKeepAlive(3600);
   conn.SetClientIdentifier("MT5_SUB");
   conn.Build(conn_pkt);

No mesmo método OnStart(), também configuramos e construímos nosso pacote de inscrição com seu Filtro de Tópico. Para ser claro e intuitivo, estamos usando o nome que escolhemos para nosso símbolo personalizado como o Filtro de Tópico. Isso é arbitrário, desde que você use o mesmo Filtro de Tópico em seu serviço de publicação, é claro.

  uchar sub_pkt[];
  sub = new CSubscribe();
  sub.SetTopicFilter("MySPX500");
  sub.Build(sub_pkt);

Finalmente, chamamos as funções para enviar ambos os pacotes em sequência, delegando o tratamento de erros para essas funções e retornando -1 se algo der errado com nossa solicitação de inscrição.

if(SendConnect(host, port, conn_pkt) == 0)
     {
      Print("Client connected ", host);
     }
   if(!SendSubscribe(sub_pkt))
     {
      return -1;
     }

A função SendConnect tem apenas algumas linhas de código relacionadas ao MQTT. A maior parte é relacionada a redes/soquetes e não vamos detalhá-la aqui. Em vez disso, consulte a documentação sobre Funções de Rede. Se você quiser aprofundar seu entendimento das Funções de Rede do MQL5, recomendamos fortemente os capítulos relacionados no AlgoBook, onde você encontrará explicações detalhadas e exemplos úteis tanto para rede simples e segura (TLS) com MQL5.

No AlgoBook, você encontrará informações como o trecho abaixo, que nos ajudou a identificar e criar uma solução alternativa para um comportamento intermitente e não determinístico em nossa função (veja o código comentado nos arquivos anexos).

“Programadores familiarizados com as APIs de sistema de soquetes do Windows/Linux sabem que um valor de 0 também pode ser um estado normal quando não há dados de entrada no buffer interno do soquete. No entanto, essa função se comporta de forma diferente no MQL5. Com um buffer de soquete de sistema vazio, ele retorna especulativamente 1, adiando a verificação real da disponibilidade de dados até a próxima chamada a uma das funções de leitura. Em particular, essa situação com um resultado fictício de 1 byte ocorre, como regra, na primeira vez que uma função é chamada em um soquete quando o buffer interno de recepção ainda está vazio.”</i>(AlgoBook)

Para o lado do MQTT, tudo o que fazemos na SendConnect é verificar a resposta CONNACK do broker, bem como o valor do Código de Razão associado.

if(rsp[0] >> 4 != CONNACK)
     {
      Print("Not Connect acknowledgment");
      CleanUp();
      return -1;
     }
   if(rsp[3] != MQTT_REASON_CODE_SUCCESS)  // Connect Return code (Connection accepted)
     {
      Print("Connection Refused");
      CleanUp();
      return -1;
     }

Como você pode ver, em ambos retornamos -1 para erro após limpar esses ponteiros dinâmicos para nossos objetos de classe.

A mesma proporção de código relacionado a rede/MQTT se aplica à função SendSubscribe. Depois de verificar a resposta SUBACK do broker e seu respectivo Código de Razão, realizamos a exclusão desses ponteiros dinâmicos de objetos de classe se ocorrer algum erro.

if(((rsp[0] >> 4) & SUBACK) != SUBACK)
     {
      Print("Not Subscribe acknowledgment");
     }
   else
      Print("Subscribed");
   if(rsp[5] > 2)  // Suback Reason Code (Granted QoS 2)
     {
      Print("Subscription Refused with error code %d ", rsp[4]);
      CleanUp();
      return false;
     }

Em um loop infinito, aguardamos mensagens do broker e as lemos com a ajuda de um método estático da classe Publish.

msg += CPublish().ReadMessageRawBytes(inpkt);
               //printf("New quote arrived for MySPX500: %s", msg);
               //UpdateRates(msg);
               printf("New tick arrived for MySPX500: %s", msg);
               UpdateTicks(msg);

Você notará que deixamos um código de desenvolvimento comentado para atualizar taxas em vez de ticks. Você pode descomentar essas linhas se quiser testar dessa forma. Lembre-se de que, ao atualizar apenas taxas e não ticks, algumas informações podem não estar presentes na janela Market Watch e no gráfico. Mas é uma alternativa razoável se você quiser reduzir o consumo de RAM, CPU e largura de banda e tiver mais interesse nos dados para automação de negociação do que nos visuais.

A função UpdateRates funciona em conjunto com sua contraparte no serviço de publicação. Estamos pagando o preço da conversão de string para/de ambos os lados enquanto desenvolvemos nossas Propriedades de Usuário MQTT e temos uma troca de dados binários mais confiável. É a principal prioridade em nosso quase-roadmap.

void UpdateTicks(string new_ticks)
  {
   string new_ticks_arr[];

   StringSplit(new_ticks, 45, new_ticks_arr);

   MqlTick last_tick[1];

   last_tick[0].time          = StringToTime(new_ticks_arr[0]);
   last_tick[0].bid           = StringToDouble(new_ticks_arr[1]);
   last_tick[0].ask           = StringToDouble(new_ticks_arr[2]);
   last_tick[0].last          = StringToDouble(new_ticks_arr[3]);
   last_tick[0].volume        = StringToInteger(new_ticks_arr[4]);
   last_tick[0].time_msc      = StringToInteger(new_ticks_arr[5]);
   last_tick[0].flags         = (uint)StringToInteger(new_ticks_arr[6]);
   last_tick[0].volume_real   = StringToDouble(new_ticks_arr[7]);

   if(CustomTicksAdd("MySPX500", last_tick) < 1)
     {
      Print("Update ticks failed: ", _LastError);
     }
  }

Ao iniciar o serviço de inscrição, você deve ver algo assim na aba de logs do Experts.

MetaTrader 5 - Log de Saída na Aba Experts Mostrando o Erro 5270

Fig. 05 - MetaTrader 5 - Log de Saída na Aba Experts Mostrando o Erro 5270

Nosso serviço de inscrição está falando sozinho no deserto. Vamos corrigir isso executando nosso broker MQTT.


Configurar um Broker Local para Desenvolvimento e Testes

O ambiente que estamos usando para nosso desenvolvimento utiliza o Windows Subsystem For Linux (WSL) em uma máquina Windows. Se tudo o que você deseja é executar os exemplos, você pode executar o cliente e o broker em um loopback na mesma máquina, desde que use identificadores de cliente diferentes para os serviços de publicação e inscrição. Mas se, além de executar os exemplos, você quiser configurar um ambiente de desenvolvimento, recomendamos que configure uma máquina separada para eles. Como você provavelmente sabe, ao desenvolver aplicações cliente/servidor - e o padrão pub/sub pode ser incluído nesta arquitetura para este propósito - é considerado uma boa prática ter cada lado rodando em seu próprio host. Fazendo isso, você pode solucionar problemas de conexão, autenticação e outras questões de rede mais cedo.

Essa configuração com WSL é bastante simples. Detalhamos a instalação, ativação e configuração do WSL em outro artigo publicado há um ano. Abaixo estão algumas dicas especificamente para o uso do broker Mosquitto no WSL. Esses são pequenos detalhes que facilitaram nossa vida e talvez você também os ache úteis.

  • Se você ativar o WSL com suas configurações padrão e instalar o Mosquitto da maneira fácil e recomendada, você provavelmente o instalará usando o gerenciador de pacotes e o executará como um serviço Ubuntu. Ou seja, o Mosquitto será iniciado automaticamente quando você iniciar o shell do WSL. Isso é bom e conveniente para uso regular, mas para desenvolvimento, recomendamos que você pare o serviço Mosquitto e o reinicie manualmente via linha de comando com a flag verbose (-v). Isso evitará a necessidade de usar o comando tail para seguir os logs, pois o Mosquitto estará rodando em primeiro plano e redirecionando todos os logs para o STDOUT. Além disso, os logs não incluem todas as informações que você obterá ao lançá-lo com a flag verbose.

Windows Subsystem For Linux - Parar o Servidor Mosquitto e Reiniciá-lo com a Flag Verbose

Fig. 06 - Windows Subsystem For Linux - Parar o Servidor Mosquitto e Reiniciá-lo com a Flag Verbose

  • Lembre-se de que você deve incluir o nome do host WSL nas URLs permitidas para rede no terminal MetaTrader 5.

Windows Subsystem For Linux - Obtendo o Nome do Host WSL

Fig. 07 - Windows Subsystem For Linux - Obtendo o Nome do Host WSL

MetaTrader 5 - Incluir URLs Permitidas no Menu de Opções do Terminal

Fig. 08 - MetaTrader 5 - Incluir URLs Permitidas no Menu de Opções do Terminal

  • Como esforço para aumentar a segurança, as versões mais recentes do Mosquitto só permitem conexões locais por padrão, ou seja, conexões da mesma máquina. Para se conectar a partir de outra máquina - e sua máquina Windows é considerada outra máquina neste contexto - você deve incluir um listener de uma linha para a porta 1883 (ou outra porta de sua escolha) no arquivo Mosquitto.conf.

Windows Subsystem For Linux - Configurando o Servidor Mosquitto para Escutar na Porta 1883

Fig. 09 - Windows Subsystem For Linux - Configurando o Servidor Mosquitto para Escutar na Porta 1883

  • Finalmente, lembre-se de que o Mosquitto estará rodando na porta 1883 por padrão para conexões não TLS. O terminal MetaTrader 5 só permite conexões nas portas 80 (HTTP) e 443 (HTTPS). Portanto, você precisa redirecionar o tráfego da porta 80 para a porta 1883. Isso pode ser feito com um comando de uma linha se você instalar uma utilidade Linux chamadaredir. Você pode instalá-lo usando o gerenciador de pacotes também.

Windows Subsystem For Linux - Realizando Redirecionamento de Porta Usando a Utilidade Redir

Fig. 10 - Windows Subsystem For Linux - Realizando Redirecionamento de Porta Usando a Utilidade Redir

  • Se você esquecer de incluir o nome do host WSL na lista de URLs permitidas ou redirecionar as portas, você terminará com uma conexão recusada e provavelmente um erro como este aparecerá em seu log na aba Experts

MetaTrader 5 - Log de Saída Mostrando o Erro 5273

Fig. 11 - MetaTrader 5 - Log de Saída Mostrando o Erro 5273 - Falha ao enviar/receber dados do soquete

Mesmo que você não esteja familiarizado com Linux, essa configuração não deve levar mais de dez a quinze minutos para ser configurada, se tudo correr bem. Quando estiver pronto, você poderá verificar se o seu serviço de inscrição está funcionando como esperado.

MetaTrader 5 - Log de Saída Mostrando o Serviço MQTT Subscribe Iniciado e Inscrito

Fig. 12 - MetaTrader 5 - Log de Saída Mostrando o Serviço MQTT Subscribe Iniciado e Inscrito



Escrever um Serviço MQTT de PUBLISH

O serviço de publicação segue a mesma estrutura do serviço de assinatura, então vamos economizar seu tempo e não repetir aqui. Exceto para lembrar novamente de usar um identificador de cliente diferente para os serviços de publicação e assinatura. (Estamos enfatizando este identificador de cliente porque, ao ignorar esse pequeno detalhe na rotina usual de copiar e colar do desenvolvedor, acabamos perdendo tempo depurando um “não-bug” que fez o Mosquitto não entregar nossas mensagens corretamente.)

   uchar conn_pkt[];
   conn = new CConnect(host, port);
   conn.SetCleanStart(true);
   conn.SetKeepAlive(3600);
   conn.SetClientIdentifier("MT5_PUB");
   conn.Build(conn_pkt);

O serviço de publicação roda em um loop contínuo até ser interrompido. Lembre-se de definir o mesmo Filtro de Tópico que você está usando no seu serviço de publicação, claro, e se você quiser atualizar as cotações - em vez dos ticks - descomentar a atribuição do payload para GetRates (e comentar a atribuição para GetLastTick) deve ser suficiente. 

   do
     {
      uchar pub_pkt[];
      pub = new CPublish();
      pub.SetTopicName("MySPX500");
      //string payload = GetRates();
      string payload = GetLastTick();
      pub.SetPayload(payload);
      pub.Build(pub_pkt);
      delete(pub);
     //ArrayPrint(pub_pkt);
      if(!SendPublish(pub_pkt))
        {
         return -1;
         CleanUp();
        }
      ZeroMemory(pub_pkt);
      Sleep(500);
     }
   while(!IsStopped());

As observações que fizemos sobre a proporção de código de rede e código específico do MQTT no serviço de assinatura também se aplicam aqui. Nem precisamos verificar o PUBACK porque não receberemos um, já que estamos usando QoS 0. Então, é apenas uma questão de construir os pacotes, conectar e enviá-los.

Vale a pena notar que, no serviço de publicação, também estamos pagando o preço da conversão de string, pelo menos até que nossa(s) Propriedade(s) de Usuário esteja(m) totalmente implementada(s) e possamos trocar dados binários com confiança.

string GetLastTick()
  {
   MqlTick last_tick;
   if(SymbolInfoTick("#USSPX500", last_tick))
     {
      string format = "%G-%G-%G-%d-%I64d-%d-%G";
      string out;
      out = TimeToString(last_tick.time, TIME_SECONDS);
      out += "-" + StringFormat(format,
                                last_tick.bid, //double
                                last_tick.ask, //double
                                last_tick.last, //double
                                last_tick.volume, //ulong
                                last_tick.time_msc, //long
                                last_tick.flags, //uint
                                last_tick.volume_real);//double
      Print(last_tick.time,
            ": Bid = ", last_tick.bid,
            " Ask = ", last_tick.ask,
            " Last = ", last_tick.last,
            " Volume = ", last_tick.volume,
            " Time msc = ", last_tick.time_msc,
            " Flags = ", last_tick.flags,
            " Vol Real = ", last_tick.volume_real
           );
      Print(out);
      return out;
     }
   else
      Print("Failed to get rates for #USSPX500");
   return "";
  }

Ao iniciar o serviço de publicação no terminal MetaTrader 5, você deve ver algo como o seguinte na aba de logs de Experts.

Saída do Log do MetaTrader 5 Mostrando Serviço de Publicação MQTT Iniciado e Conectado

Fig. 13 - Saída do Log do MetaTrader 5 Mostrando Serviço de Publicação MQTT Iniciado e Conectado

Você pode assinar o tópico no broker Mosquitto e verificar a saída detalhada do broker.

Windows Subsystem For Linux Mostrando Log do Servidor Mosquitto com Flag Verbose

Fig. 14 - Windows Subsystem For Linux Mostrando Log do Servidor Mosquitto com Flag Verbose

Se a mensagem foi recebida com sucesso, você deve vê-la na sua aba de assinatura.

Windows Subsystem For Linux Mostrando Saída da Utilidade mosquitto_sub

Fig. 15 - Windows Subsystem For Linux Mostrando Saída da Utilidade mosquitto_sub


Atualize o Símbolo Personalizado

Com ambos os serviços em funcionamento e verificados com o seu broker, é hora de executá-los no terminal MetaTrader 5 e ver os resultados do seu árduo trabalho.

Navegador MetaTrader 5 Com Serviços de Publicação e Assinatura MQTT Iniciados

Fig. 16 - Navegador MetaTrader 5 Com Serviços de Publicação e Assinatura MQTT Iniciados

Se tudo correr bem, você deve ver algo como o seguinte na aba de ticks da janela Market Watch.

 Aba Ticks do Market Watch do MetaTrader 5 Com Atualizações de Tick do Símbolo Personalizado

Fig. 17 - Aba Ticks do Market Watch do MetaTrader 5 Com Atualizações de Tick do Símbolo Personalizado

No gráfico do seu símbolo personalizado, as atualizações de ticks também devem ser refletidas.

Gráfico de Mercado do MetaTrader 5 com Atualizações de Tick do Símbolo Personalizado

Fig. 18 - Gráfico de Mercado do MetaTrader 5 com Atualizações de Tick do Símbolo Personalizado

Na aba de logs de Experts, você deve encontrar uma saída um pouco detalhada. Isso ocorre porque deixamos algumas informações de depuração por enquanto. Lá você pode ver, entre outras informações, a saída da função PrintArray para os pacotes sendo trocados. Essa saída pode evitar a necessidade de aplicar um analisador de pacotes, como o Wireshark, para verificar o conteúdo dos pacotes.

Saída do Log do MetaTrader 5 na Aba de Experts com Logs de Serviços MQTT Para Desenvolvimento e Depuração

Fig. 19 - Saída do Log do MetaTrader 5 na Aba de Experts com Logs de Serviços MQTT Para Desenvolvimento e Depuração



Conclusão

Este artigo apresenta um código funcional para compartilhar cotações em tempo real entre brokers e contas via MQTT. Embora a demonstração funcione na mesma instância e máquina do MetaTrader 5, ela demonstra a flexibilidade e robustez do MQTT. Nosso cliente nativo MQTT ainda está em desenvolvimento durante nosso tempo livre limitado. Nosso objetivo é uma versão totalmente compatível até junho, abordando desafios como a implementação do QoS_2 e das Propriedades de Usuário. Pretendemos refinar o código e torná-lo público no GitHub até o final de abril.

Convidamos contribuidores para o nosso projeto de código aberto, independentemente da experiência com MQL5. Nossa abordagem de Desenvolvimento Orientado a Testes garante um progresso sem erros, mesmo para não especialistas. Começando com testes básicos, progredimos constantemente através da documentação do MQL5. Estamos comprometidos em refinar nosso cliente até que atenda a todos os padrões MQTT.

Junte-se a nós, mesmo com habilidades básicas. Sua contribuição é valiosa. Seja bem-vindo!

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

Arquivos anexados |
mqtt-headers.zip (23.78 KB)
mqtt-services.zip (3.51 KB)
mqtt-tests.zip (19.52 KB)
Caminhe em novos trilhos: Personalize indicadores no MQL5 Caminhe em novos trilhos: Personalize indicadores no MQL5
Vou agora listar todas as possibilidades novas e recursos do novo terminal e linguagem. Elas são várias, e algumas novidades valem a discussão em um artigo separado. Além disso, não há códigos aqui escritos com programação orientada ao objeto, é um tópico muito importante para ser simplesmente mencionado em um contexto como vantagens adicionais para os desenvolvedores. Neste artigo vamos considerar os indicadores, sua estrutura, desenho, tipos e seus detalhes de programação em comparação com o MQL4. Espero que este artigo seja útil tanto para desenvolvedores iniciantes quanto para experientes, talvez alguns deles encontrem algo novo.
Rede neural na prática: O primeiro neurônio Rede neural na prática: O primeiro neurônio
Neste artigo começamos a de fato criar algo que muitos ficam admirados em ver funcionando. Um simples e singelo neurônio que conseguiremos programar com muito pouco código em MQL5.O neurônio funcionou perfeitamente nos testes que fiz. Bem, vamos voltar um pouco, nesta mesma série sobre redes neurais, para que você possa entender do que estou falando.
Está chegando o novo MetaTrader 5 e MQL5 Está chegando o novo MetaTrader 5 e MQL5
Esta é apenas uma breve resenha do MetaTrader 5. Eu não posso descrever todos os novos recursos do sistema por um período tão curto de tempo - os testes começaram em 09.09.2009. Esta é uma data simbólica, e tenho certeza que será um número de sorte. Alguns dias passaram-se desde que eu obtive a versão beta do terminal MetaTrader 5 e MQL5. Eu ainda não consegui testar todos os seus recursos, mas já estou impressionado.
Técnicas do MQL5 Wizard que você deve conhecer (Parte 15): Máquinas de Vetores de Suporte com o Polinômio de Newton Técnicas do MQL5 Wizard que você deve conhecer (Parte 15): Máquinas de Vetores de Suporte com o Polinômio de Newton
Máquinas de Vetores de Suporte classificam dados com base em classes predefinidas, explorando os efeitos de aumentar sua dimensionalidade. É um método de aprendizado supervisionado que é bastante complexo, dado seu potencial para lidar com dados multidimensionais. Neste artigo, consideramos como uma implementação muito básica de dados bidimensionais pode ser feita de maneira mais eficiente com o Polinômio de Newton ao classificar a ação do preço.