Русский Español
preview
Simulação de mercado (Parte 12): Sockets (VI)

Simulação de mercado (Parte 12): Sockets (VI)

MetaTrader 5Exemplos |
318 4
Daniel Jose
Daniel Jose

Introdução

No artigo anterior Simulação de mercado (Parte 11): Sockets (V), expliquei como você poderia criar uma aplicação em Python, que pudesse ser usada dentro do Excel. Se bem que aquela aplicação, tinha como objetivo mostrar como você poderia criar um servidor de eco no python. O grande detalhe ali, era o fato dos dados relacionados aos eventos de conexão e fechamento de conexão, serem mostrados no Excel.

Aquele servidor não é de fato de grande utilidade para nós. Principalmente pelo fato de que ele apenas permite fazermos uso, ou melhor dizendo, ele aceitar apenas e tão somente uma única conexão. De fato, um servidor cujo propósito é estabelecer apenas e somente uma única conexão, não tem grande serventia. Mas quero que você, caro leitor, não venha a focar neste detalhe. Quero que você se atente ao fato, de que o intuito ali, foi mostrar como um script feito em Python, poderia rodar no Excel. E isto de forma o mais transparente possível. Porém para o que precisamos, será preciso que o nosso servidor seja um pouco mais elaborado. E para fazer isto, precisaremos fazer algumas outras coisas.

A ideia aqui não é de fato, criar uma aplicação finalizada. Já disse e volto a repetir: Soquetes são um assunto extremamente denso e que envolve muito estudo e tempo de pesquisa. Não espere conseguir criar algo realmente seguro e perfeito, assim de uma hora para outra. Quando o assunto é soquetes, você terá realmente que se aprofundar em muitos detalhes. Alguns mais simples e outros mais complicados.

No entanto, como a nossa aplicação, a fim de conseguir uma comunicação entre o Excel e o MetaTrader 5, exige algo um pouco mais elaborado. Foi decidido que seria preciso suavizar um pouco a curva de desenvolvimento. Isto por que o intuito é mostrar para quem está começando a estudar o assunto de soquetes, como as coisas realmente podem ocorrer.

Para aqueles com mais experiência no assunto, peço desculpas se vou parecer um pouco repetitivo, ou mesmo que o artigo não venha a agregar em nada o seu conhecimento sobre o assunto. Mas para quem está começando, o conteúdo presente aqui será de grande utilidade. Principalmente pelo fato de que vamos fazer a coisa toda em Python puro.

Neste artigo não iremos de fato mexer nem com Excel, tão pouco com MQL5. Se bem que, no caso do MQL5, poderemos vir a fazer um certo uso. Para ser mais preciso, iremos fazer uso de algo que desenvolvemos aqui, nesta mesma sequência de artigos. E para que você possa entender tudo que será explicado, talvez seja bom também dar uma olhada no que foi feito em MQL5.

Se estiver interessado, olhe os seguintes artigos:

Pois foi nestes dois artigos, especificamente, que criamos o que será tema deste artigo aqui. Nos artigos acima mencionados, foi desenvolvido um Mini Chat que seria capaz de permitir que usuários no MetaTrader 5, trocasse alguma informação via texto. O detalhe, é que o código do servidor, naquele momento foi desenvolvido usando C++. Aqui vamos fazer um servidor parecido, porém desenvolvido em Python.


Entendendo algumas coisas antes

A transformação de um servidor de eco, um servidor de mini chat. A primeira vista não parece ser algo muito complicado. E mesmo a transformação de um servidor de eco em um do tipo que precisamos a fim de fazer o Excel e o MetaTrader 5, se comunicarem. Também não é uma das tarefas mais complicadas. Isto para quem realmente já tem as bases e conhecimento adequado para efetuar tal tarefa. No entanto, quando o assunto é soquetes, e principalmente uso de soquetes por diversos clientes ao mesmo tempo em um mesmo servidor. A coisa começa a mudar um pouco de figura. Isto por que muitos, principalmente quem está começando, não faz ideia do que realmente é preciso ser feito.

Então vamos voltar ao código, em Python visto no artigo anterior. Este pode ser visto logo abaixo, para que você entenda melhor a explicação.

01. import socket
02. import xlwings as xw
03. 
04. def Echo():
05.         wb = xw.Book.caller()
06.         server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
07.         server.bind(("127.0.0.1", 27015))
08.         wb.sheets[0]['A1'].value = "Waiting connection..."
09.         server.listen(1)
10.         client, addr = server.accept()
11.         client.send("Wellcome to Server in Python\n\r".encode())
12.         wb.sheets[0]['A2'].value = str(f"Client connected by {addr}")
13.         while True:
14.             info = client.recv(512)
15.             if not info:
16.                 break
17.             client.send(b"Echo Server:" + info)
18.         wb.sheets[0]['A3'].value = "Client disconnected"
19.         client.close()

