Custom Field Generator Sample
Source code
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using NLog.Extensions.Logging;
using OnixS.Fix;
using OnixS.Fix.Dictionaries;
namespace CustomFieldGeneratorSample
{
static class CustomFieldGeneratorSample
{
static void Log(string msg)
{
Console.Out.WriteLine(msg);
}
private static string GetLicenseStoreFolder()
{
string path = Path.Join(AppContext.BaseDirectory, "../../../../../license");
if (Directory.Exists(path))
return path;
// expecting it run after dotnet publish using default paths
return Path.Join(AppContext.BaseDirectory, "../../../../../../license");
}
/// <summary>
/// The main entry point for the application.
/// </summary>
static int Main()
{
try
{
var settings = new EngineSettings()
{
Dictionary = "SampleFixDialectDescription.xml",
DisableNetworkLevel = true,
LicenseStore = GetLicenseStoreFolder(),
LoggerProvider = new NLogLoggerProvider()
};
Engine.Init(settings);
var dictionary = ProtocolVersion.Fix44.ToDictionary();
string filename = "Tags.cs";
using (StreamWriter writer = new StreamWriter(filename, false))
{
var tags = GenerateTags(dictionary);
writer.WriteLine(tags);
writer.WriteLine();
}
Log($"{filename} is generated successfully.");
Engine.Shutdown();
}
catch (Exception ex)
{
Log("Exception: " + ex);
return 1;
}
finally
{
// From https://github.com/NLog/NLog/wiki/Tutorial:
// NET Application running on Mono / Linux are required to stop threads / timers before entering application shutdown phase.
// Failing to do this will cause unhandled exceptions and segmentation faults, and other unpredictable behavior.
NLog.LogManager.Shutdown(); // Flush and close down internal threads and timers
}
return 0;
}
/// <summary>
/// Generate tags and values for custom fields.
/// </summary>
/// <returns> Generated C# code </returns>
private static string GenerateTags(IMessageInfoDictionary dictionary)
{
var tags = GetTags(dictionary);
var result = new StringBuilder();
result.AppendLine($"public static class {dictionary.Name}Tag").AppendLine("{");
foreach (var tag in tags.Values.OrderBy(t => t.Tag))
{
string name = IsToken(tag.Name) ? tag.Name : ("Tag" + tag.Tag);
result.AppendLine($" public const int {name} = {tag.Tag};");
}
result.AppendLine("}");
return result.ToString();
}
private static bool IsToken(string name)
{
if (string.IsNullOrEmpty(name))
return false;
if (!char.IsLetter(name[0]) && name[0] != '_')
return false;
for (int i = 1; i < name.Length; i++)
{
if (!char.IsLetterOrDigit(name[i]))
return false;
}
return true;
}
private static Dictionary<int, FieldInfo> GetTags(IMessageInfoDictionary dictionary)
{
var tags = new Dictionary<int, FieldInfo>();
foreach (var messageType in dictionary.MessageTypes)
{
var messageInfo = dictionary.GetMessageInfo(messageType);
GetTags(messageInfo, tags);
}
return tags;
}
private static void GetTags(FieldContainerInfo fieldContainer, Dictionary<int, FieldInfo> tags)
{
foreach (var field in fieldContainer)
{
tags[field.Tag] = field;
if (field.Group != null)
{
GetTags(field.Group, tags);
}
}
}
}
}
Dialect
<?xml version="1.0" encoding="utf-8" ?>
<Dialect xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://ref.onixs.biz/fix/dialects https://ref.onixs.biz/fix/dialects/dialects-2.19.xsd" xmlns="https://onixs.biz/fix/dialects">
<FIX version="4.4" mode="override">
<Message type="SampleCustomFixMessage">
<Field tag="847" name="TargetStrategy"/>
<Field tag="168" name="EffectiveTime"/>
<Group numberOfInstancesTag="957" name="NoStrategyParameters">
<Field tag="958" name="StrategyParameterName"/>
<Field tag="959" name="StrategyParameterType"/>
<Field tag="960" name="StrategyParameterValue"/>
</Group>
</Message>
</FIX>
</Dialect>