IVlad
IVlad

Reputation: 43517

MQL5 Zmq PUB socket not being received by Python zmq SUB socket

I'm trying to set up a PUB socket in MQL5 and a SUB socket in Python that will receive messages.

I have this in MQL5:

#include <Zmq/Zmq.mqh>

Context context("helloworld");
Socket socket(context,ZMQ_PUB);

string BROKER;

int OnInit()
{
   if (socket.bind("tcp://*:5556"))
   {
       Print("Error");
   }
   else
       Print("Bound");
   BROKER = AccountInfoString(ACCOUNT_COMPANY);
   return(INIT_SUCCEEDED);
}

void OnTick()
{  
   MqlTick last_tick; 
   string str;
   if(SymbolInfoTick(Symbol(),last_tick)) 
   { 
      StringConcatenate(str, BROKER, ",", Symbol(), ",", last_tick.time_msc, ",", last_tick.ask, ",", last_tick.bid, ",", last_tick.last, ",", last_tick.volume); 
   } 
   else 
      str = "FAIL";

   Print(str);
   ZmqMsg reply(str);
   socket.send(reply);
}

And this in Python:

import zmq
import random
import sys
import time

context = zmq.Context()
socket = context.socket(zmq.SUB)

ports = [5556]
for port in ports:
    print(port)
    socket.connect("tcp://localhost:{}".format(port))
socket.setsockopt_string(zmq.SUBSCRIBE, '')

print('connected')

f = open('metatrader-1.csv', 'a')
while True:
    msg = socket.recv()
    print(msg)
    f.write(str(msg) + '\n')

This problem is that this does not seem to receive anything on the Python side, the recv call just blocks forever. The OnTick method is fired in MT, since the prints can be seen.

How can I get this to work?

Note that if I switch to a REP/REQ pair, it works.

MQL5:

#include <Zmq/Zmq.mqh>


Context context("helloworld");
Socket socket(context,ZMQ_REQ);

string BROKER;

int OnInit()
{
   if (socket.connect("tcp://localhost:5555"))
   {
      Print("Error");
   }
   else
      Print("Bound");
   BROKER = AccountInfoString(ACCOUNT_COMPANY);
   return(INIT_SUCCEEDED);
}

void OnTick()
{  
   MqlTick last_tick; 
   string str;
   if(SymbolInfoTick(Symbol(),last_tick)) 
   { 
      StringConcatenate(str, BROKER, ",", Symbol(), ",", last_tick.time_msc, ",", last_tick.ask, ",", last_tick.bid, ",", last_tick.last, ",", last_tick.volume); 
   } 
   else 
      str = "FAIL";

   Print(str);
   ZmqMsg reply(str);
   socket.send(reply);
   socket.recv(reply);
}

Python:

import zmq
import random
import sys
import time

context = zmq.Context()
socket = context.socket(zmq.REP)

ports = [5555]
for port in ports:
    print(port)
    socket.bind("tcp://*:{}".format(port))
#socket.setsockopt_string(zmq.SUBSCRIBE, '')

print('connected')

f = open('metatrader-1.csv', 'a')
while True:
    msg = socket.recv()
    socket.send_string('ack')
    print(msg)
    f.write(str(msg) + '\n')

But this has some drawbacks so I'd rather not use this if I can help it.

Upvotes: 2

Views: 962

Answers (1)

Benyamin Jafari
Benyamin Jafari

Reputation: 34226

Your socket option must be placed before the socket connection, so your code will be:

import zmq
import random
import sys
import time

context = zmq.Context()
socket = context.socket(zmq.SUB)

ports = [5556]
socket.setsockopt(zmq.SUBSCRIBE, b"")  # Note.

for port in ports:
    print(port)
    socket.connect("tcp://localhost:{}".format(port))

print('connected')

f = open('metatrader-1.csv', 'a')
while True:
    msg = socket.recv()
    print(msg)
    f.write(str(msg) + '\n')

Also, this part:

if (socket.bind("tcp://*:5556"))
{
   Print("Error");
}
else
   Print("Bound");

Should be the other way around. This will actually print an error when the socket is successfully bound.

Upvotes: 1

Related Questions