如何解决Python与MQL4通过ZMQ传输实时数据时的无限循环及接收失败问题
解决Python与MQL4通过ZMQ实时数据传输的死锁问题
我来帮你排查这个问题——你遇到的无限循环和收不到数据的核心原因是没有遵守ZMQ REQ-REP模式的通信规则,咱们一步步理清楚:
核心问题:REQ-REP模式的通信顺序错误
ZMQ的REQ(请求端)和REP(响应端)套接字有严格的交互规则:
- REQ套接字必须先发送请求,才能等待接收响应
- REP套接字必须先接收请求,才能发送响应
你的代码完全搞反了这个顺序:Python端一直卡在recv()等待响应,但从来没发过请求;MQL4端直接send()响应,但从来没接收过请求,两边互相等待,形成了死锁。
修正后的Python代码(REQ客户端)
下面是符合REQ模式的代码,先发送请求再接收响应,如果需要持续实时交互,可以加循环控制:
单次请求版本
import zmq port = "5555" print("Connecting to MQL4 server…") context = zmq.Context() socket = context.socket(zmq.REQ) socket.connect(f"tcp://localhost:{port}") try: # REQ模式必须先发送请求 socket.send_string("Request latest market data") print("Sent request to MQL4, waiting for response...") # 接收MQL4的响应 message = socket.recv_string() print(f"Received from MQL4: {message}") except zmq.ZMQError as e: print(f"ZMQ Error occurred: {e}") finally: # 清理资源 socket.close() context.term()
持续实时请求版本
import zmq import time port = "5555" print("Connecting to MQL4 server…") context = zmq.Context() socket = context.socket(zmq.REQ) socket.connect(f"tcp://localhost:{port}") try: while True: # 每次循环先发送请求 socket.send_string("Get real-time data") print("Sent request, waiting for response...") # 接收响应 message = socket.recv_string() print(f"Real-time data: {message}") # 控制请求频率,避免过度占用资源 time.sleep(1) except KeyboardInterrupt: print("Stopping Python client...") finally: socket.close() context.term()
修正后的MQL4代码(REP服务端)
MQL4是事件驱动架构,代码要放在OnInit、OnTick等事件函数里,同时必须先接收请求再发送响应:
#include <Zmq/Zmq.mqh> Context context("mt4-python-connector"); Socket socket(context, ZMQ_REP); bool socketBound = false; // 初始化时绑定端口 int OnInit() { if(!socket.bind("tcp://*:5555")) { Print("Failed to bind socket: ", ZmqLastError()); return(INIT_FAILED); } socketBound = true; Print("Socket bound to tcp://*:5555, waiting for Python requests..."); return(INIT_SUCCEEDED); } // 卸载时清理资源 void OnDeinit(const int reason) { if(socketBound) { socket.close(); context.term(); } } // 每次行情Tick触发时检查并处理请求 void OnTick() { if(!socketBound) return; ZmqMsg request; // 用非阻塞接收,避免阻塞OnTick事件 if(socket.recv(request, ZMQ_DONTWAIT)) { Print("Received request from Python: ", request.toString()); // 准备响应数据,比如当前货币对的买价 string replyContent = StringFormat("EURUSD Bid Price: %.5f", Bid); ZmqMsg reply(replyContent); if(!socket.send(reply)) { Print("Failed to send reply: ", ZmqLastError()); } else { Print("Sent reply to Python: ", replyContent); } } }
额外注意事项
- 运行顺序:必须先启动MQL4的EA/脚本(让它绑定端口并等待请求),再启动Python客户端
- ZMQ库兼容性:确保MQL4的ZMQ库放在
MT4安装目录/MQL4/Include/Zmq下,且版本与你的MT4版本匹配 - 实时推送场景优化:如果需要MQL4主动向Python推送实时数据(无需请求响应),更适合用ZMQ的PUB-SUB(发布-订阅)模式,这种模式不需要严格的请求响应顺序,更适合实时数据流传输
内容的提问来源于stack exchange,提问作者Kemal Bayram
相关产品推荐
相关产品推荐

