How to log QuickFix message in human-readable format
Asked Answered
P

5

5

I want to log QuickFix messages in sort of parsed mode like tagname,Value

I cannot find existing functionality. I am using QuickFix.Net.

I was thinking about providing some sort of method that would iterate through all presenting tags and parse them using data dictionary.

Pinchas answered 23/6, 2011 at 12:20 Comment(0)
H
4

There is no method in quickfix to parse the message in human readable format. Another option is when you handle an incoming FIX message in onMessage, you would anyway parse it to read the message. Here you can list down the tagname and values to a file or DB. But any operation to do so may slow down your Quickfix engine, because writing to a file or DB is always slow. So BEWARE !!

Another option is log your messages to your DB instead of a file and then do all your stuff in the DB, but that would mean parsing a message twice i.e. in your engine and DB. But you would get a lot more flexibilty about what you want to read and what not to.

Halutz answered 24/6, 2011 at 7:44 Comment(0)
C
9

There is a Java sample http://www.quickfixj.org/confluence/display/qfj/Using+Message+Metadata that can be converted to .NET and that may prove to be useful:

public class MetadataExample {
    public static void main(String[] args) throws Exception {
        DataDictionary dd = new DataDictionary("FIX44.xml");

        Message m = new Message("8=FIX.4.4\0019=247\00135=s\00134=5\001"
                + "49=sender\00152=20060319-09:08:20.881\001"
                + "56=target\00122=8\00140=2\00144=9\00148=ABC\00155=ABC\001"
                + "60=20060319-09:08:19\001548=184214\001549=2\001"
                + "550=0\001552=2\00154=1\001453=2\001448=8\001447=D\001"
                + "452=4\001448=AAA35777\001447=D\001452=3\00138=9\00154=2\001"
                + "453=2\001448=8\001447=D\001452=4\001448=aaa\001447=D\001"
                + "452=3\00138=9\00110=056\001", dd);

        MessagePrinter printer = new MessagePrinter();
        printer.print(System.out, dd, m);
    }
}

public class MessagePrinter {

    public void print(DataDictionary dd, Message message) throws FieldNotFound {
        String msgType = message.getHeader().getString(MsgType.FIELD);
        printFieldMap("", dd, msgType, message.getHeader());
        printFieldMap("", dd, msgType, message);
        printFieldMap("", dd, msgType, message.getTrailer());
    }

    private void printFieldMap(String prefix, DataDictionary dd, String msgType, FieldMap fieldMap)
            throws FieldNotFound {

        Iterator fieldIterator = fieldMap.iterator();
        while (fieldIterator.hasNext()) {
            Field field = (Field) fieldIterator.next();
            if (!isGroupCountField(dd, field)) {
                String value = fieldMap.getString(field.getTag());
                if (dd.hasFieldValue(field.getTag())) {
                    value = dd.getValueName(field.getTag(), fieldMap.getString(field.getTag())) + " (" + value + ")";
                }
                System.out.println(prefix + dd.getFieldName(field.getTag()) + ": " + value);
            }
        }

        Iterator groupsKeys = fieldMap.groupKeyIterator();
        while (groupsKeys.hasNext()) {
            int groupCountTag = ((Integer) groupsKeys.next()).intValue();
            System.out.println(prefix + dd.getFieldName(groupCountTag) + ": count = "
                    + fieldMap.getInt(groupCountTag));
            Group g = new Group(groupCountTag, 0);
            int i = 1;
            while (fieldMap.hasGroup(i, groupCountTag)) {
                if (i > 1) {
                    System.out.println(prefix + "  ----");
                }
                fieldMap.getGroup(i, g);
                printFieldMap(prefix + "  ", dd, msgType, g);
                i++;
            }
        }
    }

    private boolean isGroupCountField(DataDictionary dd, Field field) {
        return dd.getFieldTypeEnum(field.getTag()) == FieldType.NumInGroup;
    }

}

Output:

BeginString: FIX.4.4
BodyLength: 247
MsgSeqNum: 5
MsgType: NewOrderCross (s)
SenderCompID: sender
SendingTime: 20060319-09:08:20.881
TargetCompID: target
SecurityIDSource: EXCHANGE_SYMBOL (8)
OrdType: LIMIT (2)
Price: 9
SecurityID: ABC
Symbol: ABC
TransactTime: 20060319-09:08:19
CrossID: 184214
CrossType: CROSS_TRADE_WHICH_IS_EXECUTED_PARTIALLY_AND_THE_REST_IS_CANCELLED (2)
CrossPrioritization: NONE (0)
NoSides: count = 2
  OrderQty: 9
  Side: BUY (1)
  NoPartyIDs: count = 2
    PartyIDSource: PROPRIETARY_CUSTOM_CODE (D)
    PartyID: 8
    PartyRole: CLEARING_FIRM (4)
    ----
    PartyIDSource: PROPRIETARY_CUSTOM_CODE (D)
    PartyID: AAA35777
    PartyRole: CLIENT_ID (3)
  ----
  OrderQty: 9
  Side: SELL (2)
  NoPartyIDs: count = 2
    PartyIDSource: PROPRIETARY_CUSTOM_CODE (D)
    PartyID: 8
    PartyRole: CLEARING_FIRM (4)
    ----
    PartyIDSource: PROPRIETARY_CUSTOM_CODE (D)
    PartyID: aaa
    PartyRole: CLIENT_ID (3)
CheckSum: 056
Chercherbourg answered 28/1, 2016 at 7:21 Comment(0)
H
4

There is no method in quickfix to parse the message in human readable format. Another option is when you handle an incoming FIX message in onMessage, you would anyway parse it to read the message. Here you can list down the tagname and values to a file or DB. But any operation to do so may slow down your Quickfix engine, because writing to a file or DB is always slow. So BEWARE !!

Another option is log your messages to your DB instead of a file and then do all your stuff in the DB, but that would mean parsing a message twice i.e. in your engine and DB. But you would get a lot more flexibilty about what you want to read and what not to.

Halutz answered 24/6, 2011 at 7:44 Comment(0)
M
3

You can get the QuickFix.Message.ToXML() to output tags of a certain dictionary by using the QuickFix.Message.InitializeXML method.

eg.

QuickFix.Message msg = new QuickFix.Message();
// Create your message
QuickFix.Message.InitializeXML(@"c:\quickfix\spec\FIX44.xml");
Console.WriteLine(msg.ToXML());

It will give you the tags for each field, but not what the content of the field means if it is an enumeration value.

This is an exmple of what I see in my output window:

<message>
<header>
    <field name="BeginString" number="8"><![CDATA[FIX.4.4]]></field>
    <field name="MsgType" number="35" enum="Heartbeat"><![CDATA[0]]></field>
    <field name="MsgSeqNum" number="34"><![CDATA[10]]></field>
    <field name="SenderCompID" number="49"><![CDATA[VCMVCON]]></field>
    <field name="SendingTime" number="52"><![CDATA[20110815-09:35:33.782]]></field>
    <field name="TargetCompID" number="56"><![CDATA[BLPVCON]]></field>
  </header>
  <body>
    <field name="TestReqID" number="112"><![CDATA[R.0001.0010.000A.093519]]></field>
  </body>
  <trailer>
  </trailer>
</message>
Mohawk answered 15/8, 2011 at 9:46 Comment(0)
E
2

I took Martin Vseticka's Java answer and made my own version in C#, the key differences being that I chose to use a StringBuilder instead of printing out each line, and I added an extension method. I chose a format similar to JSON, and it wouldn't take much work at all to make it produce actual valid JSON.

public static class MessageDecoder
{
    public static string Decode(this Message message, DataDictionary dataDictionary)
    {
        return DecodeMessage(message, dataDictionary);
    }

    public static string DecodeMessage(Message message, DataDictionary dataDictionary)
    {
        var messageStr = new StringBuilder("FIX {\n");

        var msgType = message.Header.GetString(Tags.MsgType);
        DecodeFieldMap("  ", dataDictionary, messageStr, msgType, message.Header);
        DecodeFieldMap("  ", dataDictionary, messageStr, msgType, message);
        DecodeFieldMap("  ", dataDictionary, messageStr, msgType, message.Trailer);

        messageStr.Append("}");
        return messageStr.ToString();
    }

