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