EA: 交易者的MQL5编程(MQL5 Programming for Traders) - 源代码第七部分 - 页 3 12345 新评论 Stanislav Korotky 2025.03.10 13:32 #21 我在此附上websockets 类的一些错误修正和改进。 附加的文件: wss.zip 16 kb pauldic 2025.03.11 03:20 #22 Stanislav Korotky #: 我在附件中附上了对websockets 类的一些错误修正和改进。 感谢您的努力 pauldic 2025.03.12 05:10 #23 Stanislav Korotky #: 在代码库中 发布了更多关于经济日历读取和导出为 CSV 的错误修复和改进。具体而言,针对大部分已排序大数组(通常从 MQL5 日历 API 接收)的情况,修复了排序算法,从而消除了速度减慢和堆栈溢出。 在 msclient.mqh 的第 126 行 "return connection.handshake(url,host,origin,custom_headers); "中有一个小漏洞,即传递完整的 "url "而不是 "path "会导致在 python websocket 上出现 403 错误。我不得不做此更改,EA 才能成功连接到我的 python websocket 服务器。 我附上了 Postman 的服务器日志(通过)和更改前的 EA 日志(失败) ,但下一个问题是,我的服务器会按配置的时间间隔自动发送 keepalive ping,但 MT5 websocket 实现似乎没有响应,这种行为导致服务器总是在 ping 超时后立即放弃客户端连接。 请就 keepalive ping pong 提供任何帮助,不胜感激。 附加的文件: passed.png 88 kb failed.png 50 kb Experts: MQL5 Programming for MetaTrader 5 中的 WebSockets Stanislav Korotky 2025.03.12 14:11 #24 pauldic #:在 msclient.mqh 的第 126 行 "return connection.handshake(url,host,origin,custom_headers); "中有一个小漏洞,即传递完整的 "url "而不是 "路径 "会导致 python websocket 出错 403。我不得不做此更改,EA 才能成功连接到我的 python websocket 服务器。 我附上了 Postman 的服务器日志(已通过)和更改前的 EA 日志(失败) 但下一个问题是,我的服务器会按配置的时间间隔自动发送 keepalive ping,但 MT5 websocket 实现似乎没有响应,这种行为导致服务器总是在 ping 超时后立即放弃客户端连接。 请就 keepalive ping pong 提供任何帮助,不胜感激。 您好,是的,您可以在客户端调用中使用路径: template<typename T> class WebSocketClient: public IWebSocketObserver { ... bool open(const string custom_headers = NULL) { ... connection = new T(&this, socket, compression); return connection.handshake(path, host, origin, custom_headers); } 另一方面,HTTP 请求语法支持将完整的 URI 作为目标,我用原始源代码对不同的服务器(包括wss://ws.postman-echo.com/raw)进行了测试,结果都正常。因此,我不确定是违反了规定,还是你的 python 实现在某种意义上过于死板。 至于 ping/pong,它应该可以工作。请查看wsprotocol.mqh: // 处理传入的控制帧:在 Ping 时发送 Pong,并在收到关闭请求后关闭连接 void processControlFrame(IWebSocketFrame *frame) { switch(frame.getType()) { case WS_FRAME_OPCODE::WS_CLOSE_FRAME: if(closeRequested) // 我们的关闭得到确认 { Print("Server close ack"); } else if(!disconnecting) // 服务器启动关闭 { if(openMessage) // 仍未最终确定(!)。 { owner.onMessage(openMessage); openMessage = NULL; } WebSocketFrame temp(WS_FRAME_OPCODE::WS_CLOSE_FRAME); // 发送我们的 ack sendFrame(&temp); } close(); break; case WS_FRAME_OPCODE::WS_PING_FRAME: { IWebSocketFrame *temp = WebSocketFrame::create(WS_FRAME_OPCODE::WS_PONG_FRAME, frame.getData()); sendFrame(temp); delete temp; } break; } } 所以请在你这边调试这个东西,因为你有服务器向你的客户端发送 ping。 Stanislav Korotky 2025.03.12 14:14 #25 顺便说一下,我忘了添加ws/sources 中使用的新版本MQL5Book/StringUtils.mqh。 附加的文件: StringUtils.mqh 4 kb wsprotocol.mqh 16 kb pauldic 2025.03.12 18:45 #26 Stanislav Korotky #: 顺便说一下,我忘了添加ws/sources 中使用的MQL5Book/StringUtils.mqh 的新版本。 @Stanislav Korotky 再次感谢您的帮助。关于 python websocket 服务器的 ping pong 问题,在进一步调试后,我注意到服务器以文本或二进制数据形式发送 ping 请求,而 MT5 只有在发送基于文本的 ping 时才会成功响应。这帮助我找到并解决了问题。 问题出现在 ws ping 框架开关/案例中的第 310 行,即创建 Webocket 框架时: IWebSocketFrame *temp = WebSocketFrame::create(WS_FRAME_OPCODE::WS_PONG_FRAME, frame.getData()); frame.getData() 服务器似乎只在 ping 数据基于文本/字符串的情况下才会确认 pong,但如果发送的是二进制 ping,则会失败 因此,我必须使用重载的frame.getData(uchar &buf[]) 才能在两种情况下都正常工作。我不知道是否会遇到(我的改动)会破坏的其他用例,但目前看来一切正常。 uchar data[] ; frame.getData(data) ; IWebSocketFrame *temp = WebSocketFrame::create(WS_FRAME_OPCODE::WS_PONG_FRAME, data); 只是出于好奇,我想知道为什么我们必须使用 OnTimer() 事件处理程序手动检查消息间隔,而我看到的东西似乎是一个事件处理程序函数 OnMessage 传入消息。虽然目前的设置可以正常工作,但如果您能详细说明这种方法的原因,我将不胜感激。 Stanislav Korotky 2025.03.12 22:08 #27 pauldic #: @Stanislav Korotky 再次感谢您的帮助。关于 python websocket 服务器的 ping pong 问题,在进一步调试后,我注意到服务器以文本或二进制数据形式发送 ping 请求,而 MT5 只有在发送基于文本的 ping 时才会成功响应。这帮助我找到并解决了问题。 问题出现在 ws ping 框架开关/案例中的第 310 行,即创建 Webocket 框架时: IWebSocketFrame *temp = WebSocketFrame::create(WS_FRAME_OPCODE::WS_PONG_FRAME, frame.getData()); frame.getData() 服务器似乎只在 ping 数据基于文本/字符串的情况下才会确认 pong,但如果发送的是二进制 ping,则会失败 因此,我必须使用重载的frame.getData(uchar &buf[]) 才能在两种情况下都正常工作。我不知道是否会遇到(我的改动)会破坏的其他用例,但目前看来一切正常。 uchar data[] ; frame.getData(data) ; IWebSocketFrame *temp = WebSocketFrame::create(WS_FRAME_OPCODE::WS_PONG_FRAME, data); 只是出于好奇,我想知道为什么我们必须使用 OnTimer() 事件处理程序手动检查消息间隔,而我看到的东西似乎是一个事件处理程序函数 OnMessage 传入消息。虽然目前的设置可以正常工作,但如果您能详细说明这种方法的原因,我将不胜感激。 感谢您的努力。我会考虑将您的修改纳入源代码。 之所以提供 OnTimer 和 OnMessage,是因为您可能希望在应用程序中实现不同的处理逻辑。从套接字读取数据在 MQL5 API 级别上是阻塞的,并有指定的超时时间。因此,如果您只对等待新消息、处理消息和自动生成响应感兴趣,您可以在阻塞模式(读取时无限超时,且不使用 OnTimer)下进行处理,即应用程序在等待数据时处于某种冻结状态。但如果您需要为用户提供响应式用户界面(聊天应用就是这种情况),那么您可以在 OnTimer 处理程序中为短时间的读取尝试设置一个小超时(超时后会产生空数据),并监控用户在两者之间的操作。 pauldic 2025.03.13 10:52 #28 Stanislav Korotky #:感谢您的努力。我会考虑将您的编辑加入源代码中。之所以提供 OnTimer 和 OnMessage,是因为您可能希望在应用程序中实现不同的处理逻辑。从套接字读取数据在 MQL5 API 级别上是阻塞的,并有指定的超时时间。因此,如果您只对等待新消息、处理消息和自动生成响应感兴趣,您可以在阻塞模式(读取时无限超时,且不使用 OnTimer)下进行处理,即应用程序在等待数据时处于某种冻结状态。但如果您需要为用户提供响应式用户界面(聊天应用就是这种情况),那么您可以在 OnTimer 处理程序中为短时间的读取尝试设置一个小超时(超时后会产生空数据),并监控用户在两者之间的操作。 再次感谢 @StanislavKorotky 的说明 Stanislav Korotky 2025.03.19 11:06 #29 这里是对 zip 压缩包中 wss 源代码的另一些小错误修正和改进。 除其他事项外,您现在可以分析不成功的升级(例如,如果需要授权且返回的状态代码不是 101)并采取相应措施: if(wss.open(initial_headers)) { // 成功,流程正常 } else { // 出了问题 - 未升级或未连接 if(wss.isConnected()) { Print("Can't upgrade to websockets"); bool resolved = false; string headers[][2]; // response if(wss.getHeaders(headers)) { // TODO: 分析状态并解决问题 resolved = ... // 真/假 } if(!resolved) { wss.close(); // 关闭,以防止进一步尝试从未升级的套接字进行读/写操作 } else { wss.open(updated_headers); // try again } } } 此外,还对StringUtils.mqh 和URL.mqh 进行了重要修复。 附加的文件: wss.zip 16 kb StringUtils.mqh 4 kb URL.mqh 5 kb wf2000cn 2025.04.10 07:53 #30 你好@Stanislav Korotky,我是 MQL5 的新用户。我发现您发布了一个用于 webocket 的 wss.zip 文件。如何使用它,有没有演示或我可以学习的东西。衷心感谢! Stanislav Korotky 2025.04.07www.mql5.com Trader's profile 12345 新评论 您错过了交易机会: 免费交易应用程序 8,000+信号可供复制 探索金融市场的经济新闻 注册 登录 拉丁字符(不带空格) 密码将被发送至该邮箱 发生错误 使用 Google 登录 您同意网站政策和使用条款 如果您没有帐号,请注册 可以使用cookies登录MQL5.com网站。 请在您的浏览器中启用必要的设置,否则您将无法登录。 忘记您的登录名/密码? 使用 Google 登录
我在附件中附上了对websockets 类的一些错误修正和改进。
在代码库中 发布了更多关于经济日历读取和导出为 CSV 的错误修复和改进。具体而言,针对大部分已排序大数组(通常从 MQL5 日历 API 接收)的情况,修复了排序算法,从而消除了速度减慢和堆栈溢出。
在 msclient.mqh 的第 126 行 "return connection.handshake(url,host,origin,custom_headers); "中有一个小漏洞,即传递完整的 "url "而不是 "path "会导致在 python websocket 上出现 403 错误。我不得不做此更改,EA 才能成功连接到我的 python websocket 服务器。
我附上了 Postman 的服务器日志(通过)和更改前的 EA 日志(失败)
,但下一个问题是,我的服务器会按配置的时间间隔自动发送 keepalive ping,但 MT5 websocket 实现似乎没有响应,这种行为导致服务器总是在 ping 超时后立即放弃客户端连接。
请就 keepalive ping pong 提供任何帮助,不胜感激。
在 msclient.mqh 的第 126 行 "return connection.handshake(url,host,origin,custom_headers); "中有一个小漏洞,即传递完整的 "url "而不是 "路径 "会导致 python websocket 出错 403。我不得不做此更改,EA 才能成功连接到我的 python websocket 服务器。
我附上了 Postman 的服务器日志(已通过)和更改前的 EA 日志(失败)
但下一个问题是,我的服务器会按配置的时间间隔自动发送 keepalive ping,但 MT5 websocket 实现似乎没有响应,这种行为导致服务器总是在 ping 超时后立即放弃客户端连接。
请就 keepalive ping pong 提供任何帮助,不胜感激。
您好,是的,您可以在客户端调用中使用路径:
另一方面,HTTP 请求语法支持将完整的 URI 作为目标,我用原始源代码对不同的服务器(包括wss://ws.postman-echo.com/raw)进行了测试,结果都正常。因此,我不确定是违反了规定,还是你的 python 实现在某种意义上过于死板。
至于 ping/pong,它应该可以工作。请查看wsprotocol.mqh:
所以请在你这边调试这个东西,因为你有服务器向你的客户端发送 ping。
顺便说一下,我忘了添加ws/sources 中使用的MQL5Book/StringUtils.mqh 的新版本。
问题出现在 ws ping 框架开关/案例中的第 310 行,即创建 Webocket 框架时:
IWebSocketFrame *temp = WebSocketFrame::create(WS_FRAME_OPCODE::WS_PONG_FRAME, frame.getData());
frame.getData() 服务器似乎只在 ping 数据基于文本/字符串的情况下才会确认 pong,但如果发送的是二进制 ping,则会失败
因此,我必须使用重载的frame.getData(uchar &buf[]) 才能在两种情况下都正常工作。我不知道是否会遇到(我的改动)会破坏的其他用例,但目前看来一切正常。
只是出于好奇,我想知道为什么我们必须使用 OnTimer() 事件处理程序手动检查消息间隔,而我看到的东西似乎是一个事件处理程序函数 OnMessage 传入消息。虽然目前的设置可以正常工作,但如果您能详细说明这种方法的原因,我将不胜感激。
@Stanislav Korotky 再次感谢您的帮助。关于 python websocket 服务器的 ping pong 问题,在进一步调试后,我注意到服务器以文本或二进制数据形式发送 ping 请求,而 MT5 只有在发送基于文本的 ping 时才会成功响应。这帮助我找到并解决了问题。
问题出现在 ws ping 框架开关/案例中的第 310 行,即创建 Webocket 框架时: IWebSocketFrame *temp = WebSocketFrame::create(WS_FRAME_OPCODE::WS_PONG_FRAME, frame.getData());
frame.getData() 服务器似乎只在 ping 数据基于文本/字符串的情况下才会确认 pong,但如果发送的是二进制 ping,则会失败
因此,我必须使用重载的
frame.getData(uchar &buf[]) 才能在两种情况下都正常工作。我不知道是否会遇到(我的改动)会破坏的其他用例,但目前看来一切正常。
感谢您的努力。我会考虑将您的修改纳入源代码。
之所以提供 OnTimer 和 OnMessage,是因为您可能希望在应用程序中实现不同的处理逻辑。从套接字读取数据在 MQL5 API 级别上是阻塞的,并有指定的超时时间。因此,如果您只对等待新消息、处理消息和自动生成响应感兴趣,您可以在阻塞模式(读取时无限超时,且不使用 OnTimer)下进行处理,即应用程序在等待数据时处于某种冻结状态。但如果您需要为用户提供响应式用户界面(聊天应用就是这种情况),那么您可以在 OnTimer 处理程序中为短时间的读取尝试设置一个小超时(超时后会产生空数据),并监控用户在两者之间的操作。
感谢您的努力。我会考虑将您的编辑加入源代码中。
之所以提供 OnTimer 和 OnMessage,是因为您可能希望在应用程序中实现不同的处理逻辑。从套接字读取数据在 MQL5 API 级别上是阻塞的,并有指定的超时时间。因此,如果您只对等待新消息、处理消息和自动生成响应感兴趣,您可以在阻塞模式(读取时无限超时,且不使用 OnTimer)下进行处理,即应用程序在等待数据时处于某种冻结状态。但如果您需要为用户提供响应式用户界面(聊天应用就是这种情况),那么您可以在 OnTimer 处理程序中为短时间的读取尝试设置一个小超时(超时后会产生空数据),并监控用户在两者之间的操作。
这里是对 zip 压缩包中 wss 源代码的另一些小错误修正和改进。
除其他事项外,您现在可以分析不成功的升级(例如,如果需要授权且返回的状态代码不是 101)并采取相应措施:
此外,还对StringUtils.mqh 和URL.mqh 进行了重要修复。
你好@Stanislav Korotky,我是 MQL5 的新用户。我发现您发布了一个用于 webocket 的 wss.zip 文件。如何使用它,有没有演示或我可以学习的东西。衷心感谢!