Пример #1
0
        /// <summary>
        /// Adds an array of fields to the FixMessage.
        /// </summary>
        /// <param name="fields">An array of fields.</param>
        private void AddFieldArray(string[] fields)
        {
            // This local is used for repeating groups (see below.)
            StringCollection groupFields = new StringCollection();

            // Add each field after parse the values into a "Tag=Value" pair.
            foreach (string field in fields)
            {
                // The 'Split' method has a bothersome habit of leaving a null entry when a token delimiter ends up a the end
                // of the string.  This will quickly filter out those byproducts of the 'Split'.
                if (field == string.Empty)
                {
                    continue;
                }

                // Break the field up into the 'Tag' and 'Value' fields, parse them and add them to the hash table.
                string[] values = field.Split('=');
                if (values.Length > 1)
                {
                    try
                    {
                        //tagNumber
                        Tag tag = TagConverter.ConvertFrom(values[0]);

                        string stringValue = values[1];

                        // Handle repeating group fields here.
                        // Per the FIX spec:
                        //  "Fields within repeating data groups must be specified in the order that the fields are
                        //  specified in the message definition within the FIX specification document. The NoXXX field,
                        //  where XXX is the field being counted, specifies the number of repeating group instances and
                        //  must immediately precede the repeating group contents."
                        // Generally:
                        //   1. record the number of repeating group instances for a group when the NoXXX field occurs.
                        //   2. when each field in the group is read, save it in the groupFields array, unless it the last field.
                        //   3. when the last field of the group occurs, add a group entry to the group object.
                        // Order is important (See note from FIX spec above.) groupFields index 0 is the first field of the group, 1 is the second, etc.
                        // The xxxxGroup object (derived from class RepeatingGroup) holds the all of the repeating groups relating to "xxxx".
                        // Each repeating group in xxxxGroup is called an Entry.
                        // The groupFields array is temp space to hold the group fields as they are read from the FIX string.
                        switch (tag)
                        {
                        // IOIQualifiers.
                        // There is only one field (IOIQualifier) in each group, so groupFields is not used.
                        case Tag.NoIOIQualifiers:
                            // This field indicates the start of a set of repeating groups.
                            // But for FIX 4.0, only one IOIQualifier is allowed and this field is not used.
                            // So don't create the group object here, create it when the first qualifier is encountered.
                            // See IOIQualifier below.
                            break;

                        case Tag.IOIQualifier:
                            if (!this.ContainsKey(Tag.IoiQualifierGroup))
                            {
                                // if there is not yet an IoiQualifierGroup, create the group object to hold the repeating groups.
                                this[Tag.IoiQualifierGroup] = new IoiQualifierGroup();
                            }
                            // get the group object created previously.
                            IoiQualifierGroup ioiQualifierGroup = (IoiQualifierGroup)this[Tag.IoiQualifierGroup];
                            // IOIQualifier is the only field in this group, so add the group to the IoiQualifierGroup object.
                            // IOIQualifier is not a string in FixMessage, so it needs to be parsed into its correct type.
                            ioiQualifierGroup.Add((IOIQualifier)FixMessage.Parse(tag, stringValue));
                            break;

                        // RoutingIDs. (Valid in FIX 4.2 only.)
                        // There are 2 fields in each group here, so save the first one in the groupFields array.
                        // (It could just be saved in a string variable, but the array is more general. A group can have more than 2 fields.)
                        // For example:
                        // The following FIX string describes three repeating groups for Routing (215=3), with the first group having
                        // two fields: RoutingType=3 (216=3), and RoutingID=RTEID1 (217=RTEID1). Similarly for groups 2 and 3.
                        // 215=3|216=3|217=RTEID1|216=3|217=RTEID2|216=3|217=RTEID3|
                        case Tag.NoRoutingIDs:
                            // This field indicates the start of a set of repeating groups.
                            // Create the group object to hold the repeating groups.
                            this[Tag.RoutingGroup] = new RoutingGroup();
                            break;

                        case Tag.RoutingType:
                            // Save the RoutingType string in the groupFields collection.
                            groupFields.Add(stringValue);
                            break;

                        case Tag.RoutingID:
                            // RoutingID is the last field in this group, so add the group to the RoutingGroup object.
                            if (this.Contains(Tag.RoutingGroup))
                            {
                                // get the group object created above.
                                RoutingGroup routingGroup = (RoutingGroup)this[Tag.RoutingGroup];
                                if (groupFields.Count > 0)
                                {
                                    // Add the current group fields to the group object.
                                    // The first (and in this case only) item in the groupFields array is RoutingType.
                                    // RoutingType combined with the RoutingID is a complete group.
                                    // RoutingID is a string in FixMessage, so it doesn't need to be parsed.
                                    // RoutingType is not a string in FixMessage, so it needs to be parsed into its correct type.
                                    RoutingType routingType = (RoutingType)FixMessage.Parse(Tag.RoutingType, groupFields[0]);
                                    routingGroup.Add(routingType, stringValue);

                                    // once the group has been added, clear out the temp array for the next group.
                                    groupFields.Clear();
                                }
                            }
                            break;

                        // Regular processing of (non-repeating) FIX fields.
                        default:
                            this[tag] = FixMessage.Parse(tag, stringValue);
                            break;
                        }
                    }
                    catch
                    {
                        string SenderComp = this.Contains(Tag.SenderCompID) ? this.SenderCompID : string.Empty;
                        string TargetComp = this.Contains(Tag.TargetCompID) ? this.TargetCompID : string.Empty;
                        Log.Error("MsgSeqNum={0}, SenderCompID={1}, TargetCompID={2}: Can't parse FIX field {3}={4}. Field ignored.", this.MsgSeqNum, SenderComp, TargetComp, values[0], values[1]);
                    }
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Packs the FIX Message into FIX string.
        /// </summary>
        /// <returns>the FIX Message string.</returns>
        public override string ToString()
        {
            string beginStringField = string.Empty;
            string msgTypeField     = string.Empty;
            string headerFields     = string.Empty;
            string bodyFields       = string.Empty;
            string fieldValue       = string.Empty;

            if (!this.Contains(Tag.BeginString))
            {
                throw new MissingFieldException("FIX BeginString field is missing");
            }
            if (!this.Contains(Tag.MsgType))
            {
                throw new MissingFieldException("FIX MsgType field is missing");
            }

            // Create a stream of bytes from the fields in the FIX message.  Remember that a hashtable -- the underlying data store
            // for the message -- iterates through the fields in a random order.  This is fine for most FIX fields, but some in the
            // header and the trailer must be in a specified order in the packet, so these fields are pulled out of the message
            // during this loop and assembled later into the final message.
            foreach (Field field in this)
            {
                switch (field.Tag)
                {
                case Tag.BeginString:

                    // The 'BeginString' must always be the first field in the message.
                    beginStringField = TagConverter.ConvertTo(Tag.BeginString) + "=" + field.Value.ToString() + FixSeparator.ToString();
                    break;

                case Tag.BodyLength:
                case Tag.CheckSum:
                    // these are calculated below once the FIX string is assembled.
                    break;

                case Tag.MsgType:

                    // The 'MsgType' field is always the third field in the message.
                    string msgTypeValue = MsgTypeConverter.ConvertTo((MsgType)field.Value);
                    msgTypeField = TagConverter.ConvertTo(Tag.MsgType) + "=" + msgTypeValue + FixSeparator.ToString();
                    break;

                //////////////////
                // Header Fields
                //////////////////
                case Tag.PossDupFlag:
                    //case Tag.PossResend:

                    // bool Header Fields
                    headerFields += TagConverter.ConvertTo(field.Tag) + "=" + ((bool)field.Value ? "Y" : "N") + FixSeparator.ToString();
                    break;

                case Tag.SendingTime:
                //case Tag.OnBehalfOfSendingTime:
                case Tag.OrigSendingTime:

                    // DateTime Header Fields.
                    headerFields += TagConverter.ConvertTo(field.Tag) + "=" + ((DateTime)field.Value).ToString("yyyyMMdd-HH:mm:ss") + FixSeparator.ToString();
                    break;

                case Tag.MsgSeqNum:

                    // MsgSeqNum Header Field.
                    headerFields += TagConverter.ConvertTo(field.Tag) + "=" + field.Value.ToString() + FixSeparator.ToString();
                    break;

                case Tag.DeliverToCompID:
                //case Tag.DeliverToLocationID:
                case Tag.DeliverToSubID:
                case Tag.OnBehalfOfCompID:
                //case Tag.OnBehalfOfLocationID:
                case Tag.OnBehalfOfSubID:
                case Tag.SenderCompID:
                //case Tag.SenderLocationID:
                case Tag.SenderSubID:
                case Tag.TargetCompID:
                case Tag.TargetLocationID:
                case Tag.TargetSubID:

                    // ID Header Fields.
                    headerFields += TagConverter.ConvertTo(field.Tag) + "=" + field.Value.ToString() + FixSeparator.ToString();
                    break;

                //////////////////
                // Body Fields
                //////////////////
                // These are the Body Fields ( in alpha order) that require some conversion or business logic.
                // The 'default' case takes care of the rest.
                case Tag.Account:

                    // the Account Body Field is not valid in a cancel message before FIX 4.2
                    if (!this.MsgType.Equals(MsgType.OrderCancelRequest) ||
                        (this.MsgType.Equals(MsgType.OrderCancelRequest) && !this.BeginString.Equals("FIX.4.0") && !this.BeginString.Equals("FIX.4.1")))
                    {
                        if (field.Value != null)
                        {
                            bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + field.Value.ToString() + FixSeparator.ToString();
                        }
                    }
                    break;

                case Tag.BusinessRejectReason:

                    // BusinessRejectReason Body Field
                    fieldValue  = BusinessRejectReasonConverter.ConvertTo((BusinessRejectReason)field.Value);
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    break;

                case Tag.CommType:

                    // CommType Body Field
                    fieldValue  = CommTypeConverter.ConvertTo((CommType)field.Value);
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    break;

                case Tag.CxlRejReason:

                    // CxlRejReason Body Field.
                    // Only FIX 4.2 and above allow CxlRejReason > 1. (1=CxlRejReason.UnknownOrder).
                    if (this.BeginString.Equals("FIX.4.0") || this.BeginString.Equals("FIX.4.1"))
                    {
                        if ((CxlRejReason)field.Value > CxlRejReason.UnknownOrder)
                        {
                            // default to TooLateToCancel
                            field.Value = CxlRejReason.TooLateToCancel;
                        }
                    }
                    fieldValue  = CxlRejReasonConverter.ConvertTo((CxlRejReason)field.Value);
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    break;

                case Tag.CxlRejResponseTo:

                    // the CxlRejResponseTo Body Field is not valid in a cancel-reject message before FIX 4.2
                    if (!this.MsgType.Equals(MsgType.OrderCancelReject) ||
                        (this.MsgType.Equals(MsgType.OrderCancelReject) && !this.BeginString.Equals("FIX.4.0") && !this.BeginString.Equals("FIX.4.1")))
                    {
                        fieldValue  = CxlRejResponseToConverter.ConvertTo((CxlRejResponseTo)field.Value);
                        bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    }
                    break;

                case Tag.CxlType:

                    // CxlType Body Field Only for FIX 4.0
                    if (this.BeginString.Equals("FIX.4.0"))
                    {
                        fieldValue  = CxlTypeConverter.ConvertTo((CxlType)field.Value);
                        bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    }
                    break;

                case Tag.DiscretionInst:

                    // DiscretionInst Body Field
                    fieldValue  = DiscretionInstConverter.ConvertTo((DiscretionInst)field.Value);
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    break;

                case Tag.DKReason:

                    // DKReason Body Field
                    fieldValue  = DKReasonConverter.ConvertTo((DKReason)field.Value);
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    break;

                case Tag.EncryptMethod:

                    // EncryptMethod Body Field
                    fieldValue  = EncryptMethodConverter.ConvertTo((EncryptMethod)field.Value);
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    break;

                case Tag.ExecTransType:

                    // ExecTransType Body Field
                    fieldValue  = ExecTransTypeConverter.ConvertTo((ExecTransType)field.Value);
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    break;

                case Tag.ExecType:

                    // ExecType Body Field - Not valid in FIX 4.0
                    if (!this.BeginString.Equals("FIX.4.0"))
                    {
                        fieldValue  = ExecTypeConverter.ConvertTo((ExecType)field.Value);
                        bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    }
                    break;

                case Tag.ExpireTime:

                    // ExpireTime Body Field
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + ((DateTime)field.Value).ToString("yyyyMMdd-HH:mm:ss") + FixSeparator.ToString();
                    break;

                case Tag.GapFillFlag:

                    // GapFillFlag Body Field
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + ((bool)field.Value ? "Y" : "N") + FixSeparator.ToString();
                    break;

                case Tag.HandlInst:

                    // HandlInst Body Field
                    fieldValue  = HandlInstConverter.ConvertTo((HandlInst)field.Value);
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    break;

                case Tag.IOINaturalFlag:

                    // IOINaturalFlag Body Field
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + ((bool)field.Value ? "Y" : "N") + FixSeparator.ToString();
                    break;

                case Tag.IOIQltyInd:

                    // IOIQltyInd Body Field
                    fieldValue  = IOIQltyIndConverter.ConvertTo((IOIQltyInd)field.Value);
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    break;

                case Tag.IoiQualifierGroup:

                    // Expand the repeating group fields.
                    IoiQualifierGroup ioiQualifierGroup = (IoiQualifierGroup)field.Value;
                    if ((ioiQualifierGroup != null) && (ioiQualifierGroup.Count > 0))
                    {
                        // The 'NoIOIQualifiers' field is only valid for FIX 4.1 and above.
                        if (!this.BeginString.Equals("FIX.4.0"))
                        {
                            // the number of repeating instances goes in the 'NoIOIQualifiers' field.
                            bodyFields += TagConverter.ConvertTo(Tag.NoIOIQualifiers) + "=" + ioiQualifierGroup.Count.ToString() + FixSeparator.ToString();
                        }
                        // Add the qualifiers.
                        foreach (IoiQualifierGroup.Entry entry in ioiQualifierGroup)
                        {
                            fieldValue  = IoiQualifierConverter.ConvertTo(entry.IoiQualifier);
                            bodyFields += TagConverter.ConvertTo(Tag.IOIQualifier) + "=" + fieldValue + FixSeparator.ToString();

                            // FIX 4.0 only supports 1 qualifier.
                            if (this.BeginString.Equals("FIX.4.0"))
                            {
                                break;
                            }
                        }
                    }
                    break;

                // These fields should be part of the repeating group "IoiQualifierGroup",
                // and should NOT be used individually.
                case Tag.NoIOIQualifiers:
                case Tag.IOIQualifier:
                    break;

                case Tag.IOITransType:

                    // IOITransType Body Field
                    fieldValue  = IOITransTypeConverter.ConvertTo((IOITransType)field.Value);
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    break;

                case Tag.LastCapacity:

                    // LastCapacity Body Field
                    fieldValue  = LastCapacityConverter.ConvertTo((LastCapacity)field.Value);
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    break;

                case Tag.LeavesQty:

                    // LeavesQty Body Field - Not valid in FIX 4.0
                    if (!this.BeginString.Equals("FIX.4.0"))
                    {
                        fieldValue  = field.Value.ToString();
                        bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    }
                    break;

                case Tag.MaturityMonthYear:

                    // MaturityMonthYear Body Field
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + ((DateTime)field.Value).ToString("yyyyMM") + FixSeparator.ToString();
                    break;

                case Tag.OpenClose:

                    // OpenClose Body Field
                    fieldValue  = OptionPositionTypeConverter.ConvertTo((OptionPositionType)field.Value);
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    break;

                case Tag.OrdRejReason:

                    // OrdRejReason Body Field
                    fieldValue  = OrdRejReasonConverter.ConvertTo((OrdRejReason)field.Value);
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    break;

                case Tag.OrdStatus:

                    // the OrdStatus Body Field is not valid in a cancel-reject message before FIX 4.1
                    if (!this.MsgType.Equals(MsgType.OrderCancelReject) ||
                        (this.MsgType.Equals(MsgType.OrderCancelReject) && !this.BeginString.Equals("FIX.4.0")))
                    {
                        fieldValue  = OrdStatusConverter.ConvertTo((OrdStatus)field.Value);
                        bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    }
                    break;

                case Tag.OrdType:

                    // OrdType Body Field
                    fieldValue  = OrdTypeConverter.ConvertTo((OrderTypeCode)field.Value);
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    break;

                case Tag.OrigClOrdID:

                    // the OrigClOrdID Body Field is not valid in cancel-reject or execution report messages before FIX 4.1
                    if ((!this.MsgType.Equals(MsgType.OrderCancelReject) && !this.MsgType.Equals(MsgType.ExecutionReport)) ||
                        (this.MsgType.Equals(MsgType.OrderCancelReject) && !this.BeginString.Equals("FIX.4.0")) ||
                        (this.MsgType.Equals(MsgType.ExecutionReport) && !this.BeginString.Equals("FIX.4.0")))
                    {
                        if (field.Value != null)
                        {
                            bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + field.Value.ToString() + FixSeparator.ToString();
                        }
                    }
                    break;

                case Tag.PutOrCall:

                    // PutOrCall Body Field
                    fieldValue  = OptionTypeConverter.ConvertTo((OptionType)field.Value);
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    break;

                case Tag.RefMsgType:

                    // RefMsgType Body Field
                    fieldValue  = MsgTypeConverter.ConvertTo((MsgType)field.Value);
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    break;

                case Tag.ResetSeqNumFlag:

                    // ResetSeqNumFlag Body Field
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + ((bool)field.Value ? "Y" : "N") + FixSeparator.ToString();
                    break;

                case Tag.RoutingGroup:

                    // Expand the Routing repeating group fields.
                    RoutingGroup routingGroup = (RoutingGroup)field.Value;
                    if ((routingGroup != null) && (routingGroup.Count > 0))
                    {
                        // the number of repeating instances goes in the 'NoRoutingIDs' field.
                        bodyFields += TagConverter.ConvertTo(Tag.NoRoutingIDs) + "=" + routingGroup.Count.ToString() + FixSeparator.ToString();
                        foreach (RoutingGroup.Entry entry in routingGroup)
                        {
                            // Add the routing type.
                            fieldValue  = RoutingTypeConverter.ConvertTo(entry.RoutingType);
                            bodyFields += TagConverter.ConvertTo(Tag.RoutingType) + "=" + fieldValue + FixSeparator.ToString();

                            // Add the routing ID.
                            bodyFields += TagConverter.ConvertTo(Tag.RoutingID) + "=" + entry.RoutingId + FixSeparator.ToString();
                        }
                    }
                    break;

                // These fields should be part of the repeating group "RoutingGroup",
                // and should NOT be used individually.
                case Tag.NoRoutingIDs:
                case Tag.RoutingID:
                case Tag.RoutingType:
                    break;

                case Tag.SecurityType:

                    // SecurityType Body Field
                    fieldValue  = SecurityTypeConverter.ConvertTo((SecurityType)field.Value);
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    break;

                case Tag.SessionRejectReason:

                    // SessionRejectReason Body Field
                    fieldValue  = SessionRejectReasonConverter.ConvertTo((SessionRejectReason)field.Value);
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    break;

                case Tag.Side:

                    // Side Body Field
                    fieldValue  = SideConverter.ConvertTo((SideCode)field.Value);
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    break;

                case Tag.TimeInForce:

                    // TimeInForce Body Field
                    fieldValue  = TimeInForceConverter.ConvertTo((TimeInForceCode)field.Value);
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + fieldValue + FixSeparator.ToString();
                    break;

                case Tag.TransactTime:

                    // the TransactTime Body Field is not valid before FIX 4.2
                    if (!this.BeginString.Equals("FIX.4.0") && !this.BeginString.Equals("FIX.4.1"))
                    {
                        bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + ((DateTime)field.Value).ToString("yyyyMMdd-HH:mm:ss") + FixSeparator.ToString();
                    }
                    break;


                case Tag.ValidUntilTime:

                    // ValidUntilTime Body Field
                    bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + ((DateTime)field.Value).ToString("yyyyMMdd-HH:mm:ss") + FixSeparator.ToString();
                    break;


                default:
                    // Default processing of these types for Tags not in the above list.
                    // Int32 Body Fields
                    // Decimal Body Fields
                    // String Body Fields
                    if (field.Value != null)
                    {
                        bodyFields += TagConverter.ConvertTo(field.Tag) + "=" + field.Value.ToString() + FixSeparator.ToString();
                    }
                    break;
                }
            }

            if (headerFields.Equals(string.Empty))
            {
                throw new MissingFieldException("FIX Header fields are missing");
            }

            // The 'BodyLength' fields must be calculated after the body and part of the header is assembled.
            int    bodyPacketLength = msgTypeField.Length + headerFields.Length + bodyFields.Length;
            string bodyLengthField  = TagConverter.ConvertTo(Tag.BodyLength) + "=" + bodyPacketLength.ToString() + FixSeparator.ToString();

            // Assemble the packet from the component fields.
            string packet = beginStringField + bodyLengthField + msgTypeField + headerFields + bodyFields;

            // The final step in assembling a packet is the calculation of the checksum.  This is the least significant byte of
            // the sum of all the byte values in the packet.
            int checksum = 0;

            foreach (byte messageByte in packet)
            {
                checksum += messageByte;
            }
            string checksumField = TagConverter.ConvertTo(Tag.CheckSum) + "=" + (checksum & 0xFF).ToString("000") + FixSeparator.ToString();

            return(packet + checksumField);
        }