    private static void DecodeFieldMap(string prefix, DataDictionary dd, StringBuilder str, string msgType, FieldMap fieldMap)
    {
        foreach (var kvp in fieldMap)
        {
            if (dd.IsGroup(msgType, kvp.Key)) continue;

            var field = dd.FieldsByTag[kvp.Key];

            var value = fieldMap.GetString(field.Tag);
            if (dd.FieldHasValue(field.Tag, value))
            {
                value = $"{field.EnumDict[value]} ({value})";
            }

            str.AppendFormat("{0}{1} = {2};\n", prefix, field.Name, value);
        }

        foreach (var groupTag in fieldMap.GetGroupTags())
        {
            var groupField = dd.FieldsByTag[groupTag];
            str.AppendFormat("{0}{1} (count {2}) {{\n", prefix, groupField.Name, fieldMap.GetInt(groupTag));

            for (var i = 1; i <= fieldMap.GetInt(groupTag); i++)
            {
                var group = fieldMap.GetGroup(i, groupTag);
                var groupPrefix = prefix + "  ";
                str.AppendFormat("{0}{{\n", groupPrefix);
                DecodeFieldMap(groupPrefix + "  ", dd, str, msgType, group);
                str.AppendFormat("{0}}},\n", groupPrefix);
            }

            str.Remove(str.Length - 2, 1); // Remove last ","
            str.AppendFormat("{0}}};\n", prefix);
        }
    }
}

Output looks like this (I trimmed a bunch of fields):

FIX {
  BeginString = FIX.4.4;
  BodyLength = 821;
  MsgSeqNum = 123;
  MsgType = EXECUTION_REPORT (8);
  PossDupFlag = YES (Y);
  SendingTime = 20200125-02:26:17.405;
  ExecID = 76615:3975388;
  ExecInst = WORK (2);
  LastMkt = XCEC;
  OrdStatus = EXPIRED (C);
  OrdType = LIMIT (2);
  OpenClose = OPEN (O);
  SecurityDesc = Copper;
  MaturityDate = 20200129;
  CustOrderCapacity = ALL_OTHER (4);
  ManualOrderIndicator = MANUAL (Y);
  NoPartyIDs (count 2) {
    {
      PartyIDSource = PROPRIETARY (D);
      PartyID = 0;
      PartyRole = ACCOUNT_TYPE (205);
    },
    {
      PartyIDSource = PROPRIETARY (D);
      PartyID = FIX_UAT;
      PartyRole = CLEARING_ACCOUNT (83);
    }
  };
  NoSecurityAltID (count 2) {
    {
      SecurityAltID = 1HGF0;
      SecurityAltIDSource = RIC_CODE (5);
    },
    {
      SecurityAltID = 170831;
      SecurityAltIDSource = EXCHANGE_SECURITY_ID (8);
    }
  };
  CheckSum = 077;
}
Edda answered 29/1, 2020 at 14:35 Comment(0)
A
2

Here is an answer in Python. Depending on the user's need there are three solutions presented here.

  1. Marked-up XML
  2. List of fields (groups embedded).
  3. JSON-like output.

In the quickfix Python library, the FieldMap field and group key iterators are not exposed. So the approach is to first generate the XML and iterate over the tree. There is also no access to the getFieldType method of the DataDictionary, so the dictionary must be pre-processed to store the field types for conversion and handling of groups.

import quickfix as fix

import xml.etree.ElementTree as ET
from collections import OrderedDict
import json

string = "8=FIX.4.4\0019=247\00135=s\00134=5\00149=sender\00152=20060319-09:08:20.881\00156=target\00122=8\00140=2\00144=9\00148=ABC\00155=ABC\00160=20060319-09:08:19\001548=184214\001549=2\001550=0\001552=2\00154=1\001453=2\001448=8\001447=D\001452=4\001448=AAA35777\001447=D\001452=3\00138=9\00154=2\001453=2\001448=8\001447=D\001452=4\001448=aaa\001447=D\001452=3\00138=9\00110=056\001"

# Load data dictionary
data_dictionary_xml = "FIX44.xml"
data_dictionary = fix.DataDictionary(data_dictionary_xml)
fix.Message().InitializeXML(data_dictionary_xml)

# String as fix message according to dictionary
message = fix.Message(string, data_dictionary, True)

# Marked-up XML
xml = message.toXML()
print(xml)

