Example #1
0
        /// <summary>
        /// The AddField method adds an instance of a FIX field
        /// to the collection. Multiple fields with the same tag
        /// can be added to the collection, and will be stored in
        /// a list that is keyed by the field's FIX tag.
        /// </summary>
        /// <param name="field">
        /// The FIX field to add to the collection.
        /// </param>
        public void AddField(FixField field)
        {
            // REC: Ensure that the field doesn't collide with
            // an existing group that has the same tag:
            if (!_mapGroups.ContainsKey(field.Tag))
            {
                if (!_mapFields.ContainsKey(field.Tag))
                {
                    _mapFields.Add(field.Tag, new List <FixField>());
                }

                _mapFields[field.Tag].Add(field);

                if (!_mapElements.ContainsKey(field.Tag))
                {
                    _mapElements.Add(field.Tag, new List <IFixElement>());
                }

                _mapElements[field.Tag].Add(field);

                // REC: Add to the sequential list:
                _listElements.Add(field);
            }
            else
            {
                throw new ArgumentException(string.Format("Field's tag collides with an existing group."));
            }
        }
Example #2
0
 /// <summary>
 /// The SetField method attempts to assign a value to
 /// a field in the collection. If the field is already
 /// present within the collection, the existing value is
 /// replaced with the supplied value. If the field is not
 /// already in the collection, the field is added to it.
 /// </summary>
 /// <param name="field">
 /// The FIX field instance that is to be either assigned
 /// or added to the collection. If the operation results
 /// in an assigment, the Content property of the supplied
 /// field is copied into the corresponding property of the
 /// existing field, otherwise the entire field instance is
 /// added to the collection.
 /// </param>
 public void SetField(FixField field)
 {
     // REC: If the field is not already present in the
     // collection, the request can be forwarded to the
     // regular AddField method:
     if (!_mapFields.ContainsKey(field.Tag))
     {
         AddField(field);
     }
     else
     {
         // REC: Ensure that the field doesn't collide
         // with a group that is already present:
         if (!_mapGroups.ContainsKey(field.Tag))
         {
             // REC: The content of the supplied field can
             // be assigned directly to the content property
             // of the existing field, this ensures that the
             // field remains in the same location that it is
             // in within the sequential list, as well as the
             // map, of existing elements.
             _mapFields[field.Tag][0].Content = field.Content;
         }
         else
         {
             throw new ArgumentException("Field collides with an existing group.");
         }
     }
 }
Example #3
0
        /// <summary>
        /// The GetField method returns the first instance of
        /// a field that matches the specified FIX tag.
        /// </summary>
        /// <param name="tag">
        /// The FIX tag of the field to retrieve.
        /// </param>
        /// <returns>
        /// The first instance of a FIX field in the collection
        /// that matches the specified tag, or null if there is
        /// no matching entry.
        /// </returns>
        public FixField GetField(int tag)
        {
            FixField result = null;

            if (_mapFields.ContainsKey(tag))
            {
                result = _mapFields[tag][0];
            }

            return(result);
        }
Example #4
0
        /// <summary>
        /// The Finalize method calculates the values for
        /// common session layer fields and assigns those
        /// values to their respective fields.
        /// </summary>
        /// <param name="msg">
        /// The FIX message to be finalized.
        /// </param>
        public static void Finalize(FixMessage msg)
        {
            // REC: Calculate sending time and add it to the message:
            string   strTimeStamp   = DateTime.UtcNow.ToString("yyyyMMdd-HH:mm:ss.fff");
            FixField fldSendingTime = msg.Header.GetField(52);

            if (fldSendingTime != null)
            {
                fldSendingTime.Content = strTimeStamp;
            }
            else
            {
                msg.Header.AddField(new FixField(52, strTimeStamp));
            }

            // REC: Calculate the body length and add it to the message:
            int      fixBodyLength = FixCalculator.GetBodyLength(msg);
            FixField fldBodyLength = msg.Header.GetField(9);

            if (fldBodyLength != null)
            {
                fldBodyLength.Content = fixBodyLength.ToString();
            }
            else
            {
                msg.Header.AddField(new FixField(9, fixBodyLength.ToString()));
            }

            // REC: Calculate the checksum and add it to the message:
            string   strChecksum = string.Format("{0:000}", FixCalculator.GetChecksum(msg) % 256);
            FixField fldChecksum = msg.Trailer.GetField(10);

            if (fldChecksum != null)
            {
                fldChecksum.Content = strChecksum;
            }
            else
            {
                msg.Trailer.AddField(new FixField(10, strChecksum));
            }
        }
