コード例 #1
0
        private void OrderMatch(string data)
        {
            var message = JsonConvert.DeserializeObject <Messages.Matched>(data, JsonSettings);
            var cached  = CachedOrderIDs.Where(o => o.Value.BrokerId.Contains(message.MakerOrderId) || o.Value.BrokerId.Contains(message.TakerOrderId));

            var symbol = ConvertProductId(message.ProductId);

            if (!cached.Any())
            {
                return;
            }

            Log.Trace($"GDAXBrokerage.OrderMatch(): Match: {message.ProductId} {data}");
            var orderId  = cached.First().Key;
            var orderObj = cached.First().Value;

            if (!FillSplit.ContainsKey(orderId))
            {
                FillSplit[orderId] = new GDAXFill(orderObj);
            }

            var split = FillSplit[orderId];

            split.Add(message);

            //is this the total order at once? Is this the last split fill?
            var status = Math.Abs(message.Size) == Math.Abs(cached.Single().Value.Quantity) || Math.Abs(split.OrderQuantity) == Math.Abs(split.TotalQuantity())
                ? OrderStatus.Filled : OrderStatus.PartiallyFilled;

            OrderDirection direction;

            // Messages are always from the perspective of the market maker. Flip it in cases of a market order.
            if (orderObj.Type == OrderType.Market)
            {
                direction = message.Side == "sell" ? OrderDirection.Buy : OrderDirection.Sell;
            }
            else
            {
                direction = message.Side == "sell" ? OrderDirection.Sell : OrderDirection.Buy;
            }

            var orderEvent = new OrderEvent
                             (
                cached.First().Key, symbol, message.Time, status,
                direction,
                message.Price, direction == OrderDirection.Sell ? -message.Size : message.Size,
                GetFee(cached.First().Value), $"GDAX Match Event {direction}"
                             );

            //if we're filled we won't wait for done event
            if (orderEvent.Status == OrderStatus.Filled)
            {
                Orders.Order outOrder = null;
                CachedOrderIDs.TryRemove(cached.First().Key, out outOrder);
            }

            OnOrderEvent(orderEvent);
        }
コード例 #2
0
        private void EmitFillOrderEvent(Messages.Fill fill, Order order)
        {
            var symbol = _symbolMapper.GetLeanSymbol(fill.ProductId, SecurityType.Crypto, Market.GDAX);

            if (!FillSplit.ContainsKey(order.Id))
            {
                FillSplit[order.Id] = new GDAXFill(order);
            }

            var split = FillSplit[order.Id];

            split.Add(fill);

            // is this the total order at once? Is this the last split fill?
            var isFinalFill = Math.Abs(fill.Size) == Math.Abs(order.Quantity) || Math.Abs(split.OrderQuantity) == Math.Abs(split.TotalQuantity);

            var status = isFinalFill ? OrderStatus.Filled : OrderStatus.PartiallyFilled;

            var direction = fill.Side == "sell" ? OrderDirection.Sell : OrderDirection.Buy;

            var fillPrice    = fill.Price;
            var fillQuantity = direction == OrderDirection.Sell ? -fill.Size : fill.Size;

            var currency = order.PriceCurrency == string.Empty
                ? _algorithm.Securities[symbol].SymbolProperties.QuoteCurrency
                : order.PriceCurrency;

            var orderFee = new OrderFee(new CashAmount(fill.Fee, currency));

            var orderEvent = new OrderEvent
                             (
                order.Id, symbol, fill.CreatedAt, status,
                direction, fillPrice, fillQuantity,
                orderFee, $"GDAX Fill Event {direction}"
                             );

            // when the order is completely filled, we no longer need it in the active order list
            if (orderEvent.Status == OrderStatus.Filled)
            {
                Order outOrder;
                CachedOrderIDs.TryRemove(order.Id, out outOrder);

                PendingOrder removed;
                _pendingOrders.TryRemove(fill.OrderId, out removed);
            }

            OnOrderEvent(orderEvent);
        }
コード例 #3
0
        private void OnMatch(string data)
        {
            // deserialize the current match (trade) message
            var message = JsonConvert.DeserializeObject <Messages.Matched>(data, JsonSettings);

            if (string.IsNullOrEmpty(message.UserId))
            {
                // message received from the "matches" channel
                if (_isDataQueueHandler)
                {
                    EmitTradeTick(message);
                }
                return;
            }

            // message received from the "user" channel, this trade is ours

            // check the list of currently active orders, if the current trade is ours we are either a maker or a taker
            var currentOrder = CachedOrderIDs
                               .FirstOrDefault(o => o.Value.BrokerId.Contains(message.MakerOrderId) || o.Value.BrokerId.Contains(message.TakerOrderId));

            if (currentOrder.Value == null)
            {
                // should never happen, log just in case
                Log.Error($"GDAXBrokerage.OrderMatch(): Unexpected match: {message.ProductId} {data}");
                return;
            }

            Log.Trace($"GDAXBrokerage.OrderMatch(): Match: {message.ProductId} {data}");

            var order = currentOrder.Value;

            if (!FillSplit.ContainsKey(order.Id))
            {
                FillSplit[order.Id] = new GDAXFill(order);
            }

            var split = FillSplit[order.Id];

            split.Add(message);

            var symbol = ConvertProductId(message.ProductId);

            // is this the total order at once? Is this the last split fill?
            var isFinalFill = Math.Abs(message.Size) == Math.Abs(order.Quantity) || Math.Abs(split.OrderQuantity) == Math.Abs(split.TotalQuantity);

            EmitFillOrderEvent(message, symbol, split, isFinalFill);
        }
