Can the order filling be executed synchronously with fix protocol? Since protocol by it's nature is async I am thinking to use TaskCompletionSource. However I experience problem in picking up unique identifier. OrderId won't work in case when required field is missing server will respond with BusinessMessageReject
and I won't know how to set task to cancelled or failed. I thought to use msgSeq as unique identifier. However, at the time of sending and I don't know it, because it's handled by QuickFixN internally. Plus in case of connection reset seqNum will be reset too. There are possibly edge cases like to deal somehow with long running messages.
Please see below code attached. I am omitting other methods, so you can get the idea of what I am trying to achieve. Let me know if it's waste of time.
class FixClient : IApplication
{
private ConcurrentDictionary<string, TaskCompletionSource<ExecutionReport>> _currentOrdersUnderProcessing = new ConcurrentDictionary<string, TaskCompletionSource<ExecutionReport>>();
// In case when some required field is missing
public void OnMessage(BusinessMessageReject message, SessionID sessionID)
{
// how can I can extract needed key, if there is no OrderId in the response
var orderId = ""; // how?
if (_currentOrdersUnderProcessing.TryRemove(orderId, out var taskCompletionSource))
{
taskCompletionSource.SetException(new Exception("Couldn't execute order"));
}
}
public void OnMessage(ExecutionReport message, SessionID sessionID)
{
var orderId = message.GetField(11); // ClOrdID field
if (_currentOrdersUnderProcessing.TryRemove(orderId, out var taskCompletionSource))
{
taskCompletionSource.SetResult(message);
}
}
public Task SendNewBuyMarketOrderAsync(string symbol)
{
var orderId = Guid.NewGuid().ToString();
var message = new NewOrderSingle(uniqueOrderId, instructionsForOrderHandling, symbol, side, transactionTime, orderType);
if (QuickFix.Session.SendToTarget(message, sessionId)) // if send successfully
{
var tsc = new TaskCompletionSource<ExecutionReport>();
_currentOrdersUnderProcessing.TryAdd(orderId, tsc)
return tsc.Task;
}
else
{
return Task.FromException(new Exception("Couldn't place order"));
}
}
}