quickfix InvalidMessage Header fields out of order
This is very common message when you are working first time with FIX protocol and this happens if the way you have created the message not matching with FIX specification and you get exception below:
Exception in thread “main” quickfix.InvalidMessage: Header fields out of order
Exception in thread "main" quickfix.InvalidMessage: Header fields out of order at quickfix.Message.parseHeader(Message.java:498) at quickfix.Message.parse(Message.java:465) at quickfix.MessageUtils.parse(MessageUtils.java:148) at com.javahonk.fix.FixInitatorParseTest.main(FixInitatorParseTest.java:70)
Solution: In my case it was happening because I had created FIX message using below Message class from QuickFix API as sample method below:
public String convertToFix(LifeCycleManagerModel lifeCycleManagerModel, String localDateTime) { Message message = new Message(); if (lifeCycleManagerModel != null) { StringField msgType = new StringField( FixMessageTypeFields.MSGTYPE.getValue(), FixMessageTypeFields.MSGTYPEVALUE.getAssignedValue()); DoubleField qty = new DoubleField( FixMessageTypeFields.QTY.getValue(), lifeCycleManagerModel.getQuantity()); DoubleField price = new DoubleField( FixMessageTypeFields.PRICE.getValue(), lifeCycleManagerModel.getExpiryPrice()); IntField execTransType = new IntField( FixMessageTypeFields.EXECTRANSTYPE.getValue(), FixMessageTypeFields.EXECTRANSTYPEVALUE.getValue()); IntField execType = new IntField( FixMessageTypeFields.EXECTYPE.getValue(), FixMessageTypeFields.EXECTYPEVALUE.getValue()); StringField orderID = new StringField( FixMessageTypeFields.ORDERID.getValue(), StringUtils.isBlank(lifeCycleManagerModel.getOrderID()) ? "" : lifeCycleManagerModel.getOrderID()); BigDecimal origQuantity = BigDecimal.valueOf(lifeCycleManagerModel.getQuantity()); String sideTemp = origQuantity.compareTo(BigDecimal.valueOf(0.0)) < 0 ? FieldIndex.BUY .getFieldName() : FieldIndex.SELL.getFieldName(); StringField side = new StringField( FixMessageTypeFields.SIDE.getValue(), sideTemp); StringField underlierStockSymbol = new StringField( FixMessageTypeFields.UNDERLIERSTOCKSYMBOL.getValue(), StringUtils.isBlank(lifeCycleManagerModel.getUnderlier()) ? "" : lifeCycleManagerModel.getUnderlier()); StringField transactTime = new StringField( FixMessageTypeFields.TRANSACTTIME.getValue(), localDateTime); StringField sendingTime = new StringField( FixMessageTypeFields.SENDINGTIME.getValue(), localDateTime); StringField futSettDate = new StringField( FixMessageTypeFields.FUTSETTDATE.getValue(), localDateTime); StringField securityType = new StringField( FixMessageTypeFields.SECURIRYTYPE.getValue(), FixMessageTypeFields.SECURITYTYPEVALUE.getAssignedValue()); StringField send = new StringField( FixMessageTypeFields.SEND.getValue(), FixMessageTypeFields.SENDVALUE.getAssignedValue()); StringField traderID = new StringField( FixMessageTypeFields.TRADERID.getValue(), StringUtils.isBlank(lifeCycleManagerModel.getExecutedBy()) ? "" : lifeCycleManagerModel.getExecutedBy()); StringField legalEntity = new StringField( FixMessageTypeFields.LEGALENTITIY.getValue(), StringUtils.isBlank(lifeCycleManagerModel.getCustomerID()) ? "" : lifeCycleManagerModel.getCustomerID()); StringField accountName = new StringField( FixMessageTypeFields.ACCOUNTNAME.getValue(), StringUtils.isBlank(lifeCycleManagerModel.getAccountID()) ? "" : lifeCycleManagerModel.getAccountID()); StringField execID = new StringField( FixMessageTypeFields.EXECID.getValue(), StringUtils.isBlank(lifeCycleManagerModel.getExecID()) ? "" : lifeCycleManagerModel.getExecID()); message.setField(msgType); message.setField(qty); message.setField(price); message.setField(execTransType); message.setField(execType); message.setField(orderID); message.setField(side); message.setField(underlierStockSymbol); message.setField(transactTime); message.setField(sendingTime); message.setField(futSettDate); message.setField(securityType); message.setField(send); message.setField(traderID); message.setField(legalEntity); message.setField(accountName); message.setField(execID); } return message.toString(); }
- To fix this issue I had to change from Message class to NewOrderSingle Class to create FIX message as below:
public String convertToFixNewOrderSingle(LifeCycleManagerModel lifeCycleManagerModel, TransactTime transactTime, String localDateTime) { if (lifeCycleManagerModel != null) { BigDecimal origQuantity = BigDecimal.valueOf(lifeCycleManagerModel.getQuantity()); String sideTemp = origQuantity.compareTo(BigDecimal.valueOf(0.0)) < 0 ? FieldIndex.BUY.getFieldName() : FieldIndex.SELL.getFieldName(); char sideValue; if (sideTemp.equalsIgnoreCase(FieldIndex.BUY.getFieldName())) { sideValue = FixMessageTypeFields.SIDEBUY.getCharValue(); }else { sideValue = FixMessageTypeFields.SIDESELL.getCharValue(); } NewOrderSingle order = new NewOrderSingle(new ClOrdID(StringUtils.isBlank(lifeCycleManagerModel.getOrderID()) ? "" : lifeCycleManagerModel.getOrderID()), new HandlInst(HandlInst.MANUAL_ORDER), new Symbol(StringUtils.isBlank(lifeCycleManagerModel.getUnderlier()) ? "": lifeCycleManagerModel.getUnderlier()), new Side(sideValue), transactTime, new OrdType(OrdType.MARKET)); order.set(new OrderQty(lifeCycleManagerModel.getQuantity())); order.set(new Price(lifeCycleManagerModel.getExpiryPrice())); order.set(new FutSettDate(localDateTime)); order.set(new SecurityType(FixMessageTypeFields.SECURITYTYPEVALUE.getAssignedValue())); order.set(new Account(lifeCycleManagerModel.getAccountID())); order.set(new ExecInst(lifeCycleManagerModel.getExecID())); order.setString(FixMessageTypeFields.EXECID.getValue(), lifeCycleManagerModel.getExecID()); order.setString(FixMessageTypeFields.LEGALENTITIY.getValue(), StringUtils.isBlank(lifeCycleManagerModel.getCustomerID()) ? "": lifeCycleManagerModel.getCustomerID()); order.setString(FixMessageTypeFields.TRADERID.getValue(), StringUtils.isBlank(lifeCycleManagerModel.getExecutedBy()) ? "": lifeCycleManagerModel.getExecutedBy()); order.setString(FixMessageTypeFields.SENDVALUE.getValue(), FixMessageTypeFields.SENDVALUE.getAssignedValue()); order.set(transactTime); order.setString(FixMessageTypeFields.EXECTYPE.getValue(),FixMessageTypeFields.EXECTYPEVALUE.getAssignedValue()); order.setString(FixMessageTypeFields.EXECTRANSTYPE.getValue(),FixMessageTypeFields.EXECTRANSTYPEVALUE.getAssignedValue()); return order.toString(); } else { return new NewOrderSingle().toString(); } }
Also please validate message using QuickFix parser as below:
quickfix.Message message = MessageUtils.parse(quickfix.Session.lookupSession(sessions.get(0)), messageFixString);
Example below:
public static void main(String[] args) throws ConfigError, InvalidMessage { FixInitatorParseTest fixIniator = new FixInitatorParseTest(); SessionSettings sessionSettings = new SessionSettings("./config/initiator/initiator.cfg"); ApplicationAdapter application = new FixInitatorParseTest(); FileStoreFactory fileStoreFactory = new FileStoreFactory(sessionSettings); ScreenLogFactory screenLogFactory = new ScreenLogFactory(sessionSettings); DefaultMessageFactory defaultMessageFactory = new DefaultMessageFactory(); fixIniator.socketInitiator = new SocketInitiator(application,fileStoreFactory, sessionSettings, screenLogFactory,defaultMessageFactory); fixIniator.socketInitiator.start(); try { Thread.sleep(3000); } catch (InterruptedException e1) { e1.printStackTrace(); } ArrayList<SessionID> sessions = fixIniator.socketInitiator.getSessions(); String testMessage = "8=FIX.4.29=19535=D0=Y1=12345611=12345617=OTC-OE-144010626755018=12345620=021=338=4540=144=240.954=255=AAPL60=20150820-21:31:07.55564=2015-08-20T17:31:07.550150=0167=CS11107=Test111320=12345610=043"; String messageFixString = "8=FIX.4.29=16517=12345620=031=159.9932=89935=D37=12345652=2015-08-2154=Sell55=AAPL60=2015-08-2164=2015-08-21150=0167=CS10335=Y11107=Test111320=123456111321=12345610=159"; NewOrderSingle order = new NewOrderSingle(new ClOrdID("MISYS1001"), new HandlInst(HandlInst.MANUAL_ORDER), new Symbol("APPL"), new Side(Side.BUY), new TransactTime(new Date()), new OrdType(OrdType.MARKET)); order.set(new OrderQty(45)); order.set(new Price(240.9d)); SessionID sessionID = sessions.get(0); quickfix.Message message = MessageUtils.parse(quickfix.Session.lookupSession(sessions.get(0)), messageFixString); System.out.println(message.toString()); System.out.println("Sending Order to Server"); try { Session.sendToTarget(order, sessionID); } catch (SessionNotFound e) { e.printStackTrace(); } try { Thread.sleep(3000); } catch (InterruptedException e1) { e1.printStackTrace(); } System.out.println("Going to stop socketInitiator"); fixIniator.socketInitiator.stop(); }
I have written complete tutorial on FIX engine please refer tutorial here and for more information please visit QuickFix here