Ejemplo n.º 1
0
        public static byte[] Serialize(OrderWrapper order)
        {
            if (order == null)
            {
                throw new ArgumentNullException(nameof(order));
            }

            byte[] msg = new byte[sizeOfMessage];
            Write(msg, messageLengthOffset, sizeOfMessage);
            msg[messageTypeOffset] = (byte)MessageType.NewOrderRequest;
            Write(msg, versionOffset, version);
            Write(msg, sideOffset, order.Order.IsBuy);
            msg[orderConditionOffset] = (byte)order.OrderCondition;
            Write(msg, orderIdOffset, order.Order.OrderId);
            Write(msg, priceOffset, order.Order.Price);

            if (order.TipQuantity > 0 && order.TotalQuantity > 0)
            {
                Write(msg, quantityOffset, order.TipQuantity);
            }
            else
            {
                Write(msg, quantityOffset, order.Order.OpenQuantity);
            }

            Write(msg, stopPriceOffset, order.StopPrice);
            Write(msg, totalQuantityOffset, order.TotalQuantity);
            Write(msg, cancelOnOffset, order.Order.CancelOn);
            Write(msg, orderAmountOffset, order.Order.OrderAmount);
            return(msg);
        }
Ejemplo n.º 2
0
        public static OrderWrapper Deserialize(byte[] bytes)
        {
            if (bytes == null)
            {
                throw new ArgumentNullException(nameof(bytes));
            }

            if (bytes.Length != sizeOfMessage)
            {
                throw new Exception("Order Message must be of Size : " + sizeOfMessage);
            }

            var messageType = (MessageType)(bytes[messageTypeOffset]);

            if (messageType != MessageType.NewOrderRequest)
            {
                throw new Exception("Invalid Message");
            }

            var version = BitConverter.ToInt16(bytes, versionOffset);

            if (version != OrderSerializer.version)
            {
                throw new Exception("version mismatch");
            }

            var order = new OrderWrapper();

            order.Order = new Order();

            order.Order.IsBuy        = BitConverter.ToBoolean(bytes, sideOffset);
            order.OrderCondition     = (OrderCondition)bytes[orderConditionOffset];
            order.Order.OrderId      = BitConverter.ToInt32(bytes, orderIdOffset);
            order.Order.Price        = ReadPrice(bytes, priceOffset);
            order.Order.OpenQuantity = ReadQuantity(bytes, quantityOffset);
            order.StopPrice          = ReadPrice(bytes, stopPriceOffset);
            if (order.StopPrice > 0)
            {
                order.Order.IsStop = true;
            }

            order.TotalQuantity = ReadQuantity(bytes, totalQuantityOffset);
            if (order.TotalQuantity > 0)
            {
                order.TipQuantity = order.Order.OpenQuantity;
            }

            order.Order.CancelOn = BitConverter.ToInt32(bytes, cancelOnOffset);
            order.OrderAmount    = ReadQuantity(bytes, orderAmountOffset);
            order.Order.FeeId    = BitConverter.ToInt16(bytes, feeIdOffset);
            return(order);
        }