Example #5
0
        /// <summary>
        /// The ParseHeader method attempts to parse the header of
        /// a FIX message from the buffer in the parser's context:
        /// </summary>
        /// <param name="ctx">
        /// The parser's current context.
        /// </param>
        /// <param name="result">
        /// The parser's result information.
        /// </param>
        private void ParseHeader(ParseContext ctx, VfxFixParserResult result)
        {
            // REC: Default to success, let the parse logic
            // override this if an error occurs:
            result.Status = VfxFixParserStatus.MsgComplete;

            // REC: Start extracting FIX fields from the buffer:
            while (ctx.Index < ctx.Buffer.Length)
            {
                // REC: Reset index value in case there
                // is an error parsing the buffer:
                int idxRst = ctx.Index;

                int idxSep = ctx.Buffer.IndexOf('=', ctx.Index);
                int idxSoh = ctx.Buffer.IndexOf('\x01', idxSep + 1);

                // REC: If the separator or SOH fields were not
                // found, then the header is incomplete and the
                // parsing cannot continue:
                if ((idxSep == -1) || (idxSoh == -1))
                {
                    result.Consumed = 0;
                    result.Status = VfxFixParserStatus.MsgExhausted;
                    return;
                }

                // REC: Extract the field's tag from the message:
                string strTag = ctx.Buffer.Substring(ctx.Index, idxSep - ctx.Index);

                // REC: Convert the field's tag from its string
                // form into its corresponding integer value:
                int nTag = -1;
                if (int.TryParse(strTag, out nTag) == false)
                {
                    // REC: If the field cannot be converted into
                    // an integer, the message is malformed:
                    result.Consumed = 0;
                    result.Status = VfxFixParserStatus.MsgMalformed;
                    return;
                }

                // REC: If the FIX BeginString has already been parsed
                // from the buffer, and is encountered again, then the
                // message was incomplete and cannot be parsed:
                if (nTag == 8)
                {
                    if (result.Message.Header.GetField(8) != null)
                    {
                        // REC: Reset the index into the message:
                        ctx.Index = idxRst;
                        // REC: Adjust the result accordingly:
                        result.Consumed = 0;
                        result.Status = VfxFixParserStatus.MsgIncomplete;
                        return;
                    }
                }

                // REC: Determine whether or not the version of the
                // session protocol has been discovered yet:
                if (ctx.HdrElements != null)
                {
                    IFixDxElement hdrElement = ctx.HdrElements.GetElement(nTag);
                    if (hdrElement != null)
                    {
                        if (hdrElement is FixDxResolvedField)
                        {
                            // REC: Retrieve the field's value:
                            string strVal = ctx.Buffer.Substring(idxSep + 1, idxSoh - (idxSep + 1));

                            FixField field = new FixField(nTag, strVal);
                            result.Message.Header.AddField(field);

                            ctx.Index = idxSoh + 1;
                        }
                        else if (hdrElement is FixDxResolvedGroup)
                        {
                            FixDxResolvedGroup groupEntry = hdrElement as FixDxResolvedGroup;

                            // REC: Since this field is a group entry it's ok
                            // to assume that the value is the number of groups
                            // that follow the group tag:
                            string strVal = ctx.Buffer.Substring(idxSep + 1, idxSoh - (idxSep + 1));

                            // REC: Convert the value into an integer and then
                            // attempt to exract that number of repeating groups:
                            int nGroups = 0;
                            if (int.TryParse(strVal, out nGroups) == true)
                            {
                                // REC: Move the context's read index ahead
                                // to compensate for reading the repeating
                                // group's tag and associated value:
                                ctx.Index = idxSoh + 1;

                                FixGroup group = new FixGroup(nTag, strVal);

                                // REC: Try to parse N instances of the
                                // repeating group from the message:
                                ParseGroupResult parseResult = ParseGroup(ctx, groupEntry, nGroups);

                                if (parseResult.Status != VfxFixParserStatus.MsgComplete)
                                {
                                    return;
                                }

                                foreach (FixCollection instance in parseResult.Instances)
                                {
                                    group.Instances.Add(instance);
                                }

                                result.Message.Header.AddGroup(group);
                            }
                            else
                            {
                                // REC: The value in the group tag couldn't
                                // be converted into an integer, so the
                                // number of repeating groups is unknown.
                                FixGroup group = new FixGroup(nTag, strVal);
                                result.Message.Header.AddGroup(group);

                                // REC: Move the context's read index ahead
                                // to compensate for reading the repeating
                                // group's tag and associated value:
                                ctx.Index = idxSoh + 1;
                            }

                        }
                    }
                    else
                    {
                        // REC: The parser doesn't support UDFs in the
                        // header section of the message, so the result
                        // is considered complete if we hit a field that
                        // isn't in the session protocol dictionary:
                        break;
                    }
                }
                else
                {
                    // REC: The session protocol isn't known yet, so the
                    // field is considered a plain FIX field and added to
                    // the message's header:
                    string strVal = ctx.Buffer.Substring(idxSep + 1, idxSoh - (idxSep + 1));

                    FixField field = new FixField(nTag, strVal);
                    result.Message.Header.AddField(field);
                    ctx.Index = idxSoh + 1;

                    // REC: Attempt to determine the session layer protocol
                    // based on the header elements that have been parsed:
                    ctx.SxVersion = _vxMatcher.GetVersion(result.Message.Header, "session");
                    if (ctx.SxVersion == null)
                    {
                        // REC: If no session layer dictionary matched the
                        // elements that have been parsed so far, check for
                        // a combined version definition in case the session
                        // is running FIX versions 4.0-4.4 which do not have
                        // separate session and application layer versions:
                        ctx.SxVersion = _vxMatcher.GetVersion(result.Message.Header, "combined");
                    }

                    // REC: The elements in the message header correspond
                    // to a specific data dictionary, so that should be
                    // used for parsing the header and trailer elements:
                    if (ctx.SxVersion != null)
                    {
                        InitCachedHdrElements(ctx.SxVersion);
                        InitCachedTrlElements(ctx.SxVersion);

                        // REC: Assign the cached sets of resolved header
                        // and trailer elements to the parse context:
                        ctx.HdrElements = _hdrElements[ctx.SxVersion];
                        ctx.TrlElements = _trlElements[ctx.SxVersion];
                    }
                }
            }

            // REC: Determine if the message belongs to the session
            // layer protocol as opposed to the application layer:
            if (ctx.SxVersion != null)
            {
                // REC: Retrieve the FIX message type:
                FixField msgType = result.Message.Header.GetField(35);
                if (!string.IsNullOrEmpty(msgType.Content))
                {
                    // REC: Check the version definition registry for the
                    // corresponding protocol version definition:
                    VfxFixVxRecord vxDefinition = this._vxRegistry.Get(ctx.SxVersion);
                    if (vxDefinition != null)
                    {
                        // REC: Retrieve the associated dictionary from the
                        // configured FIX dictionary registry:
                        FixDictionary dxInstance = this._dxRegistry.GetEntry(vxDefinition.Dictionaries[0].Name);
                        if (dxInstance != null)
                        {
                            // REC: Check if the message is defined within the
                            // dictionary for the session layer:
                            FixDxMessage sxMessage = dxInstance.GetMessageByType(msgType.Content);
                            if (sxMessage != null)
                            {
                                if ((!_msgElements.ContainsKey(ctx.SxVersion)) || (!_msgElements[ctx.SxVersion].Elements.ContainsKey(msgType.Content)))
                                {
                                    InitCachedMsgElements(ctx, msgType.Content);
                                }

                                // REC: Look in the message definition cache
                                // for this particular message type:
                                if (_msgElements[ctx.SxVersion].Elements.ContainsKey(msgType.Content))
                                {
                                    ctx.MsgElements = _msgElements[ctx.SxVersion].Elements[msgType.Content];
                                }

                                // REC: The context is now initialized to parse the
                                // session layer message's content, so we're done:
                                return;
                            }
                        }
                    }
                }
            }

            // REC: If an override version has been specified for the
            // application layer, use that instead of hunting for it:
            if (ctx.AxVersion == null)
            {
                // REC: Now that the entire header of the message has been
                // extracted from the buffer, test the header contents and
                // determine the application protocol version:
                ctx.AxVersion = _vxMatcher.GetVersion(result.Message.Header, "application");
                if (ctx.AxVersion == null)
                {
                    // REC: If the application layer version cannot be
                    // determined, it may be a FIX 4.0-4.4 message, so
                    // check the combined versions as well:
                    ctx.AxVersion = _vxMatcher.GetVersion(result.Message.Header, "combined");
                    if(ctx.AxVersion == null)
                    {
                        // REC: If the application layer could not be
                        // resolved, then switch to the default:
                        ctx.AxVersion = ctx.AxDefault;
                    }
                }
            }

            if (ctx.AxVersion != null)
            {
                // REC: Now that the application version has been
                // determined, retrieve the message elements for
                // the type of message being parsed, initializing
                // the local message elements cache if needed:
                FixField msgType = result.Message.Header.GetField(35);
                if (msgType != null)
                {
                    if ((!_msgElements.ContainsKey(ctx.AxVersion)) || (!_msgElements[ctx.AxVersion].Elements.ContainsKey(msgType.Content)))
                    {
                        InitCachedMsgElements(ctx, msgType.Content);
                    }

                    // REC: Look in the message definition cache
                    // for this particular message type:
                    if (_msgElements[ctx.AxVersion].Elements.ContainsKey(msgType.Content))
                    {
                        ctx.MsgElements = _msgElements[ctx.AxVersion].Elements[msgType.Content];
                    }
                }
            }
        }