Servidor em Python

Apesar deste código não ser funcional, sem o que foi mostrado no artigo anterior, podemos fazer com que ele passe a ser funcional. E mesmo assim, permitir que ele possa vir a ser usado depois, sendo um módulo. Para fazer tais mudanças será necessário remover algumas coisas do código. Isto pensando em não fazer uso do Excel junto do Python. Então o código ficaria como mostrado abaixo:

01. import socket
02.  
03. def Echo():
04.     server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
05.     server.bind(("127.0.0.1", 27015))
06.     server.listen()
07.     client, addr = server.accept()
08.     client.send("Wellcome to Server in Python\n\r".encode())
09.     while True:
10.         info = client.recv(512)
11.         if not info:
12.             break
13.         client.send(b"Echo Server:" + info)
14.     client.close()
15. 
16. if __name__ == "__main__":
17.     Echo()

Servidor em Python

Ok. Se você já tem alguma base em Python é capaz de perceber o que aconteceu aqui. Mas se você não tem conhecimento sobre Python, deve estar pensando: Mas que doideira é esta? Na verdade, não é nenhuma doideira. O que aconteceu aqui foi que o código anterior, que não podia ser executado diretamente pelo interpretador do Python, agora poderá ser executado. Tudo isto apenas por que foi adicionado as linhas 16 e 17. Mas ao mesmo tempo, este mesmo código continua sendo possível ser usado em um módulo. Isto justamente por conta das linhas 16 e 17.

Mas não é isto que realmente nos interessa aqui. Onde o assunto é como tornar este código visto acima. Que a princípio, não permite que diversos clientes se conectem a ele, passe a permitir que isto ocorra.

Ok. Se você, caro leitor, aspirante a ser um utilizador de soquetes em suas implementações, estudou o material que coloquei como referência nos artigos anteriores. Já deve entender alguns detalhes e problemas neste código visto acima. Isto por que este código, é de fato, voltado a aceitar apenas e somente uma única conexão por vez. Mas como assim? O motivo é que a função accept, presente na linha sete, uma vez executada, não será executada novamente. Isto impede de que mais clientes venham a se conectar. E mesmo que o mesmo cliente, fechar a conexão, ele não conseguirá se conectar novamente.

O motivo, novamente é o fato de que a função accept, não será executada novamente. Então será que poderíamos colocar um outro laço neste código? Isto para que o conteúdo entre as linhas sete e 14 viesse a ser executado novamente, caso o cliente resolva voltar? Sim, podemos fazer isto. E de fato em alguns casos mais simples, é o que um programador realmente faz. Mas, vamos pensar um pouco além disto. Pois se esta solução for feita, ainda assim teremos apenas e somente um único cliente conectado. E para o nosso propósito de mini chat isto não seria o suficiente.

Além deste problema existe um outro. Se você chegou a testar o que foi mostrado nos dois artigos anteriores, deve ter notado que o Excel fica quase inacessível quando o servidor estiver em uso. Os artigos mencionados são os seguintes:

Isto para quem não os leu. Agora vem a pergunta: Por que o Excel fica difícil de ser utilizado quando o servidor de eco está em funcionamento? Bem, para responder esta pergunta, é preciso entender algumas coisas que estão ocorrendo no código do servidor. Lembre-se do seguinte fato, o Excel chama via VBA o código em Python para ser executado. Uma vez que o código em Python inicia, ele passa a competir com o uso da CPU junto com o Excel.

Para o sistema operacional, o código em Python, não é um processo em separado. Ele na verdade seria um tipo de thread do Excel. Esta palavra thread, de fato não seria a mais adequada de ser usada aqui. Visto que uma thread de fato, não irá competir com o programa principal no uso da CPU. Mas como ao desligar o Excel, o código em Python morre junto. Podemos usar, com o devido cuidado a palavra thread aqui. Mas cuidado com esta palavra, e o motivo será explicado um pouco mais a frente.

Mas é justo perguntar, por que o código em Python, competirá o uso da CPU, quando o Excel tiver uma janela de tempo para usar a CPU. O motivo são dois pontos no código. Então voltemos ao código original do servidor eco. Observem que na linha 10 temos uma chamada a função accept. Pois bem, esta função é uma função bloqueante. Ou seja, quando ele for executado, o código irá parar naquele ponto e não prosseguirá até que alguma conexão ocorra. Esta função é o primeiro ponto de gargalo, ou melhor dizendo, é o primeiro ponto em que o script em Python, competirá com o Excel no uso da CPU.

