private void AddToTradeResult(BuySellOperation buyOperation, BuySellOperation sellOperation,
                               ICollection <BuySellOperation> buysToBeRemoved, ICollection <BuySellOperation> sellsToBeRemoved)
 {
     if (sellOperation.Quantity == buyOperation.Quantity)
     {
         PrintTrade(buyOperation, sellOperation, sellOperation.Quantity);
         sellsToBeRemoved.Add(sellOperation);
         buysToBeRemoved.Add(buyOperation);
     }
     else if (sellOperation.Quantity < buyOperation.Quantity)
     {
         PrintTrade(buyOperation, sellOperation, sellOperation.Quantity);
         if (BuyPriceToQuantityMap.TryGetValue(buyOperation.Price, out _))
         {
             BuyPriceToQuantityMap[buyOperation.Price] -= sellOperation.Quantity;
         }
         buyOperation.Quantity -= sellOperation.Quantity;
         sellsToBeRemoved.Add(sellOperation);
     }
     else if (sellOperation.Quantity > buyOperation.Quantity)
     {
         PrintTrade(buyOperation, sellOperation, buyOperation.Quantity);
         if (SellPriceToQuantityMap.TryGetValue(sellOperation.Price, out _))
         {
             SellPriceToQuantityMap[sellOperation.Price] -= buyOperation.Quantity;
         }
         sellOperation.Quantity -= buyOperation.Quantity;
         buysToBeRemoved.Add(buyOperation);
     }
 }
 private void BalancePriceToQuantityMap(BuySellOperation operation)
 {
     if (operation.OperationType == OperationType.Buy && BuyPriceToQuantityMap.TryGetValue(operation.Price, out _))
     {
         BuyPriceToQuantityMap[operation.Price] -= operation.Quantity;
     }
     else if (operation.OperationType == OperationType.Sell &&
              SellPriceToQuantityMap.TryGetValue(operation.Price, out _))
     {
         SellPriceToQuantityMap[operation.Price] -= operation.Quantity;
     }
 }
    private static void PrintTrade(BuySellOperation input, BuySellOperation tradeResult, long quantity)
    {
        var outPut = new StringBuilder();

        outPut.Append("TRADE ");
        if (tradeResult.TimeStamp > input.TimeStamp)
        {
            outPut.Append($"{input} {quantity} {tradeResult} {quantity}").Append(Environment.NewLine);
        }
        else
        {
            outPut.Append($"{tradeResult} {quantity} {input} {quantity}").Append(Environment.NewLine);
        }
        Console.Write(outPut.ToString());
    }
    private void ReInsertModifiedBuySellOperation(BuySellOperation previousBuySellOperation, ModifyOperation modifyOperation)
    {
        if (previousBuySellOperation.OrderType == OrderType.Ioc)
        {
            return;
        }

        var newOperation = new BuySellOperation(modifyOperation.BuyOrSell, previousBuySellOperation.OrderType,
                                                modifyOperation.NewPrice, modifyOperation.NewQuantity, modifyOperation.OrderId);

        if (modifyOperation.BuyOrSell == OperationType.Sell)
        {
            Process(newOperation);
        }
        else
        {
            Process(newOperation);
        }
    }
    public void Trade(BuySellOperation operation)
    {
        var buysToBeRemoved  = new List <BuySellOperation>();
        var sellsToBeRemoved = new List <BuySellOperation>();

        if (operation.OperationType == OperationType.Buy)
        {
            for (var i = 0; i < SellOperations.Count; i++)
            {
                if (operation.Quantity <= 0)
                {
                    break;
                }
                if (operation.Price >= SellOperations.ElementAt(i).Price)
                {
                    AddToTradeResult(operation, SellOperations.ElementAt(i), buysToBeRemoved, sellsToBeRemoved);
                }
            }
        }
        else
        {
            for (var i = 0; i < BuyOperations.Count; i++)
            {
                if (operation.Quantity <= 0)
                {
                    break;
                }
                if (operation.Price <= BuyOperations.ElementAt(i).Price)
                {
                    AddToTradeResult(BuyOperations.ElementAt(i), operation, buysToBeRemoved, sellsToBeRemoved);
                }
            }
        }
        foreach (var sellToBeRemoved in sellsToBeRemoved)
        {
            CancelSellOperation(sellToBeRemoved);
        }
        foreach (var buyToBeRemoved in buysToBeRemoved)
        {
            CancelBuyOperation(buyToBeRemoved);
        }
    }
    public void Process(BuySellOperation buySellOperation)
    {
        if (buySellOperation.Price <= 0 || buySellOperation.Quantity < 0)
        {
            return;
        }

        if (buySellOperation.OperationType == OperationType.Buy)
        {
            // Put the current buy / sell operation on the queue.
            BuyOperations.Add(buySellOperation);

            // Add buyOperation to historical price to quantity map.
            if (buySellOperation.OrderType != OrderType.Ioc && BuyPriceToQuantityMap.TryGetValue(buySellOperation.Price, out var quantity))
            {
                BuyPriceToQuantityMap[buySellOperation.Price] = quantity + buySellOperation.Quantity;
            }
            else if (buySellOperation.OrderType != OrderType.Ioc)
            {
                BuyPriceToQuantityMap.Add(buySellOperation.Price, buySellOperation.Quantity);
            }
        }
        else
        {
            // Put the current buy / sell operation on the queue.
            SellOperations.Add(buySellOperation);

            // Add buyOperation to historical price to quantity map.
            if (buySellOperation.OrderType != OrderType.Ioc && SellPriceToQuantityMap.TryGetValue(buySellOperation.Price, out var quantity))
            {
                SellPriceToQuantityMap[buySellOperation.Price] = quantity + buySellOperation.Quantity;
            }
            else if (buySellOperation.OrderType != OrderType.Ioc)
            {
                SellPriceToQuantityMap.Add(buySellOperation.Price, buySellOperation.Quantity);
            }
        }
    }
 public void CancelSellOperation(BuySellOperation operation)
 {
     BalancePriceToQuantityMap(operation);
     SellOperations.Remove(operation);
 }