def get_field_type_map(data_dictionary_xml):
  """Preprocess DataDictionary to get field types."""
  field_type_map = {}
  with open(data_dictionary_xml, "r") as f:
    xml = f.read()
    tree = ET.fromstring(xml)
    fields = tree.find("fields")
    for field in fields.iter("field"):
      field_type_map[field.attrib["number"]] = field.attrib["type"]
  return field_type_map

field_type_map = get_field_type_map(data_dictionary_xml)

INT_TYPES = ["INT", "LENGTH", "NUMINGROUP", "QTY", "SEQNUM"]
FLOAT_TYPES = ["FLOAT", "PERCENTAGE", "PRICE", "PRICEOFFSET"]
BOOL_TYPES = ["BOOLEAN"]
DATETIME_TYPES = ["LOCALMKTDATE", "MONTHYEAR", "UTCDATEONLY", "UTCTIMEONLY", "UTCTIMESTAMP"]
STRING_TYPES = ["AMT", "CHAR", "COUNTRY", "CURRENCY", "DATA", "EXCHANGE", "MULTIPLEVALUESTRING", "STRING"]

def field_map_to_list(field_map, field_type_map):
  fields = []
  field_iter = iter([el for el in field_map if el.tag == "field"])
  group_iter = iter([el for el in field_map if el.tag == "group"])
  for field in field_iter:
    # Extract raw value
    raw = field.text
    # Type the raw value
    field_type = field_type_map.get(field.attrib["number"])
    if field_type in INT_TYPES:
      value = int(raw)
    elif field_type in FLOAT_TYPES:
      value = float(raw)
    elif field_type in BOOL_TYPES:
      value = bool(int(raw))
    elif field_type in DATETIME_TYPES:
      value = str(raw)
    elif field_type in STRING_TYPES:
      value = str(raw)
    else:
      value = str(raw)
    # field.attrib should contain "name", "number", "enum"
    _field = {
      **field.attrib,
      "type": field_type,
      "raw": raw,
      "value": value,
    }
    # If NUMINGROUP type then iterate groups the number indicated
    # This assumes groups are in the same order as their field keys
    if field_type == "NUMINGROUP":
      groups = []
      for _ in range(value):
        group = next(group_iter)
        # Parse group as field map
        group_fields = field_map_to_list(group, field_type_map)
        groups.append(group_fields)
      _field["groups"] = groups
    fields.append(_field)
  return fields

def field_map_to_dict(field_map, field_type_map):
  fields = OrderedDict()
  field_iter = iter([el for el in field_map if el.tag == "field"])
  group_iter = iter([el for el in field_map if el.tag == "group"])
  for field in field_iter:
    # Define key
    # field.attrib should contain "name", "number", "enum"
    key = field.attrib.get("name") or field.attrib.get("number")
    # Extract raw value
    raw = field.text
    # Type the raw value
    field_type = field_type_map.get(field.attrib["number"])
    if field_type in INT_TYPES:
      value = int(raw)
    elif field_type in FLOAT_TYPES:
      value = float(raw)
    elif field_type in BOOL_TYPES:
      value = bool(int(raw))
    elif field_type in DATETIME_TYPES:
      value = str(raw)
    elif field_type in STRING_TYPES:
      value = str(raw)
    else:
      value = str(raw)
    # If NUMINGROUP type then iterate groups the number indicated
    # This assumes groups are in the same order as their field keys
    if field_type == "NUMINGROUP":
      groups = []
      for _ in range(value):
        group = next(group_iter)
        # Parse group as field map
        group_fields = field_map_to_dict(group, field_type_map)
        groups.append(group_fields)
      fields[key] = groups
    else:
      # Preference enum above value
      fields[key] = field.attrib.get("enum") or value
  return fields

def parse_message_xml(xml, field_type_map, as_dict=False):
  parsed = OrderedDict()
  tree = ET.fromstring(xml)
  for field_map in tree:
    if not as_dict:
      parsed[field_map.tag] = field_map_to_list(field_map, field_type_map)
    else:
      parsed[field_map.tag] = field_map_to_dict(field_map, field_type_map)
  return parsed

# List of fields (groups embedded)
parsed = parse_message_xml(xml, field_type_map, as_dict=False)
print(json.dumps(parsed, indent=True))

# JSON-like output
parsed = parse_message_xml(xml, field_type_map, as_dict=True)
print(json.dumps(parsed, indent=True))

Outputs:

<message>
  <header>
    <field name="BeginString" number="8"><![CDATA[FIX.4.4]]></field>
    <field name="BodyLength" number="9"><![CDATA[247]]></field>
    <field name="MsgType" number="35" enum="NewOrderCross"><![CDATA[s]]></field>
    <field name="MsgSeqNum" number="34"><![CDATA[5]]></field>
    <field name="SenderCompID" number="49"><![CDATA[sender]]></field>
    <field name="SendingTime" number="52"><![CDATA[20060319-09:08:20.881]]></field>
    <field name="TargetCompID" number="56"><![CDATA[target]]></field>
  </header>
  <body>
    <field name="SecurityIDSource" number="22" enum="EXCHANGE_SYMBOL"><![CDATA[8]]></field>
    <field name="OrdType" number="40" enum="LIMIT"><![CDATA[2]]></field>
    <field name="Price" number="44"><![CDATA[9]]></field>
    <field name="SecurityID" number="48"><![CDATA[ABC]]></field>
    <field name="Symbol" number="55"><![CDATA[ABC]]></field>
    <field name="TransactTime" number="60"><![CDATA[20060319-09:08:19]]></field>
    <field name="CrossID" number="548"><![CDATA[184214]]></field>
    <field name="CrossType" number="549" enum="CROSS_TRADE_WHICH_IS_EXECUTED_PARTIALLY_AND_THE_REST_IS_CANCELLED_ONE_SIDE_IS_FULLY_EXECUTED_THE_OTHER_SIDE_IS_PARTIALLY_EXECUTED_WITH_THE_REMAINDER_BEING_CANCELLED_THIS_IS_EQUIVALENT_TO_AN_IMMEDIATE_OR_CANCEL_ON_THE_OTHER_SIDE_NOTE_THE_CROSSPRIORITZATION"><![CDATA[2]]></field>
    <field name="CrossPrioritization" number="550" enum="NONE"><![CDATA[0]]></field>
    <field name="NoSides" number="552" enum="BOTH_SIDES"><![CDATA[2]]></field>
    <group>
      <field name="Side" number="54" enum="BUY"><![CDATA[1]]></field>
      <field name="NoPartyIDs" number="453"><![CDATA[2]]></field>
      <field name="OrderQty" number="38"><![CDATA[9]]></field>
      <group>
        <field name="PartyID" number="448"><![CDATA[8]]></field>
        <field name="PartyIDSource" number="447" enum="PROPRIETARY_CUSTOM_CODE"><![CDATA[D]]></field>
        <field name="PartyRole" number="452" enum="CLEARING_FIRM"><![CDATA[4]]></field>
      </group>
      <group>
        <field name="PartyID" number="448"><![CDATA[AAA35777]]></field>
        <field name="PartyIDSource" number="447" enum="PROPRIETARY_CUSTOM_CODE"><![CDATA[D]]></field>
        <field name="PartyRole" number="452" enum="CLIENT_ID"><![CDATA[3]]></field>
      </group>
    </group>
    <group>
      <field name="Side" number="54" enum="SELL"><![CDATA[2]]></field>
      <field name="NoPartyIDs" number="453"><![CDATA[2]]></field>
      <field name="OrderQty" number="38"><![CDATA[9]]></field>
      <group>
        <field name="PartyID" number="448"><![CDATA[8]]></field>
        <field name="PartyIDSource" number="447" enum="PROPRIETARY_CUSTOM_CODE"><![CDATA[D]]></field>
        <field name="PartyRole" number="452" enum="CLEARING_FIRM"><![CDATA[4]]></field>
      </group>
      <group>
        <field name="PartyID" number="448"><![CDATA[aaa]]></field>
        <field name="PartyIDSource" number="447" enum="PROPRIETARY_CUSTOM_CODE"><![CDATA[D]]></field>
        <field name="PartyRole" number="452" enum="CLIENT_ID"><![CDATA[3]]></field>
      </group>
    </group>
  </body>
  <trailer>
    <field name="CheckSum" number="10"><![CDATA[056]]></field>
  </trailer>