Example #6
0
        /// <summary>
        /// The ParseContent method attempts to parse the message body
        /// from an instance of a FIX message.
        /// </summary>
        /// <param name="ctx">
        /// The parser's context information.
        /// </param>
        /// <param name="result">
        /// The parser's result information.
        /// </param>
        private void ParseContent(ParseContext ctx, VfxFixParserResult result)
        {
            // REC: Attempt to retrieve the FIX message type
            // from the header of the message:
            FixField msgType = result.Message.Header.GetField(35);

            while (ctx.Index < ctx.Buffer.Length)
            {
                int idxSep = ctx.Buffer.IndexOf('=', ctx.Index);
                int idxSoh = ctx.Buffer.IndexOf('\x01', idxSep + 1);

                // REC: If the separator or SOH fields were not
                // found, then the message is incomplete and the
                // parsing cannot continue:
                if ((idxSep == -1) || (idxSoh == -1))
                {
                    result.Status = VfxFixParserStatus.MsgExhausted;
                    return;
                }

                // REC: Extract the field's tag from the message:
                string strTag = ctx.Buffer.Substring(ctx.Index, idxSep - ctx.Index);
                // REC: Convert the field's tag to an integer:
                int nTag;
                if (int.TryParse(strTag, out nTag) == false)
                {
                    result.Status = VfxFixParserStatus.MsgMalformed;
                    return;
                }

                // REC: Test for premature message termination:
                if (nTag == 8)
                {
                    result.Status = VfxFixParserStatus.MsgMalformed;
                    return;
                }

                if (ctx.MsgElements != null)
                {
                    IFixDxElement element = ctx.MsgElements.GetElement(nTag);
                    if (element != null)
                    {
                        if (element is FixDxResolvedField)
                        {
                            // REC: Retrieve the field's value:
                            string strVal = ctx.Buffer.Substring(idxSep + 1, idxSoh - (idxSep + 1));

                            // REC: Create a new field to represent
                            // the parsed field/value pair:
                            FixField field = new FixField(nTag, strVal);
                            result.Message.AddField(field);
                            ctx.Index = idxSoh + 1;
                        }
                        else if (element is FixDxResolvedGroup)
                        {
                            // REC: Since this field is a group entry it's ok
                            // to assume that the value is the number of groups
                            // that follow the group tag:
                            string strVal = ctx.Buffer.Substring(idxSep + 1, idxSoh - (idxSep + 1));

                            // REC: Convert the value into an integer and then
                            // attempt to exract that number of repeating groups:
                            int nGroups = 0;
                            if (int.TryParse(strVal, out nGroups) == true)
                            {
                                // REC: Move the context's read index ahead
                                // to compensate for reading the repeating
                                // group's tag and associated value:
                                ctx.Index = idxSoh + 1;

                                FixGroup group = new FixGroup(nTag, strVal);

                                // REC: Try to parse N instances of the
                                // repeating group from the message:
                                FixDxResolvedGroup resolvedGroup = element as FixDxResolvedGroup;
                                ParseGroupResult parseResult = ParseGroup(ctx, resolvedGroup, nGroups);

                                if (parseResult.Status != VfxFixParserStatus.MsgComplete)
                                {
                                    result.Status = parseResult.Status;
                                    return;
                                }

                                foreach (FixCollection instance in parseResult.Instances)
                                {
                                    group.Instances.Add(instance);
                                }

                                result.Message.AddGroup(group);

                            }
                            else
                            {
                                // REC: The value in the group tag couldn't
                                // be converted into an integer, so the
                                // number of repeating groups is unknown.
                                FixGroup group = new FixGroup(nTag, strVal);
                                result.Message.AddGroup(group);

                                // REC: Move the context's read index ahead
                                // to compensate for reading the repeating
                                // group's tag and associated value:
                                ctx.Index = idxSoh + 1;
                            }
                        }
                    }
                    else
                    {
                        // REC: The tag wasn't found in the map of elements
                        // that are known for this message type, so determine
                        // whether it is a UDF or a field from the trailer:
                        if (ctx.TrlElements.GetElement(nTag) != null)
                        {
                            // REC: The field is a trailer element
                            // so content parsing is now complete:
                            return;
                        }
                        else
                        {
                            // REC: The field is just a UDF so it can be added
                            // to the message body:
                            string strVal = ctx.Buffer.Substring(idxSep + 1, idxSoh - (idxSep + 1));

                            FixField field = new FixField(nTag, strVal);
                            result.Message.AddField(field);

                            ctx.Index = idxSoh + 1;
                        }
                    }
                }
                else
                {
                    // REC: There is no cached set of elements for this
                    // type of message, so the field is either a trailer
                    // field or it is a user-defined field:
                    if (ctx.TrlElements.GetElement(nTag) != null)
                    {
                        // REC: The field is a trailer element
                        // so content parsing is now complete:
                        return;
                    }
                    else
                    {
                        // REC: The field is just a UDF so it can be added
                        // to the message body:
                        string strVal = ctx.Buffer.Substring(idxSep + 1, idxSoh - (idxSep + 1));

                        FixField field = new FixField(nTag, strVal);
                        result.Message.AddField(field);

                        ctx.Index = idxSoh + 1;
                    }
                }
            }
        }
