private bool MatchWithOpenOrders(Order incomingOrder)
        {
            bool anyMatchHappend = false;

            while (true)
            {
                Order restingOrder = _book.GetBestBuyOrderToMatch(!incomingOrder.IsBuy);
                if (restingOrder == null)
                {
                    break;
                }

                if ((incomingOrder.IsBuy && (restingOrder.Price <= incomingOrder.Price || incomingOrder.Price == 0)) || (!incomingOrder.IsBuy && (restingOrder.Price >= incomingOrder.Price)))
                {
                    Price    matchPrice  = restingOrder.Price;
                    Quantity maxQuantity = 0;
                    if (incomingOrder.OpenQuantity > 0)
                    {
                        maxQuantity = incomingOrder.OpenQuantity >= restingOrder.OpenQuantity ? restingOrder.OpenQuantity : incomingOrder.OpenQuantity;
                        incomingOrder.OpenQuantity -= maxQuantity;
                    }
                    else
                    {
                        throw new Exception("not expected");
                    }

                    var cost = Math.Round(maxQuantity * matchPrice, _quoteCurrencyDecimalPlaces);
                    restingOrder.Cost  += cost;
                    incomingOrder.Cost += cost;
                    bool orderFilled       = _book.FillOrder(restingOrder, maxQuantity);
                    bool isRestingTipAdded = false;
                    if (orderFilled)
                    {
                        _currentOrders.Remove(restingOrder.OrderId);
                        if (restingOrder.CancelOn > 0)
                        {
                            RemoveGoodTillDateOrder(restingOrder.CancelOn, restingOrder.OrderId);
                        }

                        if (restingOrder.IsTip)
                        {
                            isRestingTipAdded = AddTip(restingOrder, restingOrder.Cost);
                        }
                    }

                    bool isIncomingOrderFilled = incomingOrder.IsFilled;
                    if (incomingOrder.IsTip == true)
                    {
                        isIncomingOrderFilled = !_currentIcebergOrders.ContainsKey(incomingOrder.OrderId);
                    }

                    bool isRestingOrderFilled = restingOrder.IsFilled && !isRestingTipAdded;

                    Quantity?askRemainingQuanity = null;
                    Quantity?bidCost             = null;
                    if (incomingOrder.IsBuy)
                    {
                        if (isIncomingOrderFilled)
                        {
                            bidCost = incomingOrder.Cost;
                        }
                        if (isRestingOrderFilled)
                        {
                            askRemainingQuanity = restingOrder.OpenQuantity;
                        }
                    }
                    else
                    {
                        if (isRestingOrderFilled)
                        {
                            bidCost = restingOrder.Cost;
                        }
                        if (isIncomingOrderFilled)
                        {
                            askRemainingQuanity = incomingOrder.OpenQuantity;
                        }
                    }

                    _tradeListener?.OnTrade(incomingOrder.OrderId, restingOrder.OrderId, matchPrice, maxQuantity, askRemainingQuanity, bidCost);
                    _marketPrice    = matchPrice;
                    anyMatchHappend = true;
                }
                else
                {
                    break;
                }

                if (incomingOrder.IsFilled)
                {
                    break;
                }
            }
            return(anyMatchHappend);
        }
 public static byte[] Serialize(OrderId orderId, Quantity remainingQuantity, Quantity cost, Quantity fee, CancelReason cancelReason, int timeStamp)
 {
     byte[] msg = new byte[sizeOfMessage];
     Write(msg, messageLengthOffset, sizeOfMessage);
     msg[messageTypeOffset] = (byte)MessageType.Cancel;
     Write(msg, versionOffset, version);
     Write(msg, orderIdOffset, orderId);
     Write(msg, remainingQuantityOffset, remainingQuantity);
     msg[cancelReasonOffset] = (byte)cancelReason;
     Write(msg, timestampOffset, timeStamp);
     Write(msg, costOffset, cost);
     Write(msg, feeOffset, fee);
     return(msg);
 }
Beispiel #3
0
 internal void AddOrder(Order order)
 {
     _quantity += order.OpenQuantity;
     _orders.Add(order);
 }
Beispiel #4
0
 internal bool RemoveOrder(Order order)
 {
     _quantity -= order.OpenQuantity;
     return(_orders.Remove(order));
 }
 public static byte[] Serialize(ulong makerOrderId, ulong takerOrderId, Price matchRate, Quantity matchQuantity, long timeStamp, bool incomingOrderFilled)
 {
     byte[] msg = new byte[sizeOfMessage];
     Write(msg, messageLengthOffset, sizeOfMessage);
     msg[messageTypeOffset] = (byte)MessageType.Fill;
     Write(msg, versionOffset, version);
     Write(msg, makerOrderIdOffset, makerOrderId);
     Write(msg, takerOrderIdOffset, takerOrderId);
     Write(msg, matchRateOffset, matchRate);
     Write(msg, matchQuantityOffset, matchQuantity);
     Write(msg, timestampOffset, timeStamp);
     Write(msg, incomingOrderFilledOffset, incomingOrderFilled);
     return(msg);
 }