Muito bem, uma vez que uma conexão ocorra temos um segundo problema. E é justamente na linha 14, onde novamente o script em Python ficará competindo com o Excel. Esta competição irá de fato ocorrer a cada interação com a linha 14. Assim o Excel receberá menos atenção do que o script em Python. Ficando o Excel, difícil de ser utilizado durante o funcionamento do servidor.

Mas existe alguma forma de resolvermos isto? Sim. Existem algumas formas de se promover uma solução para esta situação. A primeira é fazer com que o script em Python, de fato venha a ser uma thread real do Excel. Fazendo isto, quando o Excel entrar na sua janela de execução, tanto o Excel, quanto o script em Python, não irão mais competir pelo uso da CPU. Isto por que o sistema operacional ajustará as coisas de maneira que cada um receba uma fração de tempo. Ou em casos de CPU multicore, o sistema operacional pode permitir que o Excel use um core e o script em Python use outro core. Mas para que isto de fato venha a ocorrer, é preciso que o Excel, diga ao sistema operacional que o script em Python será uma thread.

Mas em fim, o que é esta tal de thread, de que você está falando?  Para entender isto, vamos a um novo tópico.


Entendendo o que é uma thread

Uma thread, a grosso modo dizendo, seria como se fosse um outro programa dentro de um programa principal. De fato isto é uma forma grosseira de descrever uma thread. A thread, somente existe, enquanto o programa principal existir. Uma vez que o programa principal, no nosso caso o Excel, deixar de existir, qualquer coisa ligada a ele morre junto.

Este conceito de thread, nasceu com o surgimento do que muitos conhecem como processamento paralelo. Na verdade uma thread serve justamente para isto. Ela ajuda o programa principal e fazer algum tipo de tarefa que seria muito difícil ser programada diretamente dentro do código principal. Então para ajudar você coloca esta parte do código, em um fragmento de código, que será executada de forma paralela ao que o programa principal esteja fazendo.

Assim que a thread terminar o seu trabalho, o programa principal poderá fazer uso dos dados calculados ou buscados. Estes estarão presentes na área que você reservou. É um forma bastante curiosa de programação. Isto por que, quando usamos uma thread, você pode fazer algo, enquanto a thread, permite que o programa principal continue funcionando. Mesmo que a tarefa que foi mandada para a thread demore alguns minutos para ser completada.

Tal coisa em Python é bastante interessante. Assim como em outras linguagens. Porém é preciso realmente ver a coisa funcionando para que você entenda o que está acontecendo. E qual é a vantagem em se usar uma thread. Pois bem, para não deixar as coisas assim sem algum tipo de código. Vamos ver um caso de uso de thread em Python.

01. import socket as sock
02. import threading as thread
03. 
04. def NewClientHandler(conn, addr):
05.     print(f"Client [%s:%s] is online..." % addr)
06.     while True:
07.         msg = conn.recv(512).decode().rstrip(None)
08.         if msg:
09.             print(f"Message from [%s:%s]: {msg}" % addr)
10.             if msg.lower() == "/see you later":
11.                 break
12.     print(f"Client [%s:%s] is disconnected..." % addr)
13.     conn.close()
14. 
15. server = sock.socket(sock.AF_INET, sock.SOCK_STREAM)
16. server.bind(('localhost', 27015))
17. server.listen()
18. print("Waiting connections...")
19. while True:
20.     conn, addr = server.accept()
21.     conn.send("Wellcome to Server.\n\r".encode())
22.     thread.Thread(target=NewClientHandler, args=(conn, addr)).start()

Servidor em Python

Este servidor, cujo código é visto acima, faz uso de thread a fim de conseguir lidar com mais de um cliente ao mesmo tempo. Preste atenção em algumas coisas aqui. Primeiro, este servidor não repassará a informação dada por um cliente a todos, os demais. Segundo este servidor é apenas para demonstrar o uso de thread. Tendo assim um propósito didático. Mas se você entender o que está acontecendo, poderá fazer muitas coisas interessantes. Isto apenas modificando o código acima.

Mas vamos entender o que está acontecendo neste código. Novamente se você já sabe Python, tenha paciência com os novos programadores. Lembre-se de que você não nasceu sabendo, alguém lhe ensinou, ou você aprendeu por meio de documentos que outros escreveram. Então paciência.

