Atualmente, tento configurar uma arquitetura Push-Pull-Socket simples usando zeroMQ enquanto o Metatrader 4 (MQL) atua como publisher
e meu back-end Python atua como consumer
.
Eu envio dados do terminal Metatrader 4 a cada segundo, o que funciona muito bem. No entanto, estou tendo dificuldades para receber dados no soquete pull . Uma vez que tento extrair esses dados da rede, o script
pacote atom gera o erro address already in use
.
Eu executo o terminal MT 4 e o script Python na minha máquina local durante o desenvolvimento.
Metatrader 4:
extern string PROJECT_NAME = "Dashex.Feeder";
extern string ZEROMQ_PROTOCOL = "tcp";
extern string HOSTNAME = "*";
extern int PUSH_PORT = 32220;
extern string t0 = "--- Feeder Parameters ---";
input string DID = "insert your DID here";
extern string t1 = "--- ZeroMQ Configuration ---";
extern bool Publish_MarketData = false;
// ZeroMQ environment //
// CREATE ZeroMQ Context
Context context(PROJECT_NAME);
// CREATE ZMQ_PUSH SOCKET
Socket pushSocket(context, ZMQ_PUSH);
string Publish_Symbols[7] = {
"EURUSD","GBPUSD","USDJPY","USDCAD","AUDUSD","NZDUSD","USDCHF"
};
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
EventSetTimer(1); // Set Millisecond Timer to get client socket input
context.setBlocky(false);
// Send responses to PULL_PORT that client is listening on.
Print("[PUSH] Connecting MT4 Server to Socket on Port " + IntegerToString(PUSH_PORT) + "..");
pushSocket.connect(StringFormat("%s://%s:%d", ZEROMQ_PROTOCOL, HOSTNAME, PUSH_PORT));
pushSocket.setSendHighWaterMark(1);
pushSocket.setLinger(0);
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
Print("[PUSH] Disconnecting MT4 Server from Socket on Port " + IntegerToString(PUSH_PORT) + "..");
pushSocket.disconnect(StringFormat("%s://%s:%d", ZEROMQ_PROTOCOL, HOSTNAME, PUSH_PORT));
// Shutdown ZeroMQ Context
context.shutdown();
context.destroy(0);
EventKillTimer();
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTimer()
{
/*
Use this OnTimer() function to send market data to consumer.
*/
if(!IsStopped() && Publish_MarketData == true)
{
for(int s = 0; s < ArraySize(Publish_Symbols); s++)
{
// Python clients can subscribe to a price feed by setting
// socket options to the symbol name. For example:
string _tick = GetBidAsk(Publish_Symbols[s]);
Print("Sending " + Publish_Symbols[s] + " " + _tick + " to PUSH Socket");
ZmqMsg reply(StringFormat("%s %s", Publish_Symbols[s], _tick));
pushSocket.send(reply, true);
}
}
}
//+------------------------------------------------------------------+
string GetBidAsk(string symbol) {
MqlTick last_tick;
if(SymbolInfoTick(symbol,last_tick))
{
return(StringFormat("%f;%f", last_tick.bid, last_tick.ask));
}
// Default
return "";
}
O envio de dados funciona como pretendido:
Soquete pull baseado em Python:
import zmq
import time
context = zmq.Context()
zmq_socket = context.socket(zmq.PULL)
zmq_socket.bind("tcp://*:32220")
time.sleep(1)
while True:
result = zmq_socket.recv()
print(result)
time.sleep(1)
Isso é o que script
relata no console:
Saída Netstat:
Observação: quando eu encerro o script push do Metatrader e o script python, a porta ainda está marcada como "ouvida" no netstats. Quando mudo a porta para 32225 (ou qualquer outra) em ambas as instâncias e as executo novamente, recebo o mesmo erro novamente. Se eu executar a instância pull pela primeira vez, tenho uma ampulheta surgindo no átomo script
, quando eu executo a instância push MT4 nada acontece no lado pull. Quando executo novamente a instância pull, recebo o mesmo erro novamente.
Atualizar:
A python.exe
instância em segundo plano ocupou a porta. Desliguei a execução do python e a porta foi liberada novamente. Quando agora executo minha instância pull, recebo o seguinte feedback do console:
1.)
2.)
Em seguida, executo a instância push, que funciona perfeitamente.
3.)
A instância pull ainda mostra a ampulheta e não imprime nenhum dado no console:
4.)
Quando eu executo novamente a instância pull, ela levanta o endereço de erro em uso, o que agora faz sentido, já que o Python usa aquela porta ainda em segundo plano.
Mas por que nenhum dado é impresso no lado de puxar? Tenho que alterar o código do cliente pull para poder "pegar" os dados enviados?
O problema é com seu PUSH
código, aqui:
extern string HOSTNAME = "*";
Embora você possa usar legitimamente *
para o componente do nome do host em um bind
URL (nesse caso, significa "ouvir em todos os endereços"), não faz sentido em uma connect
chamada: você deve fornecer um nome de host ou endereço IP válido.
Se você modificasse seu código para ler:
extern string HOSTNAME = "localhost";
Provavelmente funcionaria como esperado.
Aqui está um PUSH
cliente Python simples que usei para testar seu PULL
código; se você executar isso e executar seu PULL
código (conforme postado em sua pergunta), tudo funcionará:
import time
import zmq
c = zmq.Context()
s = c.socket(zmq.PUSH)
s.connect('tcp://localhost:32220')
i = 0
while True:
s.send_string('this is message {}'.format(i))
i += 1
time.sleep(0.5)
Este artigo é coletado da Internet.
Se houver alguma infração, entre em [email protected] Delete.
deixe-me dizer algumas palavras