コード例 #4
0
        private void OrderMatch(string data)
        {
            // deserialize the current match (trade) message
            var message = JsonConvert.DeserializeObject <Messages.Matched>(data, JsonSettings);

            if (_isDataQueueHandler)
            {
                EmitTradeTick(message);
            }

            // check the list of currently active orders, if the current trade is ours we are either a maker or a taker
            var currentOrder = CachedOrderIDs
                               .FirstOrDefault(o => o.Value.BrokerId.Contains(message.MakerOrderId) || o.Value.BrokerId.Contains(message.TakerOrderId));

            if (_pendingGdaxMarketOrderId != null &&
                // order fill for other users
                (currentOrder.Value == null ||
                 // order fill for other order of ours (less likely but may happen)
                 currentOrder.Value.BrokerId[0] != _pendingGdaxMarketOrderId))
            {
                // process all fills for our pending market order
                var fills        = FillSplit[_pendingLeanMarketOrderId];
                var fillMessages = fills.Messages;

                for (var i = 0; i < fillMessages.Count; i++)
                {
                    var fillMessage = fillMessages[i];
                    var isFinalFill = i == fillMessages.Count - 1;

                    // emit all order events with OrderStatus.PartiallyFilled except for the last one which has OrderStatus.Filled
                    EmitFillOrderEvent(fillMessage, fills.Order.Symbol, fills, isFinalFill);
                }

                // clear the pending market order
                _pendingGdaxMarketOrderId = null;
                _pendingLeanMarketOrderId = 0;
            }

            if (currentOrder.Value == null)
            {
                // not our order, nothing else to do here
                return;
            }

            Log.Trace($"GDAXBrokerage.OrderMatch(): Match: {message.ProductId} {data}");

            var order = currentOrder.Value;

            if (order.Type == OrderType.Market)
            {
                // Fill events for this order will be delayed until we receive messages for a different order,
                // so we can know which is the last fill.
                // The market order total filled quantity can be less than the total order quantity,
                // details here: https://github.com/QuantConnect/Lean/issues/1751

                // do not process market order fills immediately, save off the order ids
                _pendingGdaxMarketOrderId = order.BrokerId[0];
                _pendingLeanMarketOrderId = order.Id;
            }

            if (!FillSplit.ContainsKey(order.Id))
            {
                FillSplit[order.Id] = new GDAXFill(order);
            }

            var split = FillSplit[order.Id];

            split.Add(message);

            if (order.Type != OrderType.Market)
            {
                var symbol = ConvertProductId(message.ProductId);

                // is this the total order at once? Is this the last split fill?
                var isFinalFill = Math.Abs(message.Size) == Math.Abs(order.Quantity) || Math.Abs(split.OrderQuantity) == Math.Abs(split.TotalQuantity);

                EmitFillOrderEvent(message, symbol, split, isFinalFill);
            }
        }
コード例 #5
0
        private void OrderMatch(string data)
        {
            var message = JsonConvert.DeserializeObject <Messages.Matched>(data, JsonSettings);

            if (_isDataQueueHandler)
            {
                EmitTradeTick(message);
            }

            var cached = CachedOrderIDs
                         .Where(o => o.Value.BrokerId.Contains(message.MakerOrderId) || o.Value.BrokerId.Contains(message.TakerOrderId))
                         .ToList();

            var symbol = ConvertProductId(message.ProductId);

            if (cached.Count == 0)
            {
                return;
            }

            Log.Trace($"GDAXBrokerage.OrderMatch(): Match: {message.ProductId} {data}");
            var orderId = cached[0].Key;
            var order   = cached[0].Value;

            if (!FillSplit.ContainsKey(orderId))
            {
                FillSplit[orderId] = new GDAXFill(order);
            }

            var split = FillSplit[orderId];

            split.Add(message);

            //is this the total order at once? Is this the last split fill?
            var status = Math.Abs(message.Size) == Math.Abs(order.Quantity) || Math.Abs(split.OrderQuantity) == Math.Abs(split.TotalQuantity())
                ? OrderStatus.Filled : OrderStatus.PartiallyFilled;

            OrderDirection direction;

            // Messages are always from the perspective of the market maker. Flip direction if executed as a taker.
            if (order.BrokerId[0] == message.TakerOrderId)
            {
                direction = message.Side == "sell" ? OrderDirection.Buy : OrderDirection.Sell;
            }
            else
            {
                direction = message.Side == "sell" ? OrderDirection.Sell : OrderDirection.Buy;
            }

            decimal totalOrderFee;

            if (!_orderFees.TryGetValue(orderId, out totalOrderFee))
            {
                totalOrderFee       = GetFee(order);
                _orderFees[orderId] = totalOrderFee;
            }

            // apply order fee on a pro rata basis
            var orderFee = totalOrderFee * Math.Abs(message.Size) / Math.Abs(order.Quantity);

            var orderEvent = new OrderEvent
                             (
                orderId, symbol, message.Time, status,
                direction,
                message.Price, direction == OrderDirection.Sell ? -message.Size : message.Size,
                orderFee, $"GDAX Match Event {direction}"
                             );

            //if we're filled we won't wait for done event
            if (orderEvent.Status == OrderStatus.Filled)
            {
                Order outOrder;
                CachedOrderIDs.TryRemove(orderId, out outOrder);

                decimal outOrderFee;
                _orderFees.TryRemove(orderId, out outOrderFee);
            }

            OnOrderEvent(orderEvent);
        }