0

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"));
        }
    }
}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
unsafePtr
  • 1,591
  • 2
  • 17
  • 27
  • 1
    You may want to reach out to your counterparty about how they recommend you can match rejects to orders. – Grant Birchmeier May 26 '22 at 15:51
  • When you are using the normal NewOrder/ExecutionReport workflow the unique ID should be `ClOrdID`. But of course there can be multiple matches for the same `ClOrdID`. Probably your counterparty has something like an execution ID (`ExecID`)? – Christoph John May 30 '22 at 09:29
  • It seems that handling with Task would be error-prone. FIX protocol is by itself an asynchronous protocol. We don't know when precisely the server will respond. You can't restart your application at any given point, as Disctionary with tasks stored in memory will lose its state. In the end, we decided to send the request from the server and return Ok(). Then when the response message arrives we do server push using SignalR. – unsafePtr Jun 30 '22 at 07:29

0 Answers0