本系列力求手把手教你怎样利用 QuickFix Java 搭建自己的 FIX 协议收发平台,以及其中的注意事项。
所有源码的地址(免费):
这节我们讨论将Acceptor和Initiator启动以后,收到的消息极其查看方式。
6. 收发双方的通信
6.1. 启动后的通信和登录
注意:请参照上一篇的方法配置你的IP地址,端口,和收发双方的ID!
启动acceptor之后,会调用onCreate方法,随后系统便会开启监听状态。
启动Initiator之后,基本也是一样。我们可以让Initiator率先发起通信,发送一个35=V的信息。这个时候就会调用toApp方法,因为具体信息的传输是应用层的(Application)。
随后我们看到在Admin层开始有消息的通信,具体表现为日志中出现了“fromAdmin” 和 “toAdmin” 字样。
Admin层的消息一般为登录登出,以及心跳活动。心跳的间隔设置在property文件中的HeartBtInt,单位是秒。
6.2. 协议消息的收发
在Initiator的代码中,我们让它率先发送一个MarketDataRequest(行情订阅)的信息:
public void sendMarketDataRequest(SessionID sessionID) throws SessionNotFound {
// 具体set哪些字段,参考你的FIX44.modified.xml MarketDataRequest req = new MarketDataRequest();
req.set(new MDReqID("mockedMDReqID"));
req.set(new SubscriptionRequestType('1'));
// 重复组的设置 MarketDataRequest.NoRelatedSym symGroup1 = new MarketDataRequest.NoRelatedSym();
symGroup1.set(new Symbol("mockedSymbol1"));
req.addGroup(symGroup1);
MarketDataRequest.NoRelatedSym symGroup2 = new MarketDataRequest.NoRelatedSym();
symGroup2.set(new Symbol("mockedSymbol2"));
req.addGroup(symGroup2);
System.out.println("Sending MarketDataRequest");
Session.sendToTarget(req, sessionID);
}
在第一章我们就说过,如果不用“暗号”,拼凑起来的通信字段将会非常长,比如一个MarketDataRequest就要好多字节,因此程序就回去查阅FIX44的字典,找到它对应的代码:
上图中的msgtype=“V”就是那个“暗号”,而msgcat=“app”就代表这是一个app层的传输信息。因此在发送出的消息就会有35=V的识别符号:
上图中的问号小图标是IDE无法识别的分隔符,每一段的格式是X=Y的形式,X为字段代码编号,可以在字典中查到。Y为具体的数值。
如果是发送别的消息,形式也是一样,可以自行解析如下消息片段:
相应的,acceptor端会受到消息,因此它会调用“fromApp”方法:
6.3. 收到消息后的解析
acceptor端收到消息以后,会读取35字段中的值。比如上述的35=D,则会被解析为NewOrderSingle,也就是新订单。
解析完成后,acceptor就会去看用户有没有针对NewOrderSingle重写onMessage方法,在FixAcceptorApplication里:
@Override
public void onMessage(NewOrderSingle message, SessionID sessionID) throws FieldNotFound, UnsupportedMessageType, IncorrectTagValue {
System.out.println("Received NewOrderSingle: " + message + ", sessionID: " + sessionID);
// 收都收了,解析一下 System.out.println(String.format("clOrderID: %s, symbol: %s, side: %s",
message.getClOrdID().getValue(),
message.getSymbol().getValue(),
message.getSide().getValue()));
// 返还一个订单回复 ExecutionReport executionReport = new ExecutionReport();
executionReport.set(message.getClOrdID());
executionReport.set(new ExecID("mockedExecID"));
executionReport.set(message.getSide());
executionReport.set(message.getSymbol());
try {
Session.sendToTarget(executionReport, sessionID);
} catch (SessionNotFound sessionNotFound) {
sessionNotFound.printStackTrace();
}
}
重写之后就能进行自定义的解析,比如输出关键字:
如果没有重写此方法,就什么也不做。因此我建议大家至少重写以下方法:
public void onMessage(Reject message, SessionID sessionID)
public void onMessage(BusinessMessageReject message, SessionID sessionID)
6.4. 其他查看消息的方式
有人问:粽子君,我的代码是部署在服务器上的,怎么查看收发的消息呢?
——还是在properties文件里:
FileStorePath=fileStore
FileLogPath=log
在fileStore里,主要存储真是传输中的消息头、消息体,和当下的消息序列号。如果序列号对不上,消息就会被废弃或者拒收。
在log里,分为两种文件:一种是event,来记录消息和事件。一种是message,记录消息本身。
新建项目的时候,要确保程序对上述两个文件的地址有写入权限。