Ejemplo n.º 3
0
        public OrderMatchingResult AddOrder(OrderWrapper orderWrapper, bool isOrderTriggered = false)
        {
            var incomingOrder = orderWrapper.Order;

            if (incomingOrder == null)
            {
                throw new ArgumentNullException(nameof(incomingOrder));
            }

            incomingOrder.IsTip = false;

            if (incomingOrder.Price < 0 || (incomingOrder.OpenQuantity <= 0 && orderWrapper.OrderAmount == 0) || (incomingOrder.OpenQuantity == 0 && orderWrapper.OrderAmount <= 0) || orderWrapper.StopPrice < 0 || orderWrapper.TotalQuantity < 0)
            {
                return(OrderMatchingResult.InvalidPriceQuantityStopPriceOrderAmountOrTotalQuantity);
            }

            if (orderWrapper.OrderCondition == OrderCondition.BookOrCancel && (incomingOrder.Price == 0 || orderWrapper.StopPrice != 0))
            {
                return(OrderMatchingResult.BookOrCancelCannotBeMarketOrStopOrder);
            }

            if (incomingOrder.OpenQuantity % _stepSize != 0 || orderWrapper.TotalQuantity % _stepSize != 0)
            {
                return(OrderMatchingResult.QuantityAndTotalQuantityShouldBeMultipleOfStepSize);
            }

            if (orderWrapper.OrderCondition == OrderCondition.ImmediateOrCancel && (orderWrapper.StopPrice != 0))
            {
                return(OrderMatchingResult.ImmediateOrCancelCannotBeStopOrder);
            }

            if (orderWrapper.OrderCondition == OrderCondition.FillOrKill && orderWrapper.StopPrice != 0)
            {
                return(OrderMatchingResult.FillOrKillCannotBeStopOrder);
            }

            if (incomingOrder.CancelOn < 0)
            {
                return(OrderMatchingResult.InvalidCancelOnForGTD);
            }

            if (incomingOrder.CancelOn > 0 && (orderWrapper.OrderCondition == OrderCondition.FillOrKill || orderWrapper.OrderCondition == OrderCondition.ImmediateOrCancel))
            {
                return(OrderMatchingResult.GoodTillDateCannotBeIOCorFOK);
            }

            if (incomingOrder.Price == 0 && orderWrapper.OrderAmount != 0 && incomingOrder.OpenQuantity != 0)
            {
                return(OrderMatchingResult.MarketOrderOnlySupportedOrderAmountOrQuantityNoBoth);
            }

            if (orderWrapper.OrderAmount != 0 && (incomingOrder.Price != 0 || !incomingOrder.IsBuy))
            {
                return(OrderMatchingResult.OrderAmountOnlySupportedForMarketBuyOrder);
            }

            if (orderWrapper.TotalQuantity > 0)
            {
                incomingOrder.OpenQuantity = orderWrapper.TipQuantity;
                if (orderWrapper.OrderCondition == OrderCondition.FillOrKill || orderWrapper.OrderCondition == OrderCondition.ImmediateOrCancel)
                {
                    return(OrderMatchingResult.IcebergOrderCannotBeFOKorIOC);
                }
                if (orderWrapper.StopPrice != 0 || incomingOrder.Price == 0)
                {
                    return(OrderMatchingResult.IcebergOrderCannotBeStopOrMarketOrder);
                }
                if (orderWrapper.TotalQuantity <= orderWrapper.TipQuantity)
                {
                    return(OrderMatchingResult.InvalidIcebergOrderTotalQuantity);
                }
            }

            if (_acceptedOrders.Contains(incomingOrder.OrderId))
            {
                return(OrderMatchingResult.DuplicateOrder);
            }
            _acceptedOrders.Add(incomingOrder.OrderId);
            _tradeListener?.OnAccept(incomingOrder.OrderId);
            if (orderWrapper.OrderAmount != 0 && orderWrapper.StopPrice != 0)
            {
                _orderAmount.Add(orderWrapper.Order.OrderId, orderWrapper.OrderAmount);
            }

            Quantity?quantity    = null;
            bool     canBeFilled = false;

            if (orderWrapper.Order.IsBuy && orderWrapper.Order.OpenQuantity == 0 && orderWrapper.StopPrice == 0)
            {
                var quantityAndFill = GetQuantity(orderWrapper.OrderAmount);
                if (quantityAndFill.Quantity.HasValue)
                {
                    quantity    = quantityAndFill.Quantity.Value;
                    canBeFilled = quantityAndFill.CanFill;
                }
            }

            var timeNow = _timeProvider.GetSecondsFromEpoch();

            CancelExpiredOrders(timeNow);
            if (orderWrapper.OrderCondition == OrderCondition.BookOrCancel && ((incomingOrder.IsBuy && _book.BestAskPrice <= incomingOrder.Price) || (!incomingOrder.IsBuy && incomingOrder.Price <= _book.BestBidPrice)))
            {
                if (orderWrapper.TotalQuantity == 0)
                {
                    _tradeListener?.OnCancel(incomingOrder.OrderId, incomingOrder.OpenQuantity, incomingOrder.Cost, CancelReason.BookOrCancel);
                }
                else
                {
                    _tradeListener?.OnCancel(incomingOrder.OrderId, orderWrapper.TotalQuantity, incomingOrder.Cost, CancelReason.BookOrCancel);
                }
            }
            else if (orderWrapper.OrderCondition == OrderCondition.FillOrKill && orderWrapper.OrderAmount == 0 && !_book.CheckCanFillOrder(incomingOrder.IsBuy, incomingOrder.OpenQuantity, incomingOrder.Price))
            {
                _tradeListener?.OnCancel(incomingOrder.OrderId, incomingOrder.OpenQuantity, incomingOrder.Cost, CancelReason.FillOrKill);
            }
            else if (orderWrapper.OrderCondition == OrderCondition.FillOrKill && orderWrapper.OrderAmount != 0 && canBeFilled == false)
            {
                _tradeListener?.OnCancel(incomingOrder.OrderId, 0, 0, CancelReason.FillOrKill);
            }
            else if (incomingOrder.CancelOn > 0 && incomingOrder.CancelOn <= timeNow)
            {
                if (orderWrapper.TotalQuantity == 0)
                {
                    _tradeListener?.OnCancel(incomingOrder.OrderId, incomingOrder.OpenQuantity, incomingOrder.Cost, CancelReason.ValidityExpired);
                }
                else
                {
                    _tradeListener?.OnCancel(incomingOrder.OrderId, orderWrapper.TotalQuantity, incomingOrder.Cost, CancelReason.ValidityExpired);
                }
            }
            else
            {
                if (orderWrapper.TotalQuantity > 0)
                {
                    var iceberg = new Iceberg()
                    {
                        TipQuantity = orderWrapper.TipQuantity, TotalQuantity = orderWrapper.TotalQuantity
                    };
                    _currentIcebergOrders.Add(incomingOrder.OrderId, iceberg);
                    incomingOrder = GetTip(incomingOrder, iceberg);
                }
                if (incomingOrder.CancelOn > 0)
                {
                    AddGoodTillDateOrder(incomingOrder.CancelOn, incomingOrder.OrderId);
                }
                _currentOrders.Add(incomingOrder.OrderId, incomingOrder);

                if (orderWrapper.StopPrice != 0 && !isOrderTriggered && ((incomingOrder.IsBuy && orderWrapper.StopPrice > _marketPrice) || (!incomingOrder.IsBuy && (orderWrapper.StopPrice < _marketPrice || _marketPrice == 0))))
                {
                    _book.AddStopOrder(incomingOrder, orderWrapper.StopPrice);
                }
                else
                {
                    if (orderWrapper.Order.IsBuy && orderWrapper.Order.OpenQuantity == 0)
                    {
                        if (quantity.HasValue)
                        {
                            orderWrapper.Order.OpenQuantity = quantity.Value;
                            MatchAndAddOrder(incomingOrder, orderWrapper.OrderCondition);
                        }
                        else
                        {
                            _currentOrders.Remove(orderWrapper.Order.OrderId);
                            _tradeListener?.OnCancel(orderWrapper.Order.OrderId, 0, 0, CancelReason.MarketOrderNoLiquidity);
                        }
                    }
                    else
                    {
                        MatchAndAddOrder(incomingOrder, orderWrapper.OrderCondition);
                    }
                }
            }

            return(OrderMatchingResult.OrderAccepted);
        }