Beispiel #6
0
 public QuantityTrackingPriceLevel(Price price)
 {
     _price    = price;
     _quantity = 0;
     _orders   = new SortedSet <Order>(_orderSequenceComparer);
 }
        private bool MatchWithOpenOrders(Order incomingOrder)
        {
            bool anyMatchHappend = false;

            while (true)
            {
                Order?restingOrder = _book.GetBestBuyOrderToMatch(!incomingOrder.IsBuy);
                if (restingOrder == null)
                {
                    break;
                }

                if ((incomingOrder.IsBuy && (restingOrder.Price <= incomingOrder.Price || incomingOrder.Price == 0)) || (!incomingOrder.IsBuy && (restingOrder.Price >= incomingOrder.Price)))
                {
                    Price    matchPrice  = restingOrder.Price;
                    Quantity maxQuantity = 0;
                    if (incomingOrder.OpenQuantity > 0)
                    {
                        maxQuantity = incomingOrder.OpenQuantity >= restingOrder.OpenQuantity ? restingOrder.OpenQuantity : incomingOrder.OpenQuantity;
                        incomingOrder.OpenQuantity -= maxQuantity;
                    }
                    else
                    {
                        throw new Exception(Constant.NOT_EXPECTED);
                    }

                    var cost = Math.Round(maxQuantity * matchPrice, _quoteCurrencyDecimalPlaces);
                    restingOrder.Cost  += cost;
                    incomingOrder.Cost += cost;
                    var incomingFee = _feeProvider.GetFee(incomingOrder.FeeId);
                    var restingFee  = _feeProvider.GetFee(restingOrder.FeeId);
                    restingOrder.Fee  += Math.Round((cost * restingFee.MakerFee) / 100, _quoteCurrencyDecimalPlaces);
                    incomingOrder.Fee += Math.Round((cost * incomingFee.TakerFee) / 100, _quoteCurrencyDecimalPlaces);
                    bool orderFilled       = _book.FillOrder(restingOrder, maxQuantity);
                    bool isRestingTipAdded = false;
                    if (orderFilled)
                    {
                        _currentOrders.Remove(restingOrder.OrderId);
                        if (restingOrder.CancelOn > 0)
                        {
                            RemoveGoodTillDateOrder(restingOrder.CancelOn, restingOrder.OrderId);
                        }

                        if (restingOrder.IsTip)
                        {
                            isRestingTipAdded = AddTip(restingOrder);
                        }
                    }

                    bool isIncomingOrderFilled = incomingOrder.IsFilled;
                    if (incomingOrder.IsTip == true)
                    {
                        isIncomingOrderFilled = incomingOrder.TotalQuantity == 0;
                    }

                    bool isRestingOrderFilled = restingOrder.IsFilled && !isRestingTipAdded;

                    Quantity?askRemainingQuanity = null;
                    Quantity?askFee  = null;
                    Quantity?bidCost = null;
                    Quantity?bidFee  = null;
                    if (incomingOrder.IsBuy)
                    {
                        if (isIncomingOrderFilled)
                        {
                            bidCost = incomingOrder.Cost;
                            bidFee  = incomingOrder.Fee;
                        }
                        if (isRestingOrderFilled)
                        {
                            askRemainingQuanity = restingOrder.OpenQuantity;
                            askFee = restingOrder.Fee;
                        }
                    }
                    else
                    {
                        if (isRestingOrderFilled)
                        {
                            bidCost = restingOrder.Cost;
                            bidFee  = restingOrder.Fee;
                        }
                        if (isIncomingOrderFilled)
                        {
                            askRemainingQuanity = incomingOrder.OpenQuantity;
                            askFee = incomingOrder.Fee;
                        }
                    }

                    _tradeListener?.OnTrade(incomingOrder.OrderId, restingOrder.OrderId, matchPrice, maxQuantity, askRemainingQuanity, askFee, bidCost, bidFee);
                    _marketPrice    = matchPrice;
                    anyMatchHappend = true;
                }
                else
                {
                    break;
                }

                if (incomingOrder.IsFilled)
                {
                    break;
                }
            }
            return(anyMatchHappend);
        }
        public MatchingEngine(ITradeListener tradeListener, IFeeProvider feeProvider, Quantity stepSize, int quoteCurrencyDecimalPlaces = 0)
        {
            if (quoteCurrencyDecimalPlaces < 0)
            {
                throw new NotSupportedException($"Invalid value of {nameof(quoteCurrencyDecimalPlaces)}");
            }

            if (stepSize < 0)
            {
                throw new NotSupportedException($"Invalid value of {nameof(stepSize)}");
            }

            _book                       = new Book();
            _currentOrders              = new Dictionary <OrderId, Order>();
            _goodTillDateOrders         = new SortedDictionary <int, HashSet <OrderId> >();
            _acceptedOrders             = new HashSet <OrderId>();
            _tradeListener              = tradeListener;
            _feeProvider                = feeProvider;
            _quoteCurrencyDecimalPlaces = quoteCurrencyDecimalPlaces;
            _power                      = (decimal)Math.Pow(10, _quoteCurrencyDecimalPlaces);
            _stepSize                   = stepSize;
        }