Example #7
0
        private void ParseTrailer(ParseContext ctx, VfxFixParserResult result)
        {
            while (ctx.Index < ctx.Buffer.Length)
            {
                int idxSep = ctx.Buffer.IndexOf('=', ctx.Index);
                int idxSoh = ctx.Buffer.IndexOf('\x01', idxSep + 1);

                // REC: If the separator or SOH fields were not
                // found, then the message is incomplete and the
                // parsing cannot continue:
                if ((idxSep == -1) || (idxSoh == -1))
                {
                    // result.Consumed = 0;
                    result.Status = VfxFixParserStatus.MsgExhausted;
                    return;
                }

                // REC: Extract the field's tag from the message:
                string strTag = ctx.Buffer.Substring(ctx.Index, idxSep - ctx.Index);

                // REC: Convert the field's tag to an integer:
                int nTag;
                if (int.TryParse(strTag, out nTag) == false)
                {
                    result.Status = VfxFixParserStatus.MsgMalformed;
                    return;
                }

                if (ctx.TrlElements != null)
                {
                    IFixDxElement element = ctx.TrlElements.GetElement(nTag);
                    if(element != null)
                    {
                        if (element is FixDxResolvedField)
                        {
                            // REC: Retrieve the field's value:
                            string strVal = ctx.Buffer.Substring(idxSep + 1, idxSoh - (idxSep + 1));

                            // REC: Create a new field to represent
                            // the parsed field/value pair:
                            FixField field = new FixField(nTag, strVal);
                            result.Message.Trailer.AddField(field);
                            ctx.Index = idxSoh + 1;
                        }
                        else if (element is FixDxResolvedGroup)
                        {
                            FixDxResolvedGroup groupEntry = element as FixDxResolvedGroup;
                            // REC: Since this field is a group entry it's ok
                            // to assume that the value is the number of groups
                            // that follow the group tag:
                            string strVal = ctx.Buffer.Substring(idxSep + 1, idxSoh - (idxSep + 1));

                            // REC: Convert the value into an integer and then
                            // attempt to exract that number of repeating groups:
                            int nGroups = 0;
                            if (int.TryParse(strVal, out nGroups) == true)
                            {
                                // REC: Move the context's read index ahead
                                // to compensate for reading the repeating
                                // group's tag and associated value:
                                ctx.Index = idxSoh + 1;

                                FixGroup group = new FixGroup(nTag, strVal);

                                // REC: Try to parse N instances of the
                                // repeating group from the message:
                                ParseGroupResult parseResult = ParseGroup(ctx, groupEntry, nGroups);

                                if (parseResult.Status != VfxFixParserStatus.MsgComplete)
                                {
                                    result.Status = parseResult.Status;
                                    return;
                                }

                                foreach (FixCollection instance in parseResult.Instances)
                                {
                                    group.Instances.Add(instance);
                                }

                                result.Message.Trailer.AddGroup(group);

                            }
                            else
                            {
                                // REC: The value in the group tag couldn't
                                // be converted into an integer, so the
                                // number of repeating groups is unknown.
                                FixGroup group = new FixGroup(nTag, strVal);
                                result.Message.Trailer.AddGroup(group);

                                // REC: Move the context's read index ahead
                                // to compensate for reading the repeating
                                // group's tag and associated value:
                                ctx.Index = idxSoh + 1;
                            }
                        }
                    }
                    else
                    {
                        // REC: If the element is not in the set of trailer
                        // elements, then the parsing is complete.
                        return;
                    }
                }
                else
                {
                    result.Status = VfxFixParserStatus.MsgUnkSxProtocol;
                    return;
                }
            }
        }
Example #8
0
 /// <summary>
 /// The AddField method adds an instance of a FIX field
 /// to the body of the message.
 /// </summary>
 /// <param name="field"></param>
 public void AddField(FixField field)
 {
     _msgElements.AddField(field);
 }
Example #9
0
 /// <summary>
 /// The SetField method registers an instance of a field with 
 /// the assembler. The assembler will use this field whenever
 /// it constructs a message that contains the field's tag.
 /// </summary>
 /// <param name="field">
 /// The FIX field to register with the assembler.
 /// </param>
 public void SetField(FixField field)
 {
     if (!_mapFields.ContainsKey(field.Tag))
     {
         _mapFields.Add(field.Tag, field);
     }
     else
     {
         _mapFields[field.Tag] = field;
     }
 }