QuickFIX/J常见问题汇总
最近在搞QuickFIX/J,网上的资料不算很多,遇到一些简单的问题都需要google一阵才能找到解决方法,因此做点记录:
错误:Rejecting invalid message: quickfix.UnsupportedMessageType
这个异常的产生,有两个条件:
1) UseDataDictionary = N
2) 没有覆盖对应的onMessage方法
具体说来,如果没有将UseDataDictionary设为N,几时没有覆盖对应的onMessage方法,也不会产生这个异常。
至于没有覆盖对应的onMessage方法,是指覆盖的onMessage方法,参数必须是接收的信息的类型:
//Will throws error @Override public void onMessage(Message message, SessionID sessionID) throws FieldNotFound, UnsupportedMessageType, IncorrectTagValue{ super.onMessage(message, sessionID); System.out.println("--crack--"); } //Correct! @Override public void onMessage(ExecutionReport message, SessionID sessionID) throws FieldNotFound, UnsupportedMessageType, IncorrectTagValue { System.out.println("--crack ER--"); }
如果接收的信息35=8(ExecutionReport),则需用第二个onMessage方法,而非第一个。
在FIX信息中,自定义域(Add new field)
在QuickFIX/J中新增自定义域,最简单的就是修改对应版本的xml文件,在xml文件里增加自定义域,然后在配置文件中设置如下:
UseDataDictionary=Y
DataDictionary=config/FIX42.xml
用这种方法去指定自定义的DataDictionary文件。
但此方法有两个缺点:
1) 接收信息,解析自定义域数据时,只能使用类型不安全的解析
@Override public void onMessage(ExecutionReport message, SessionID sessionID) throws FieldNotFound, UnsupportedMessageType, IncorrectTagValue { System.out.println("--crack ER--"); StringField field = new StringField(10041); System.out.println(message.getField(field).toString()); }
假设新增了10041这个域(FIX Tag),由于QuickFIX/J包里默认没有这个域对应的对象,这能使用这种方法取得这个域的值,而这种方法在官方文档里描述为类型不安全,并不推荐。
2) 当自定义域的信息含有Repeating Group时,会抛出Out of order repeating group members这个错误。暂时还未找到解决方法
最好的解决方法,是修改xml文件,新增自定义域(Field)和消息类型(Message Type)后,重新build一个自定义的.jar文件。
使用这种方法需要注意的是,如果自定义域和自定义消息类型只针对某一个版本的FIX,例如只修改了FIX42.xml,而QuickFIX/J默认是将所有的Field放在“quickfix.field”这个包里,并非如消息类型那样分开不同版本的包放,因此自定义的Field有可能会被其它版本(如FIX43/44)覆盖。
看来这个类quickfix.codegen.MessageCodeGenerator.java:
public static void main(String[] args) { MessageCodeGenerator codeGenerator = new MessageCodeGenerator(); try { if (args.length != 3) { String classname = MessageCodeGenerator.class.getName(); System.err.println("usage: " + classname + " specDir xformDir outputBaseDir"); return; } boolean overwrite = getOption(OVERWRITE_OPTION, true); boolean orderedFields = getOption(ORDERED_FIELDS_OPTION, false); boolean useDecimal = getOption(BIGDECIMAL_TYPE_OPTION, false); long start = System.currentTimeMillis(); // final String[] vers = new String[] { "FIXT 1.1", "FIX 5.0", "FIX 4.4", "FIX 4.3", "FIX 4.2", // "FIX 4.1", "FIX 4.0" }; final String[] vers = new String[] {"FIXT 1.1","FIX 4.2"}; for (int i = 0; i < vers.length; ++i) { Task task = new Task(); task.setName(vers[i]); final String temp = stripSpaces(vers[i]); task.setSpecification(args[0] + "/" + temp + ".xml"); task.setTransformDirectory(args[1]); task.setMessagePackage("quickfix." + temp.toLowerCase()); task.setOutputBaseDirectory(args[2]); task.setFieldPackage("quickfix.field"); task.setOverwrite(overwrite); task.setOrderedFields(orderedFields); task.setDecimalGenerated(useDecimal); codeGenerator.generate(task); } double duration = System.currentTimeMillis() - start; DecimalFormat durationFormat = new DecimalFormat("#.###"); codeGenerator.log.info("Time for generation: " + durationFormat.format(duration / 1000L) + " seconds"); } catch (Exception e) { codeGenerator.log.error("error during code generation", e); System.exit(1); } }
留意注释部分是默认的实现。可以看到setMessagePackage和setFieldPackage之间的不同。
成功build了以后,就可以这样解析10041(name=BoInstrumentCode2)这个自定义域:
public void onMessage(quickfix.fix42.ExecutionReport message, SessionID sessionID) throws FieldNotFound { System.out.println(message.getBoInstrumentCode2().toString()); }
简单清晰,面向对象
参考:
http://www.quickfixj.org/confluence/display/qfj/User+FAQ
http://www.quickfixj.org/quickfixj/usermanual/1.5.3/usage/configuration.html#Sample Settings File