Na linha um importamos o pacote de soquetes, note que estou declarando a coisa de uma forma ligeiramente diferente. Já na linha dois, importamos o pacote para nos permitir criar threads. Assim como foi feita na linha um, aqui também temos algo estranho. Mas não se assuste. O que estou fazendo é criando um alias para fazer as coisas no Python de uma forma mais agradável a fim de que você consiga entender o código.

Entre as linhas quatro e 13 temos um procedimento. Por hora vamos deixar este procedimento de lado. E vamos direto para a linha 15. Observe com os códigos anteriores visto neste mesmo artigo, que entre as linhas 15 e 18, o código é praticamente igual. Esta parte é a responsável por criar o soquete no servidor. Por isto o código é igual. Um detalhe: Nestes exemplos estamos usando o protocolo TCP. Mas lembre-se que existem outros protocolos de rede. Então o código pode variar um pouco de servidor para servidor. Principalmente devido a algumas coisas que veremos depois.

De qualquer forma, na linha 18, informamos que o servidor está pronto para receber conexões. Lembra do fato que mencionei anteriormente, onde colocaríamos um laço antes da chamada accept? Pois bem, aqui estamos fazendo justamente isto. Então mesmo que o cliente se desconecte, ele conseguirá se reconectar ao servidor. Isto por que o laço permitirá mais de uma interação com a chamada accept. Agora vamos relembrar um detalhe. A chamada accept bloqueia o código, e o faz ficar esperando que uma conexão aconteça. Quando isto ocorrer, teremos a execução da linha 21 que enviará ao novo cliente uma mensagem básica. Isto para que o cliente saiba que a conexão aconteceu. Logo depois na linha 22 temos a criação da thread em Python.

Agora a coisa realmente fica interessante. E é neste ponto que temos algo bastante importante. Se no lugar desta mesma linha 22 colocarmos o código que está entre a linha quatro e a linha 13. Teremos um funcionamento completamente diferente do servidor. Isto por que o código deixará de permitir mais de uma conexão, e passará a aceitar apenas e somente uma única conexão.

Mas espera um pouco. Como assim? Para entender isto, você precisa compreender que a linha 22, não é uma linha mágica. Ela na verdade é uma linha que está chamando o procedimento que está na linha quatro. Porém existe um detalhe, que é justamente o que faz toda a diferença entre uma chamada que se tornará uma thread e uma que não será uma thread. O detalhe é que uma vez que a chamada será uma thread, assim como é visto aqui neste código. O sistema operacional passará a fazer o seguinte: Ele pegará o código da thread, alocar ele na memória. E logo depois fará com que o tempo, ou janela de execução do nosso código principal, seja dividido entre o código e a thread.

Talvez isto seja um pouco confuso, de entender no começo. Mas pense da seguinte forma: A janela de tempo que o sistema operacional dá a um programa, seria como uma barra de doce. Quando o programa não tem nenhuma thread, ele pode consumir toda a barra. Porém, quando ele começa a ter threads, esta barra será dividida em pedaços cada vez menores. Assim o programa principal somente poderá consumir um destes pedaços. Todos demais pedaços serão consumidos pelas threads. Esta seria uma explicação bastante simples, considerando que você tivesse uma CPU com apenas um core.

Muito bem, voltando ao nosso código, assim que a linha 22 for executada, o programa se "dividirá" em dois. Uma parte voltará imediatamente para a linha 19, onde voltaremos a cair na espera da linha 20. Lembrando que a função accept bloqueará o código impedido de ele continuar a executar. E uma outra parte irá ser direcionada para a linha quatro.

Ok. Agora fiquei realmente confuso. Como o código da linha quatro funcionará, se o código será bloqueado na linha 20? Isto é muito confuso para mim. Calma meu caro leitor. Não é motivo para confusão. Lembre-se do exemplo da barra de doce. De fato o código principal ficará bloqueado na linha 20, esperando que um novo cliente venha a se conectar. Mas também, teremos a execução do código entre as linhas quatro e 13. Isto independentemente de um novo cliente conectar ou não. O grande detalhe, é que o servidor, passará a ouvir o que o cliente conectado está informando. Por conta disto entramos em um novo loop na linha seis. Preste muita atenção a isto. Pois se você não entender esta parte ficará completamente sem direção no que se refere a threads.

Este loop que se inicia na linha seis e vai até a linha onze. Estará apenas e somente na thread. E cada cliente, e isto que é importante entender. Cada cliente conectado, terá o seu próprio loop. Então mesmo que dois ou mais clientes, estejam conectados. Um não irá de forma alguma interferir no loop de outro. Agora pense isto, como se cada cliente tivesse um servidor só para ele. Ou seja, cada cliente conectado, ou que vier a se conectar estará criando um servidor para ele. E este servidor responderá somente a este cliente.

