Throttling Buy Side Sample
Source code
using System;
using OnixS.Fix;
using System.Globalization;
using System.IO;
using OnixS.Fix.Fix44;
using System.Net;
using NLog.Extensions.Logging;
using System.Threading;
namespace ThrottlingBuySide
{
/// <summary>
/// Establishes the FIX session as Initiator.
/// </summary>
internal static class Initiator
{
private const ProtocolVersion fixVersion = ProtocolVersion.Fix44;
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");
}
private static Message CreateOrderMessage(IMessageInfoDictionary dictionary)
{
var order = new Message(MsgType.NewOrderSingle, dictionary);
order.Set(Tag.HandlInst, HandlInst.AutoExecPub)
.Set(Tag.ClOrdID, "Unique identifier for Order")
.Set(Tag.Symbol, "TSLA")
.Set(Tag.Side, Side.Buy)
.Set(Tag.OrderQty, 1000)
.Set(Tag.OrdType, OrdType.Market)
.Set(Tag.TransactTime, DateTime.UtcNow.ToString("yyyyMMdd-HH:mm:ss", CultureInfo.InvariantCulture));
#if DEBUG
try
{
order.Validate();
}
catch (Exception ex)
{
Console.WriteLine("Exception on order validation: " + ex);
}
#endif
return order;
}
/// <summary>
/// The main entry point for the application.
/// </summary>
private static int Main()
{
Console.WriteLine("Throttling Buy Side Sample");
try
{
var settings = new EngineSettings()
{
LicenseStore = GetLicenseStoreFolder(),
LoggerProvider = new NLogLoggerProvider()
};
Engine.Init(settings);
var dictionary = fixVersion.ToDictionary();
using (Session session = new("ThrottlingBuySide", "ThrottlingSellSide", dictionary))
{
const int MessagesPerSecondLimitDelta = 3;
const int MessagesPerSecondLimit = 10 - MessagesPerSecondLimitDelta;
TimeSpan ThrottlingInterval = TimeSpan.FromSeconds(1);
AutoResetEvent orderHandlingComplete = new AutoResetEvent(false);
int totalOrdersHandled = 0;
int totalMessagesRejected = 0;
session.ThrottlingLimit(MessagesPerSecondLimit, ThrottlingInterval);
session.InboundApplicationMessage += (object sender, InboundMessageEventArgs e) =>
{
Console.WriteLine("Inbound application-level message:\n" + e.Message);
if (e.Message.Type == MsgType.ExecutionReport)
{
++totalOrdersHandled;
orderHandlingComplete.Set();
}
};
session.InboundSessionMessage += (object sender, InboundMessageEventArgs e) =>
{
Console.WriteLine("Inbound session-level message:\n" + e.Message);
if (e.Message.Type == MsgType.Reject)
{
++totalMessagesRejected;
Console.WriteLine("Rejection " + totalMessagesRejected + ": message " + e.Message.Get(Tag.RefSeqNum) + " rejected.");
orderHandlingComplete.Set();
}
};
session.StateChanged += (object sender, SessionStateChangeEventArgs e) =>
{
Console.WriteLine("Session state: " + e.NewState);
};
session.Error += (object sender, SessionErrorEventArgs e) =>
{
Console.WriteLine("Error: " + e.ToString());
};
session.Warning += (object sender, SessionWarningEventArgs e) =>
{
Console.WriteLine("Warning: " + e.ToString());
};
session.LogonAsInitiator(IPAddress.Loopback, 10450);
Console.WriteLine("Press any key to send throttled orders...");
Console.ReadKey(true);
Message order = CreateOrderMessage(dictionary);
const int NumOfMessages = 100;
for (int msgCounter = 0; msgCounter < NumOfMessages; ++msgCounter)
{
session.Throttle();
session.Send(order);
orderHandlingComplete.WaitOne();
}
Console.WriteLine("Orders handled: " + totalOrdersHandled + ", messages rejected: " + totalMessagesRejected);
Console.WriteLine("Press any key to disconnect the session and terminate the application.");
Console.ReadKey(true);
session.Logout("The session is disconnected by BuySide");
}
Engine.Instance.Shutdown();
}
catch (Exception ex)
{
Console.WriteLine("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;
}
}
}