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;
                    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, restingOrder.Cost, restingOrder.Fee);
                        }
                    }

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

                    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);
        }
Example #2
0
 public bool CheckCanFillOrder(bool isBuy, Quantity requestedQuantity, Price limitPrice)
 {
     return(isBuy ? CheckBuyOrderCanBeFilled(requestedQuantity, limitPrice) : CheckSellOrderCanBeFilled(requestedQuantity, limitPrice));
 }
Example #3
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);
        }