</message>
{
 "header": [
  {
   "number": "8",
   "name": "BeginString",
   "value": "FIX.4.4",
   "raw": "FIX.4.4",
   "type": "STRING"
  },
  {
   "number": "9",
   "name": "BodyLength",
   "value": 247,
   "raw": "247",
   "type": "LENGTH"
  },
  {
   "number": "35",
   "name": "MsgType",
   "enum": "NewOrderCross",
   "value": "s",
   "raw": "s",
   "type": "STRING"
  },
  {
   "number": "34",
   "name": "MsgSeqNum",
   "value": 5,
   "raw": "5",
   "type": "SEQNUM"
  },
  {
   "number": "49",
   "name": "SenderCompID",
   "value": "sender",
   "raw": "sender",
   "type": "STRING"
  },
  {
   "number": "52",
   "name": "SendingTime",
   "value": "20060319-09:08:20.881",
   "raw": "20060319-09:08:20.881",
   "type": "UTCTIMESTAMP"
  },
  {
   "number": "56",
   "name": "TargetCompID",
   "value": "target",
   "raw": "target",
   "type": "STRING"
  }
 ],
 "body": [
  {
   "number": "22",
   "name": "SecurityIDSource",
   "enum": "EXCHANGE_SYMBOL",
   "value": "8",
   "raw": "8",
   "type": "STRING"
  },
  {
   "number": "40",
   "name": "OrdType",
   "enum": "LIMIT",
   "value": "2",
   "raw": "2",
   "type": "CHAR"
  },
  {
   "number": "44",
   "name": "Price",
   "value": 9.0,
   "raw": "9",
   "type": "PRICE"
  },
  {
   "number": "48",
   "name": "SecurityID",
   "value": "ABC",
   "raw": "ABC",
   "type": "STRING"
  },
  {
   "number": "55",
   "name": "Symbol",
   "value": "ABC",
   "raw": "ABC",
   "type": "STRING"
  },
  {
   "number": "60",
   "name": "TransactTime",
   "value": "20060319-09:08:19",
   "raw": "20060319-09:08:19",
   "type": "UTCTIMESTAMP"
  },
  {
   "number": "548",
   "name": "CrossID",
   "value": "184214",
   "raw": "184214",
   "type": "STRING"
  },
  {
   "number": "549",
   "name": "CrossType",
   "enum": "CROSS_TRADE_WHICH_IS_EXECUTED_PARTIALLY_AND_THE_REST_IS_CANCELLED_ONE_SIDE_IS_FULLY_EXECUTED_THE_OTHER_SIDE_IS_PARTIALLY_EXECUTED_WITH_THE_REMAINDER_BEING_CANCELLED_THIS_IS_EQUIVALENT_TO_AN_IMMEDIATE_OR_CANCEL_ON_THE_OTHER_SIDE_NOTE_THE_CROSSPRIORITZATION",
   "value": 2,
   "raw": "2",
   "type": "INT"
  },
  {
   "number": "550",
   "name": "CrossPrioritization",
   "enum": "NONE",
   "value": 0,
   "raw": "0",
   "type": "INT"
  },
  {
   "number": "552",
   "name": "NoSides",
   "enum": "BOTH_SIDES",
   "value": 2,
   "raw": "2",
   "type": "NUMINGROUP",
   "groups": [
    [
     {
      "number": "54",
      "name": "Side",
      "enum": "BUY",
      "value": "1",
      "raw": "1",
      "type": "CHAR"
     },
     {
      "number": "453",
      "name": "NoPartyIDs",
      "groups": [
       [
        {
         "number": "448",
         "name": "PartyID",
         "value": "8",
         "raw": "8",
         "type": "STRING"
        },
        {
         "number": "447",
         "name": "PartyIDSource",
         "enum": "PROPRIETARY_CUSTOM_CODE",
         "value": "D",
         "raw": "D",
         "type": "CHAR"
        },
        {
         "number": "452",
         "name": "PartyRole",
         "enum": "CLEARING_FIRM",
         "value": 4,
         "raw": "4",
         "type": "INT"
        }
       ],
       [
        {
         "number": "448",
         "name": "PartyID",
         "value": "AAA35777",
         "raw": "AAA35777",
         "type": "STRING"
        },
        {
         "number": "447",
         "name": "PartyIDSource",
         "enum": "PROPRIETARY_CUSTOM_CODE",
         "value": "D",
         "raw": "D",
         "type": "CHAR"
        },
        {
         "number": "452",
         "name": "PartyRole",
         "enum": "CLIENT_ID",
         "value": 3,
         "raw": "3",
         "type": "INT"
        }
       ]
      ],
      "value": 2,
      "raw": "2",
      "type": "NUMINGROUP"
     },
     {
      "number": "38",
      "name": "OrderQty",
      "value": 9,
      "raw": "9",
      "type": "QTY"
     }
    ],
    [
     {
      "number": "54",
      "name": "Side",
      "enum": "SELL",
      "value": "2",
      "raw": "2",
      "type": "CHAR"
     },
     {
      "number": "453",
      "name": "NoPartyIDs",
      "groups": [
       [
        {
         "number": "448",
         "name": "PartyID",
         "value": "8",
         "raw": "8",
         "type": "STRING"
        },
        {
         "number": "447",
         "name": "PartyIDSource",
         "enum": "PROPRIETARY_CUSTOM_CODE",
         "value": "D",
         "raw": "D",
         "type": "CHAR"
        },
        {
         "number": "452",
         "name": "PartyRole",
         "enum": "CLEARING_FIRM",
         "value": 4,
         "raw": "4",
         "type": "INT"
        }
       ],
       [
        {
         "number": "448",
         "name": "PartyID",
         "value": "aaa",
         "raw": "aaa",
         "type": "STRING"
        },
        {
         "number": "447",
         "name": "PartyIDSource",
         "enum": "PROPRIETARY_CUSTOM_CODE",
         "value": "D",
         "raw": "D",
         "type": "CHAR"
        },
        {
         "number": "452",
         "name": "PartyRole",
         "enum": "CLIENT_ID",
         "value": 3,
         "raw": "3",
         "type": "INT"
        }
       ]
      ],
      "value": 2,
      "raw": "2",
      "type": "NUMINGROUP"
     },
     {
      "number": "38",
      "name": "OrderQty",
      "value": 9,
      "raw": "9",
      "type": "QTY"
     }
    ]
   ]
  }
 ],
 "trailer": [
  {
   "number": "10",
   "name": "CheckSum",
   "value": "056",
   "raw": "056",
   "type": "STRING"
  }
 ]
}
{
 "header": {
  "BeginString": "FIX.4.4",
  "BodyLength": 247,
  "MsgType": "NewOrderCross",
  "MsgSeqNum": 5,
  "SenderCompID": "sender",
  "SendingTime": "20060319-09:08:20.881",
  "TargetCompID": "target"
 },
 "body": {
  "SecurityIDSource": "EXCHANGE_SYMBOL",
  "OrdType": "LIMIT",
  "Price": 9.0,
  "SecurityID": "ABC",
  "Symbol": "ABC",
  "TransactTime": "20060319-09:08:19",
  "CrossID": "184214",
  "CrossType": "CROSS_TRADE_WHICH_IS_EXECUTED_PARTIALLY_AND_THE_REST_IS_CANCELLED_ONE_SIDE_IS_FULLY_EXECUTED_THE_OTHER_SIDE_IS_PARTIALLY_EXECUTED_WITH_THE_REMAINDER_BEING_CANCELLED_THIS_IS_EQUIVALENT_TO_AN_IMMEDIATE_OR_CANCEL_ON_THE_OTHER_SIDE_NOTE_THE_CROSSPRIORITZATION",
  "CrossPrioritization": "NONE",
  "NoSides": [
   {
    "Side": "BUY",
    "NoPartyIDs": [
     {
      "PartyID": "8",
      "PartyIDSource": "PROPRIETARY_CUSTOM_CODE",
      "PartyRole": "CLEARING_FIRM"
     },
     {
      "PartyID": "AAA35777",
      "PartyIDSource": "PROPRIETARY_CUSTOM_CODE",
      "PartyRole": "CLIENT_ID"
     }
    ],
    "OrderQty": 9
   },
   {
    "Side": "SELL",
    "NoPartyIDs": [
     {
      "PartyID": "8",
      "PartyIDSource": "PROPRIETARY_CUSTOM_CODE",
      "PartyRole": "CLEARING_FIRM"
     },
     {
      "PartyID": "aaa",
      "PartyIDSource": "PROPRIETARY_CUSTOM_CODE",
      "PartyRole": "CLIENT_ID"
     }
    ],
    "OrderQty": 9
   }
  ]
 },
 "trailer": {
  "CheckSum": "056"
 }
}
Alcuin answered 10/4, 2020 at 5:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.