Esta é a mágica do thread. Mas nem tudo é uma perfeita maravilha. Existem alguns problemas no uso das threads. Mas muitos destes problemas surgem justamente quando você, como programador, começa a fazer um uso indiscriminado de thread. Você deve sempre pensar que uma thread tomará uma fatia de tempo do programa principal. Mesmo quando aparentemente existe uma execução em paralelo. Isto por que, por mais cores de sua CPU contenha, eles não serão infinitos. Porém, o uso indiscriminado de threads podem consumir todos os cores disponíveis. E quando isto ocorrer, o tempo de execução pode aumentar. Diminuindo assim a vantagem em se usar threads.

Agora você pode estar confuso sobre uma outra questão. Apesar deste código acima conseguir lidar com diversos clientes, ele não permite que os clientes se comuniquem entre si. Será que ao usar threads não podemos transferir informações entre clientes? Bem, se você pensou assim, significa de que fato você não entende muito sobre threads. Mas não se sinta mal por isto. Pelo contrário. Você deve se sentir feliz, por se questionar isto. Pois se você olhando o código e lendo o artigo pensou isto. Significa de fato, que você entendeu a explicação do funcionamento do servidor. Mas lhe surgiu a dúvida, significando que você ainda não sabe muito sobre thread. Então vamos solucionar esta sua dúvida. Mas para separar as coisas, vamos ver isto em um outro tópico.


Transferindo informações em clientes mantidos por thread

Para entender como isto acontece, é preciso que você tenha entendido o que acontece antes deste ponto. Caso você não tenha compreendido os tópicos anteriores, volte e os leia novamente. É importante entender eles, caso contrário, você irá se confundir ainda mais neste tópico daqui. Que apesar de ser relativamente curto, pode lhe deixe muito confuso. E pior, sem entender nada do que está acontecendo.

Então vamos ver o código.

01. import socket as sock
02. import threading as thread
03. 
04. CONN_LIST = []
05. 
06. def NewClientHandler(conn, addr):
07.     global CONN_LIST
08.     CONN_LIST.append(conn)
09.     print(f"Client [%s:%s] is online..." % addr)
10.     while True:
11.         msg = conn.recv(512).decode().rstrip(None)
12.         if msg:
13.             print(f"Message from [%s:%s]: {msg}" % addr)
14.             for slave in CONN_LIST:
15.                 if slave != conn:
16.                     slave.send(f"[{addr[0]}]: {msg}\n\r".encode())
17.             if msg.lower() == "/see you later":
18.                 break
19.     print(f"Client [%s:%s] is disconnecting..." % addr)
20.     conn.close()
21.     CONN_LIST.remove(conn)
22. 
23. server = sock.socket(sock.AF_INET, sock.SOCK_STREAM)
24. server.bind(('0.0.0.0', 27015))
25. server.listen()
26. print("Waiting connections...")
27. while True:
28.     conn, addr = server.accept()
29.     conn.send("Wellcome to Server.\n\r".encode())
30.     thread.Thread(target=NewClientHandler, args=(conn, addr)).start()

Servidor em Python

Mas, o que é isto? Cara você apenas adicionou umas poucas linhas de código. Você tem certeza de que este código permite que clientes enviem informações um para os outros? Sim. Eu garanto que este código consegue além de enviar informações entre os clientes, que o servidor consiga mostrar estas mesmas mensagens. Isto para quem estiver olhando o prompt de comando onde o servidor estiver rodando.

Porém existe um detalhe neste código. As mensagens mais antigas não estarão disponíveis. Ou seja, só receberá mensagens postadas, quem realmente estiver conectado ao servidor naquele momento. Mas como isto acontece de fato. Pois estou olhando o código e não estou conseguindo entender bulhufas.

Para entender como este servidor consegue transferir as mensagens postadas, para outros clientes. É preciso você entender como uma thread funciona. Isto foi explicado no tópico anterior. Considerando que você entendeu o funcionamento de uma thread. Podemos então entender como elas se comunicam. Pois é isto mesmo. Para que a thread possa passar as postagens para outros clientes, é preciso que elas, threads, troquem informações. Mas como isto se dá? No caso mais simples de todos, isto acontece fazendo uso de uma parte compartilhada da memória. E esta parte compartilhada é justamente declarada na linha quatro. Ou seja, esta lista declarada na linha quatro, será vista por todas as threads.

Para que isto aconteça sem grandes problemas, dentro da thread, na linha sete, dizemos que a lista é global. Isto para que o Python, não venha a criar a lista localmente. Se o Python criar a lista localmente, a memória não será compartilhada entre as threads. E precisamos que ela seja. Ok, então na linha oito, adicionamos a conexão que criou a thread a nossa lista. Este passo é importante. Já que cada nova conexão, criará uma nova thread, que adicionará um novo valor na lista.

