QuickFIX/J 中断开连接的客户端的消息队列行为

Message queue behavior in QuickFIX/J for disconnected clients

我想澄清 QuickFIX/J (FIX 4.2) 在以下情况下的行为。此 QuickFIX/J 通讯涉及两方:

  1. 一个客户端启动器,名为 I
  2. 我们公司的接受者计划,称为 A

I 登录到 A 时,他们交换带有标签 35=A 的 FIX 消息。连接建立后,I开始提交订单。然而,可能有一个点,I 意外断开连接,此时 A 决定为 [=48] 的所有未结订单发送取消=]I(这是有效的,因为 A 不知道为什么 I 失败或 I 会活着回来的)。

请注意,整个断开连接取消程序由 A 单独启动和处理 - 它从 A 启动onLogout(...) 方法并由其正常的订单管理机制处理。为 I 的每个未结订单生成一条 35=F 消息,并且在每次成功取消时生成一条 ExecutionReport (35=8)。

I 活着回来时,这些 ExecutionReports 必须以某种方式传递给 I 以便它意识到所有它之前的订单已被取消。我的印象是 QuickFIX/J 的消息队列实现无需应用程序级帮助即可处理此问题。所有 QuickFIX 消息都确保传递给对方 (http://permalink.gmane.org/gmane.comp.finance.quickfix.devel/169)。

但是,与我的理解相反,AQuickFIX 日志中没有显示 ExecutionReport,也没有传送到 II 重新连接时,导致 I 不知道其之前的订单已被取消。我注意到由于 QuickFIX/JSessionsendRaw(Message message, int num) 方法的以下源代码,不会发生日志记录:

/**
 * Send the message
 *
 * @param message is the message to send
 * @param num is the seq num of the message to send, if 0, the next expected sender seqnum is used.
 * @return
 */
private boolean sendRaw(Message message, int num) {
    ...
        } else {
            try {
                application.toApp(message, sessionID);
            } catch (final DoNotSend e) {
                return false;
            } catch (final Throwable t) {
                logApplicationException("toApp()", t);
            }
            messageString = message.toString();
            if (isLoggedOn()) { // happens only if session is connected
                result = send(messageString); // logging happens within "send"
            }
        }
    ...
}

在为 I 的断开连接发起的取消生成 ExecutionReport 消息时会话未登录,因此它从未达到 send(messageString); 并且没有记录发生。我相信没有消息出于同样的原因排队(基于 I 活着回来时没有收到任何消息的事实)。

我们公司基于 QuickFIX/J 保证所有消息无损传送的信念进行了许多实施,但我对上述情况的观察表明情况并非如此。

当会话未登录时,QuickFIX/J 的消息队列在这种情况下的预期行为如何?它是应该无论如何都对消息进行排队,等待会话在将来再次可用时发送,还是在会话关闭期间停止排队?

这是我的 10 美分:当 QF/J 根据序列号和间隙填充保证活动 session 的消息传递时...

如果 session 丢失,则无法保证任何事情。一旦发现序列号不匹配,您需要做的是将您的发起者和接受者配置为在重新连接时填充间隙。嗯,你的 ResetOnDisconnect 标志在配置中说了什么? ResetOnLogout 怎么样?

我不认为 QF 中有 "queue" 的消息在等待 session,因为 session 可以迪斯科并且永远不会侦察意味着 QF 队列一直在填充,或永远活跃,这不是 QF 能够立即为每个人处理的事情。

如果你有迪斯科舞厅,你也不能使用 OnLogout 向断开连接的客户端发送执行报告!首先,并不总是在每个迪斯科舞厅都调用 OnLogout,其次,正如您所说,我们进入了 QF 内部,它找不到要向其发送消息的 session,所以它除外。我不希望 QF 内部队列为我处理这种情况。同样,保证交付是在连接启动时......这是一个依赖关系。但是,我 希望它被记录在某个地方。您的日志记录配置是什么?

我想你需要看看为什么:"When / comes back alive, these ExecutionReports must be delivered to / somehow so that it becomes aware all its previous orders have been cancelled." disco 上的所有订单不是都被取消了吗?为什么/需要确认?这是给定的,不是吗?这可能是您必须单独编码到 QF 基础的东西。

阅读this

一些公司支持 LOGON 消息中的标签 35002(断开连接时取消),可能的值:

  • 0: 不使用 COD
  • 1:仅在发送 "graceful" 注销时使用 COD
  • 2:在任何 "network" 断开连接时使用 COD
  • 3: 1 和 2

了解您的交易对手是否支持这一点。我没有检查 QuickFIX 支持,但您始终可以自己手动添加标签,或自定义您的 FIX 字典以支持该标签。

显然这经常被高频交易者使用。对这个行业不熟悉,所以在评论区提问

private boolean sendRaw(Message message, int num) 方法的末尾有这段代码:

if (num == 0) {
    final int msgSeqNum = header.getInt(MsgSeqNum.FIELD);
    if (persistMessages) {
        state.set(msgSeqNum, messageString);
    }
    state.incrNextSenderMsgSeqNum();
}

如果会话未连接,state.set(msgSeqNum, messageString) 将调用 messageStore.set(sequence, message) 实际存储消息以供稍后传送。

据我所知,所有消息都将排队等待会话成功登录。