Beispiel #9
0
 public bool CheckCanFillMarketOrderAmount(bool isBuy, Quantity orderAmount)
 {
     return(isBuy ? CheckMarketOrderAmountCanBeFilled(orderAmount, _askSide) : CheckMarketOrderAmountCanBeFilled(orderAmount, _bidSide));
 }
Beispiel #10
0
 public bool CheckCanFillOrder(bool isBuy, Quantity requestedQuantity, Price limitPrice)
 {
     return(isBuy ? CheckBuyOrderCanBeFilled(requestedQuantity, limitPrice) : CheckSellOrderCanBeFilled(requestedQuantity, limitPrice));
 }
Beispiel #11
0
        private (bool anyMatch, bool isMarketOrderLessThanStepSize) MatchWithOpenOrders(Order incomingOrder)
        {
            bool anyMatchHappend = false;
            bool isMarketOrderLessThanStepSize = false;

            while (true)
            {
                Order restingOrder = _book.GetBestBuyOrderToMatch(!incomingOrder.IsBuy);
                if (restingOrder == null)
                {
                    break;
                }

                if ((incomingOrder.IsBuy && (restingOrder.Price <= incomingOrder.Price || incomingOrder.Price == 0)) || (!incomingOrder.IsBuy && (restingOrder.Price >= incomingOrder.Price)))
                {
                    Price    matchPrice  = restingOrder.Price;
                    Quantity maxQuantity = 0;
                    if (incomingOrder.Price == 0 && incomingOrder.IsBuy == true && incomingOrder.OpenQuantity == 0 && incomingOrder.OrderAmount != 0)
                    {
                        Quantity quantity = incomingOrder.OrderAmount / matchPrice;
                        quantity = quantity - (quantity % _stepSize);
                        if (quantity == 0)
                        {
                            isMarketOrderLessThanStepSize = true;
                            break;
                        }

                        maxQuantity = quantity >= restingOrder.OpenQuantity ? restingOrder.OpenQuantity : quantity;
                        var tradeAmount = decimal.Round(maxQuantity * matchPrice * _power) / _power;
                        if (tradeAmount == 0)
                        {
                            isMarketOrderLessThanStepSize = true;
                            break;
                        }

                        incomingOrder.OrderAmount -= tradeAmount;
                    }
                    else if (incomingOrder.OpenQuantity != 0)
                    {
                        maxQuantity = incomingOrder.OpenQuantity >= restingOrder.OpenQuantity ? restingOrder.OpenQuantity : incomingOrder.OpenQuantity;
                        incomingOrder.OpenQuantity -= maxQuantity;
                    }
                    else
                    {
                        throw new Exception("not expected");
                    }
                    bool orderFilled = _book.FillOrder(restingOrder, maxQuantity);
                    if (orderFilled)
                    {
                        _currentOrders.Remove(restingOrder.OrderId);
                        if (restingOrder.CancelOn > 0)
                        {
                            RemoveGoodTillDateOrder(restingOrder.CancelOn, restingOrder.OrderId);
                        }

                        if (restingOrder.IsTip)
                        {
                            AddTip(restingOrder);
                        }
                    }

                    bool isIncomingOrderFilled = incomingOrder.IsFilled;
                    if (incomingOrder.IsTip == true)
                    {
                        isIncomingOrderFilled = !_currentIcebergOrders.ContainsKey(incomingOrder.OrderId);
                    }

                    _tradeListener?.OnTrade(incomingOrder.OrderId, restingOrder.OrderId, matchPrice, maxQuantity, isIncomingOrderFilled);
                    _marketPrice    = matchPrice;
                    anyMatchHappend = true;
                }
                else
                {
                    break;
                }

                if (incomingOrder.IsFilled)
                {
                    break;
                }
            }
            return(anyMatchHappend, isMarketOrderLessThanStepSize);
        }