Muito bem, quando a linha 11 for ser executada ela bloqueará esperando receber algum dado da conexão. Isto acontecerá em todas as threads individualmente. Assim que um cliente passar algo ao servidor, iremos na linha 14 entra em um pequeno laço. Este é o ponto onde a mágica acontece. Observe que varreremos a lista de conexões. Esta foi criada pelas threads de forma individual. Porém o laço ignora isto, já que a memória, está sendo compartilhada entre as threads. Assim ele conseguirá varrer todas as conexões. Uma a uma.

Quando a condição na linha 15 for falsa, ou seja, a conexão corresponde exatamente a conexão da thread do laço, não faremos nada. Porém, quando este teste for verdadeiro, teremos a execução da linha 16. Esta enviará para a conexão que está sendo, observada por outra thread, o que a conexão desta thread aqui recebeu. Não sei se ficou claro esta parte. Mas cada thread, corresponde a uma conexão. Quando uma conexão recebe dados, ela fará com que o laço repasse para cada uma das demais conexões o dado recebido. Porém isto não fará com que as outras threads disparem.

Mas espera um pouco. Como assim? Se uma thread envia dados as outras conexões, isto deveria fazer com que as demais threads dispararem. Não, meu caro leitor. Pensar assim, é um equívoco. Não em sua totalidade. Mas pelo fato de que você está se esquecendo do seguinte fato: O servidor NÃO ouve o que se passa nas threads. Ele, o servidor, ouve o que se passa nos clientes. No que rege cada cliente, ele imagina estar ligado única e exclusivamente a um servidor dedicado. O cliente não tem a devida noção de que está dentro de uma thread.

Para finalizar, quando o cliente se desconecta, na linha 21, que foi adicionada, removemos a identidade da conexão da lista. Desta maneira, todas as demais threads não mais verão esta conexão que acabou de ser fechada.


Considerações finais

Apesar de parecer muito confuso o que foi visto neste artigo. Este assunto sobre threads é tão, ou talvez até mais denso que o assunto sobre soquetes. Porém, esta solução que usa threads, é apenas uma entre tantas outras possíveis. No próximo artigo abordarei uma outra forma de solucionar este problema. Já que esta solução via thread não resolve o problema do Excel. Isto por que ainda temos a questão da função accept. Esta bloqueia o servidor fazendo com que a experiência do uso do Python no Excel não seja tão agradável. Pelo menos para nós que precisamos dos soquetes.

ArquivoDescrição
Experts\Expert Advisor.mq5
Demonstra a interação entre o Chart Trade e o Expert Advisor ( É necessário o Mouse Study para interação )
 Indicators\Chart Trade.mq5Cria a janela para configuração da ordem a ser enviada   ( É necessário o Mouse Study para interação )
 Indicators\Market Replay.mq5Cria os controles para interação com o serviço de replay / simulador   ( É necessário o Mouse Study para interação )
 Indicators\Mouse Study.mq5Permite interação entre os controles gráficos e o usuário ( Necessário tanto para operar o replay simulador, quanto no mercado real )
 Services\Market Replay.mq5Cria e mantém o serviço de replay e simulação de mercado ( Arquivo principal de todo o sistema )
 Code VS C++\Servidor.cppCria e mantém um soquete servidor criado em C++ ( Versão Mini Chat )
 Code in Python\Server.pyCria e mantém um soquete em python para comunicação entre o MetaTrader 5 e o Excel
 Scripts\CheckSocket.mq5Permite efetuar um teste de conexão com um soquete externo
 Indicators\Mini Chat.mq5Permite implementar um mini chat via indicador ( Necessário uso de um servidor para funcionar )
 Experts\Mini Chat.mq5Permite implementar um mini chat via Expert Advisor ( Necessário uso de um servidor para funcionar )
Arquivos anexados |
Anexo.zip (560.03 KB)
Últimos Comentários | Ir para discussão (4)
Levison Da Silva Barbosa
Levison Da Silva Barbosa | 23 mar. 2025 em 12:47
Gostaria de expressar minha profunda gratidão pelo conhecimento e sabedoria que compartilha aqui.
Roman Shiredchenko
Roman Shiredchenko | 18 nov. 2025 em 11:44

Obrigado pelas informações... como os soquetes podem ajudar a conectar dois terminais MT5 de corretoras diferentes? em um forex no outro moex - a negociação emparelhada de dois terminais pode ser realizada por meio de soquetes?

