// REC: The PopulateQueue method is a recursive function // that loads all of the elements in a FixCollection into // an instance of a SrcField queue so that the validator // can then process all the elements sequentially: private void PopulateQueue(Queue <SrcField> queue, FixCollection elements) { foreach (IFixElement element in elements) { if (element is FixField) { FixField msgField = element as FixField; if (msgField != null) { // REC: Attempt to resolve the field's name // by retrieving it using it's tag: string fieldName = ResolveFieldName(msgField.Tag.ToString()); if (fieldName == null) { fieldName = "Unresolved"; } // REC: Create a new instance of SrcField that // represents the contents of this field: SrcField srcField = new SrcField(); srcField.Tag = msgField.Tag.ToString(); srcField.Name = fieldName; srcField.Value = msgField.Content; queue.Enqueue(srcField); } } else if (element is FixGroup) { FixGroup msgGroup = element as FixGroup; if (msgGroup != null) { string groupName = ResolveFieldName(msgGroup.Tag.ToString()); if (groupName == null) { groupName = "Unresolved"; } // REC: Create a new instance of SrcField that // represents the contents of the group: SrcField srcField = new SrcField(); srcField.Tag = msgGroup.Tag.ToString(); srcField.Name = groupName; srcField.Value = msgGroup.Content; queue.Enqueue(srcField); foreach (FixCollection instance in msgGroup.Instances) { PopulateQueue(queue, instance); } } } } }
/// <summary> /// The GetVersion method attempts to determine the version /// of a specific layer of the FIX protocol, based on a set /// of FIX message elements. /// </summary> /// <param name="elements"> /// The collection of FIX elements to analyze. /// </param> /// <param name="layer"> /// The layer of the protocol version to retrieve. /// </param> /// <returns> /// The name of the protocol, at the specified layer, that /// matches the specified FIX message elements. /// </returns> public string GetVersion(FixCollection elements, string layer) { string result = null; if (_mapLayers.ContainsKey(layer)) { foreach (MatchEntry matchEntry in _mapLayers[layer]) { bool matched = true; foreach (VfxFixVersion_Rule rule in matchEntry.Rules) { foreach (VfxFixVersion_Field field in rule.Fields) { int nTag = int.Parse(field.Tag); IFixElement element = elements.GetField(nTag); if (element == null) { element = elements.GetGroup(nTag); } if (element != null) { string fieldContent = element.Content.ToString(); if (fieldContent.CompareTo(field.Value) != 0) { matched = false; } } else { matched = false; break; } } if (matched == true) { break; } } if (matched == true) { result = matchEntry.Name; } } } return(result); }
/// <summary> /// The GetAxVersion method attempts to retrieve the /// name of the app layer protocol version which best /// applies to a collection of FIX elements. /// </summary> /// <param name="elements"> /// The collection of FIX elements to analyze. /// </param> /// <returns> /// The name of the FIX protocol version that is the /// best match for the supplied elements. /// </returns> public string GetAxVersion(FixCollection elements) { string result = GetVersion(elements, "application"); if (result == null) { result = GetVersion(elements, "combined"); if (result == null) { result = GetVersion(elements, "session"); } } return(result); }
private void HandleWork_SendMessages(object state) { int orderId = 1; IVfxFixAppSession session = state as IVfxFixAppSession; for (int i = 0; i != 5; i++) { FixMessage msg = new FixMessage(); msg.Header.SetField(new FixField(35, "8")); msg.Content.SetField(new FixField(37, orderId++.ToString())); msg.Content.SetField(new FixField(17, "5000")); msg.Content.SetField(new FixField(20, "0")); msg.Content.SetField(new FixField(150, "0")); msg.Content.SetField(new FixField(39, "0")); msg.Content.SetField(new FixField(55, "AAPL")); msg.Content.SetField(new FixField(54, "1")); msg.Content.SetField(new FixField(151, "3000")); msg.Content.SetField(new FixField(14, "0")); msg.Content.SetField(new FixField(6, "0")); FixGroup grpTest = new FixGroup(382, "2"); FixCollection grpInstance = new FixCollection(); grpInstance.AddField(new FixField(375, "foo")); grpInstance.AddField(new FixField(337, "bar")); grpTest.Instances.Add(grpInstance); grpTest.Instances.Add(grpInstance); msg.Content.AddGroup(grpTest); session.Send(msg); } if (session != null) { for (int i = 0; i != 10000; i++) { FixMessage message = new FixMessage(); message.Header.AddField(new FixField(35, "D")); session.Send(message); } } }
/// <summary> /// The GetDictionaries method analyzes a collection of elements /// and determines which FIX data dictionaries are relevant to the /// collection of elements. The method uses VfxFixVxMatcher to find /// the version definitions that match the elements, and then it goes /// to the version registry to retrieve the relevant dictionaries. /// </summary> /// <param name="elements"> /// The collection of FIX elements to analyze. /// </param> /// <returns> /// The collection of all FIX dictionaries that are relevant to the /// elements, according to the corresponding version definitions. /// </returns> public Collection <string> GetDictionaries(FixCollection elements) { Collection <string> result = new Collection <string>(); if ((_vxRegistry != null) && (_dxRegistry != null)) { VfxFixVxMatcher matcher = new VfxFixVxMatcher(); matcher.Init(_vxRegistry); string sxVersion = matcher.GetVersion(elements, "session"); if (sxVersion == null) { sxVersion = matcher.GetVersion(elements, "combined"); } string axVersion = matcher.GetVersion(elements, "app"); if (axVersion == null) { axVersion = matcher.GetVersion(elements, "combined"); } VfxFixVxRecord sxDetails = _vxRegistry.Get(sxVersion); if (sxDetails != null) { foreach (VfxFixVersion_Dictionary_Reference dxEntry in sxDetails.Dictionaries) { result.Add(dxEntry.Name); } } if ((sxVersion == null) || (sxVersion.CompareTo(axVersion) != 0)) { VfxFixVxRecord axDetails = _vxRegistry.Get(axVersion); if (axDetails != null) { foreach (VfxFixVersion_Dictionary_Reference dxEntry in axDetails.Dictionaries) { result.Add(dxEntry.Name); } } } } return(result); }
/// <summary> /// The GetDictionaries method analyzes a collection of elements /// and determines which FIX data dictionaries are relevant to the /// collection of elements. The method uses VfxFixVxMatcher to find /// the version definitions that match the elements, and then it goes /// to the version registry to retrieve the relevant dictionaries. /// </summary> /// <param name="elements"> /// The collection of FIX elements to analyze. /// </param> /// <returns> /// The collection of all FIX dictionaries that are relevant to the /// elements, according to the corresponding version definitions. /// </returns> public Collection<string> GetDictionaries(FixCollection elements) { Collection<string> result = new Collection<string>(); if ((_vxRegistry != null) && (_dxRegistry != null)) { VfxFixVxMatcher matcher = new VfxFixVxMatcher(); matcher.Init(_vxRegistry); string sxVersion = matcher.GetVersion(elements, "session"); if (sxVersion == null) { sxVersion = matcher.GetVersion(elements, "combined"); } string axVersion = matcher.GetVersion(elements, "app"); if (axVersion == null) { axVersion = matcher.GetVersion(elements, "combined"); } VfxFixVxRecord sxDetails = _vxRegistry.Get(sxVersion); if (sxDetails != null) { foreach (VfxFixVersion_Dictionary_Reference dxEntry in sxDetails.Dictionaries) { result.Add(dxEntry.Name); } } if ((sxVersion == null) || (sxVersion.CompareTo(axVersion) != 0)) { VfxFixVxRecord axDetails = _vxRegistry.Get(axVersion); if (axDetails != null) { foreach (VfxFixVersion_Dictionary_Reference dxEntry in axDetails.Dictionaries) { result.Add(dxEntry.Name); } } } } return result; }
/// <summary> /// The ParseGroup method attempts to parse all of the group /// instances from a repeating group. /// </summary> /// <param name="ctx"> /// The parser's current parsing context. /// </param> /// <param name="group"> /// The resolved group information for the repeating group /// that is being extracted from the message. /// </param> /// <param name="count"> /// The number of instances of the repeating group that the /// parser should expect to encounter. /// </param> /// <returns></returns> private ParseGroupResult ParseGroup(ParseContext ctx, FixDxResolvedGroup group, int count) { ParseGroupResult result = new ParseGroupResult(); // Build a temporary map of flags that indicate whether // or not a specific element of the repeating group has // been encountered during the parsing of an instance: Dictionary<int, bool> mapEncountered = new Dictionary<int, bool>(); foreach (IFixDxElement element in group.Elements) { if (!mapEncountered.ContainsKey(element.Tag)) { mapEncountered.Add(element.Tag, false); } else { mapEncountered[element.Tag] = false; } } // REC: Extract the FIX tag of the first field in // the repeating group; this is needed to determine // when one instance stops and another starts: IFixDxElement startField = group.Elements.First(); int nStartField = startField.Tag; // REC: Default to the complete status when parsing // a group, so that zero-instance groups don't cause // a problem; a zero-instance group is okay in terms // of parsing, and should only be flagged as a fault // when validation is run... result.Status = VfxFixParserStatus.MsgComplete; for (int i = 0; i != count; i++) { FixCollection collection = new FixCollection(); List<int> listEncounterMapKeys = new List<int>(); foreach (int key in mapEncountered.Keys) { listEncounterMapKeys.Add(key); } // REC: Reset the encounter map for all of the // tags that can be encountered in an instance // of the repeating group: foreach (int key in listEncounterMapKeys) { mapEncountered[key] = false; } while (ctx.Index < ctx.Buffer.Length) { // REC: Ignore leading SOH characters: while (ctx.Buffer[ctx.Index] == '\x01') { ctx.Index++; if (ctx.Index >= ctx.Buffer.Length) { return result; } } // REC: Locate the next tag/value separator: int idxSep = ctx.Buffer.IndexOf('=', ctx.Index); if (idxSep == -1) { // REC: If the next separator couldn't // be found, the message is incomplete: result.Status = VfxFixParserStatus.MsgIncomplete; return result; } // REC: If the field doesn't have a tag then // the parsing of the groups can't continue: if (idxSep == ctx.Index) { result.Status = VfxFixParserStatus.MsgMalformed; return result; } // REC: Attempt to locate the end of the field: int idxSoh = ctx.Buffer.IndexOf('\x01', idxSep + 1); if (idxSoh == -1) { result.Status = VfxFixParserStatus.MsgIncomplete; return result; } string strTag = ctx.Buffer.Substring(ctx.Index, idxSep - ctx.Index); if (strTag != null) { int nTag; if (int.TryParse(strTag, out nTag) == false) { result.Status = VfxFixParserStatus.MsgMalformed; return result; } string strVal = null; // REC: Determine whether or not the tag // is a valid member of the current group: IFixDxElement element = group.Elements.GetElement(nTag); if (element == null) { // REC: The parsing of a repeating group // should cease if a tag that is not a // member of the group is encountered: result.Instances.Add(collection); // REC: Set the status so that the caller knows // the group was successfully parsed: result.Status = VfxFixParserStatus.MsgComplete; return result; } // REC: Determine whether or not the tag // has already been encountered during // the parsing of the current instance: if (mapEncountered[nTag] == true) { // REC: Determine whether or not the // redundant tag is the first tag in // the repeating group's layout: if (nTag == nStartField) { // REC: This field is the start tag // for another instance of the group: result.Instances.Add(collection); break; } return result; } mapEncountered[nTag] = true; // REC: Determine whether or not the element // represents a length encoded field: if (element is FixDxResolvedField) { FixDxResolvedField fieldEntry = element as FixDxResolvedField; if (fieldEntry.LengthCoded == true) { // REC: Determine whether or not the // corresponding length field exists: string strLen = collection.GetField(fieldEntry.LengthField).Content; if (strLen != null) { int nLen = -1; if (int.TryParse(strLen, out nLen) == true) { // REC: Determine whether or not there // are enough characters remaining in // the buffer to parse the contents: if ((idxSep + nLen) >= ctx.Buffer.Length) { result.Status = VfxFixParserStatus.MsgIncomplete; return result; } strVal = ctx.Buffer.Substring(idxSep + 1, nLen); // REC: Adjust the context's read index: ctx.Index = (idxSep + 1) + nLen; } } else { // REC: The encoded length field couldn't // be located, so the contents will be // parsed as though they were any other // normal field's contents: strVal = ctx.Buffer.Substring(idxSep + 1, idxSoh - (idxSep + 1)); // REC: Adjust the context's read index: ctx.Index = idxSoh + 1; } } else { strVal = ctx.Buffer.Substring(idxSep + 1, idxSoh - (idxSep + 1)); // REC: Adjust the context's read index: ctx.Index = idxSoh + 1; } collection.AddField(new FixField(nTag, strVal)); } else if (element is FixDxResolvedGroup) { // REC: If the group field's value isn't set // to a specific value, then add a null group // entry to the collection and continue: if (idxSoh == idxSep + 1) { FixGroup parsedGroup = new FixGroup(nTag, null); collection.AddGroup(parsedGroup); result.Instances.Add(collection); ctx.Index = idxSoh + 1; } else { // REC: Attempt to convert the field's value // into an integer that represents the number // of repeating groups that should follow: strVal = ctx.Buffer.Substring(idxSep + 1, idxSoh - (idxSep + 1)); // REC: This might have been the issue with nested repeating // groups becoming a problem: ctx.Index = idxSoh + 1; int nInstances = -1; if (int.TryParse(strVal, out nInstances) == true) { FixDxResolvedGroup subGroup = element as FixDxResolvedGroup; ParseGroupResult subResult = ParseGroup(ctx, subGroup, nInstances); if (subResult.Status != VfxFixParserStatus.MsgComplete) { break; } else { FixGroup parsedGroup = new FixGroup(nTag, strVal); foreach (FixCollection instance in subResult.Instances) { parsedGroup.Instances.Add(instance); } collection.AddGroup(parsedGroup); // REC: Adjust the context's read index: //ctx.Index = idxSoh + 1; } } else { // REC: The instance count couldn't be converted // to an integer, so the message is malformed: result.Status = VfxFixParserStatus.MsgMalformed; break; } } } } } } return result; }
private static int CalculateSum(FixCollection elements) { int result = 0; foreach (IFixElement element in elements) { result += CalculateSum(element.Tag.ToString()); result += 0x3D; result += CalculateSum(element.Content); result += 0x01; FixGroup group = element as FixGroup; if (group != null) { foreach (FixCollection instance in group.Instances) { result += CalculateSum(instance); } } } return result; }
// REC: The CalculateLength method calculates the combined // length of all of the elements in a collection. This is // a support method for the CalculateBodyLength method. private static int CalculateLength(FixCollection collection) { int result = 0; foreach (IFixElement element in collection) { result += element.Tag.ToString().Length; result += 1; result += element.Content.Length; result += 1; FixGroup group = element as FixGroup; if (group != null) { foreach (FixCollection instance in group.Instances) { result += CalculateLength(instance); } } } return result; }
// REC: The PopulateQueue method is a recursive function // that loads all of the elements in a FixCollection into // an instance of a SrcField queue so that the validator // can then process all the elements sequentially: private void PopulateQueue(Queue<SrcField> queue, FixCollection elements) { foreach (IFixElement element in elements) { if (element is FixField) { FixField msgField = element as FixField; if (msgField != null) { // REC: Attempt to resolve the field's name // by retrieving it using it's tag: string fieldName = ResolveFieldName(msgField.Tag.ToString()); if (fieldName == null) { fieldName = "Unresolved"; } // REC: Create a new instance of SrcField that // represents the contents of this field: SrcField srcField = new SrcField(); srcField.Tag = msgField.Tag.ToString(); srcField.Name = fieldName; srcField.Value = msgField.Content; queue.Enqueue(srcField); } } else if (element is FixGroup) { FixGroup msgGroup = element as FixGroup; if (msgGroup != null) { string groupName = ResolveFieldName(msgGroup.Tag.ToString()); if (groupName == null) { groupName = "Unresolved"; } // REC: Create a new instance of SrcField that // represents the contents of the group: SrcField srcField = new SrcField(); srcField.Tag = msgGroup.Tag.ToString(); srcField.Name = groupName; srcField.Value = msgGroup.Content; queue.Enqueue(srcField); foreach (FixCollection instance in msgGroup.Instances) { PopulateQueue(queue, instance); } } } } }
/// <summary> /// The GetSxVersion method attempts to retrieve the /// name of the session layer protocol version which /// applies to a collection of FIX elements. /// </summary> /// <param name="elements"> /// The collection of FIX elements to analyze. /// </param> /// <returns> /// The name of the FIX protocol version that is the /// best match for the supplied elements. /// </returns> public string GetSxVersion(FixCollection elements) { return(GetVersion(elements, "session")); }