Grant and TT are correct in stating that actually FIX does not mandate a specific tag (or field) ordering except inside repeating groups.
However, there are some counterparties which require a specific field ordering in the message body.
When setting fields on a message, QuickFIX/J arranges the tags in the order as they appear in the data dictionary. This is because the code for a specific message type is generated from the data dictionary on compile time.
If you wanted to change this ordering there are two possibilities.
Change the data dictionary and recompile QuickFIX/J. Instructions are here: build instructions
Extend the general Message
, specify the tag ordering and pass it to the super constructor. See below for example code.
NOTE: Thinking further about this I realized that there is a downside to this approach. In the case of the event that your side needs to resend messages, then the messages from the store are parsed using the configured data dictionary and message factory for that session. I.e. you will probably end up using the field ordering from the data dictionary / generated code again.
So to sum this up: option 1 is the clean approach but requires rebuilding QuickFIX/J.
And a general note: please note that you don't have to add the repeating group count (NoPartyIDs
in your code) by yourself. This is done by QuickFIX/J when you add a group to the message.
Example code:
@Test
public void testCustomFieldOrder() {
final int[] FIELD_ORDER = {38, 55, 44, 1};
final int[] PARTY_GROUP_ORDER = {447, 452, 448, 0};
class MyNewOrderSingle extends quickfix.fix50sp1.Message {
public static final String MSGTYPE = "D";
public MyNewOrderSingle() {
super(FIELD_ORDER);
getHeader().setField(new quickfix.field.MsgType(MSGTYPE));
}
}
class MyPartyGroup extends Group {
public MyPartyGroup() {
super(453, 447, PARTY_GROUP_ORDER);
}
}
quickfix.fix50sp1.NewOrderSingle nos1 = new quickfix.fix50sp1.NewOrderSingle();
nos1.setString(38, "1000");
nos1.setString(55, "SYM");
nos1.setString(44, "1");
nos1.setString(1, "ACCOUNT");
nos1.setString(100, "XETR");
quickfix.fix50sp1.NewOrderSingle.NoPartyIDs group1 = new quickfix.fix50sp1.NewOrderSingle.NoPartyIDs();
group1.setString(447, "C");
group1.setString(452, "12");
group1.setString(448, "PARTYID");
nos1.addGroup(group1);
System.out.println("orig " + nos1.toString().replace('\001', '|'));
MyNewOrderSingle nos2 = new MyNewOrderSingle();
nos2.setString(38, "1000");
nos2.setString(55, "SYM");
nos2.setString(44, "1");
nos2.setString(1, "ACCOUNT");
nos2.setString(100, "XETR");
MyPartyGroup group2 = new MyPartyGroup();
group2.setString(447, "C");
group2.setString(452, "12");
group2.setString(448, "PARTYID");
nos2.addGroup(group2);
System.out.println("custom " + nos2.toString().replace('\001', '|'));
}
Output:
orig 8=FIXT.1.1|9=75|35=D|1=ACCOUNT|38=1000|44=1|55=SYM|100=XETR|453=1|448=PARTYID|447=C|452=12|10=014|
custom 8=FIXT.1.1|9=75|35=D|38=1000|55=SYM|44=1|1=ACCOUNT|100=XETR|453=1|447=C|452=12|448=PARTYID|10=014|