Eu mesmo estou pesquisando esse tópico... desculpe-me antecipadamente se minha pergunta estiver um pouco fora do assunto.... Ainda estou lendo artigos e procurando soluções para dois MT5 negociando em conjunto e obtendo cotações de símbolos de diferentes bolsas em essência e negociando em conjunto depois de analisar dados sobre cotações de 2-3-4-5 símbolos.....

Estarei fazendo o socketing:

  • Troca entre terminais: os dados vão diretamente entre o MT5 A e o MT5 B.

  • Eventos: OnSocketEvent() é acionado instantaneamente quando os dados são recebidos.

  • Flexibilidade de dados: JSON, estruturas binárias e matrizes podem ser transferidos.

  • Velocidade: a latência é uma ordem de magnitude menor do que o polling variável.

  • Confiabilidade: há mecanismos para reenvio e confirmação.

Nesse contexto, estou planejando criar um servidor Python avançado com cálculo de propagação, ACK/NACK, armazenamento de estados de posição e interface da Web para monitoramento;

// Terminal A
string msg = "{\"cmd\":\"OPEN\", \"symbol\":\"USDRUBF\", \"volume\":1.0}";
SocketSend(socket, msg);

// Terminal B
string cmd;
SocketReceive(socket, cmd);  // Obteve a estrutura completa do sinal
Daniel Jose
Daniel Jose | 18 nov. 2025 em 21:40
Roman Shiredchenko a negociação emparelhada de dois terminais pode ser realizada por meio de soquetes?

Eu mesmo estou pesquisando esse tópico... desculpe-me antecipadamente se minha pergunta estiver um pouco fora do assunto.... Ainda estou lendo artigos e procurando soluções para dois MT5 negociando em um soquete e obtendo cotações de símbolos de diferentes bolsas em essência e negociando em um soquete depois de analisar dados sobre cotações de 2-3-4-5 símbolos....

Estarei fazendo um socket:

  • Troca entre terminais : os dados vão diretamente entre o MT5 A e o MT5 B.

  • Eventos : OnSocketEvent() é acionado instantaneamente quando os dados são recebidos.

  • Flexibilidade de dados : JSON, estruturas binárias e matrizes podem ser transmitidos.

  • Velocidade : a latência é uma ordem de magnitude menor do que a sondagem variável.

  • Confiabilidade : há mecanismos de reenvio e confirmação.

Nesse contexto, estou planejando criar: um servidor Python avançado com cálculo de propagação, ACK/NACK, armazenamento de estados de posição e interface da Web para monitoramento;

Sua pergunta é relevante e interessante. Mas acho que você está tirando conclusões precipitadas. Deixe-me esclarecer: embora a MQL5 implemente soquetes, como explico em meus artigos, ela não permite a criação de um servidor. Somente um cliente. Portanto, muito do que você está planejando fazer é impossível. É IMPOSSÍVEL de ser implementado na MQL5. Você precisará de código externo. No seu caso, você menciona o uso do Python, que já é uma solução em si.

De fato, muito do que você precisa pode ser implementado em Python. No entanto, há um pequeno problema com o que você está tentando fazer: interagir diretamente com o corretor. Por que estou dizendo isso? Por motivos de segurança, os corretores geralmente não aceitam acesso por meio de soquetes. Há um protocolo especial para essa interação, projetado especificamente para evitar interrupções nos mecanismos internos do corretor. Mas não é impossível tentar. Eles podem lhe informar o protocolo de comunicação para que você possa acessá-lo quando for conveniente. Mas não pense que isso será fácil, a menos que você tenha um amigo MUITO próximo na corretora que possa lhe fornecer as informações de que você precisa.

Outro aspecto que chamou minha atenção foi a interação e a troca de informações entre duas instâncias diferentes do MetaTrader 5. Na minha humilde opinião, o que você está tentando fazer não é uma boa ideia. Você não entende alguns conceitos de programação paralela e problemas relacionados. Se não se importar, tente estudar a tarefa "produtor-consumidor". Ela o ajudará a entender o nível de complexidade e as armadilhas que você pode encontrar ao transferir informações entre diferentes instâncias do MetaTrader 5 para fins de negociação.

De qualquer forma, boa sorte com seu projeto 🙂👍

Roman Shiredchenko
Roman Shiredchenko | 19 nov. 2025 em 08:32
Daniel Jose #:

Sua pergunta é relevante e interessante. Mas acho que você está tirando conclusões precipitadas. Deixe-me esclarecer: embora a MQL5 implemente soquetes, como explico em meus artigos, ela não permite que você crie um servidor. Somente um cliente. Portanto, muito do que você está planejando fazer é impossível. É IMPOSSÍVEL ser implementado na MQL5. Você precisará de código externo. No seu caso, você menciona o uso do Python, que já é uma solução em si.

De fato, muito do que você precisa pode ser implementado em Python. No entanto, há um pequeno problema com o que você está tentando fazer: interagir diretamente com o corretor. Por que estou dizendo isso? Por motivos de segurança, os corretores geralmente não aceitam acesso por meio de soquetes. Há um protocolo especial para essa interação, projetado especificamente para evitar interrupções nos mecanismos internos do corretor. Mas não é impossível tentar. Eles podem lhe informar o protocolo de comunicação para que você possa acessá-lo quando for conveniente. Mas não pense que isso será fácil, a menos que você tenha um amigo MUITO próximo na corretora que possa lhe fornecer as informações de que você precisa.

Outro aspecto que chamou minha atenção foi a interação e a troca de informações entre duas instâncias diferentes do MetaTrader 5. Na minha humilde opinião, o que você está tentando fazer não é uma boa ideia. Você não entende alguns conceitos de programação paralela e problemas relacionados. Se não se importar, tente estudar a tarefa "produtor-consumidor". Isso o ajudará a entender o nível de complexidade e as armadilhas que você pode encontrar ao transferir informações entre diferentes instâncias do MetaTrader 5 para fins de negociação.

De qualquer forma, boa sorte com seu projeto 🙂👍

MUITO OBRIGADO pelo feedback que você forneceu..... não tenho amigos nas corretoras!!! ) tenho terminais MT5 em duas corretoras diferentes! preciso torná-los amigos..... ) esse é um projeto para o próximo ano!!!

aqui - tentando... obrigado pelos artigos - estou lendo-os e estudando o conteúdo!!! se a velocidade permitir - então talvez eu faça isso diretamente através dos arquivos... acesso - como os discos rígidos anteriores conectados no BIOS em duas partes: um mestre e um escravo... )

Então aqui... em um computador potente, dois terminais MT5, um mestre (o principal) e o outro escravo (o segundo), em um deles a bolsa de valores e no outro o MT5 forex! talvez a realização por meio de arquivos), a leitura e a gravação serão suficientes... mas eu gostaria de implementar uma variante de leitura e recebimento de dados mais rápida e fácil.... por tipo de variáveis globais do terminal do cliente (não uso arquivos - há muito tempo), mas as variáveis globais do terminal do cliente são visíveis somente nesse terminal..... você precisa conectar processos externos... talvez criar tabelas na memória... como as bibliotecas de dll de conexão que eu vou perceber!

Tenha um bom dia!

Auto-otimização de take-profits e parâmetros do indicador usando SMA e EMA Auto-otimização de take-profits e parâmetros do indicador usando SMA e EMA
Este artigo apresenta um EA avançado para negociação no mercado Forex, que combina aprendizado de máquina com análise técnica. Ele é projetado para operar ações da Apple por meio de otimização adaptativa, gerenciamento de risco e múltiplas estratégias. Testes com dados históricos têm apresentado resultados promissores, embora também tenham evidenciado retrações significativas, indicando potencial para melhorias adicionais.
Do básico ao intermediário: Indicador (II) Do básico ao intermediário: Indicador (II)
Neste artigo veremos como implementar o calculo de média móvel e os cuidados a serem tomados ao efetivamente criar este calculo. Além disto, vamos também falar sobre a sobrecarga da função OnCalculate a fim de podemos saber quando e como trabalhar com um ou outro modelo de sobrecarga.
Reimaginando Estratégias Clássicas (Parte V): Análise de Múltiplos Símbolos no USDZAR Reimaginando Estratégias Clássicas (Parte V): Análise de Múltiplos Símbolos no USDZAR
Nesta série de artigos, revisitamos estratégias clássicas para verificar se podemos melhorá-las usando IA. No artigo de hoje, examinaremos uma estratégia popular de análise de múltiplos símbolos utilizando uma cesta de ativos correlacionados. Focaremos no par de moedas exótico USDZAR.
Funcionalidades do Assistente MQL5 que você precisa conhecer (Parte 31): Escolha da função de perda Funcionalidades do Assistente MQL5 que você precisa conhecer (Parte 31): Escolha da função de perda
A função de perda (Loss Function) é uma métrica fundamental nos algoritmos de aprendizado de máquina, que fornece feedback para o processo de aprendizado ao quantificar o quão bem um determinado conjunto de parâmetros se comporta em comparação com o valor-alvo esperado. Vamos explorar os diferentes formatos dessa função na classe personalizada do Assistente MQL5.