/// <summary>
        /// Emits a new trade tick from a match message
        /// </summary>
        private void EmitTradeTick(Messages.Matched message)
        {
            var symbol = _symbolMapper.GetLeanSymbol(message.ProductId, SecurityType.Crypto, Market.GDAX);

            _aggregator.Update(new Tick
            {
                Value    = message.Price,
                Time     = DateTime.UtcNow,
                Symbol   = symbol,
                TickType = TickType.Trade,
                Quantity = message.Size
            });
        }
        /// <summary>
        /// Emits a new trade tick from a match message
        /// </summary>
        private void EmitTradeTick(Messages.Matched message)
        {
            var symbol = ConvertProductId(message.ProductId);

            _aggregator.Update(new Tick
            {
                Value    = message.Price,
                Time     = DateTime.UtcNow,
                Symbol   = symbol,
                TickType = TickType.Trade,
                Quantity = message.Size
            });
        }
        /// <summary>
        /// Emits a new trade tick from a match message
        /// </summary>
        private void EmitTradeTick(Messages.Matched message)
        {
            var symbol = ConvertProductId(message.ProductId);

            lock (TickLocker)
            {
                Ticks.Add(new Tick
                {
                    Value    = message.Price,
                    Time     = DateTime.UtcNow,
                    Symbol   = symbol,
                    TickType = TickType.Trade,
                    Quantity = message.Size
                });
            }
        }
        private void EmitFillOrderEvent(Messages.Matched message, Symbol symbol, GDAXFill split, bool isFinalFill)
        {
            var order = split.Order;

            var status = isFinalFill ? 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;
            }

            var fillPrice    = message.Price;
            var fillQuantity = direction == OrderDirection.Sell ? -message.Size : message.Size;
            var isMaker      = order.BrokerId[0] == message.MakerOrderId;

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

            var orderFee = new OrderFee(new CashAmount(
                                            GetFillFee(_algorithm.UtcTime, fillPrice, fillQuantity, isMaker),
                                            currency));

            var orderEvent = new OrderEvent
                             (
                order.Id, symbol, message.Time, status,
                direction, fillPrice, fillQuantity,
                orderFee, $"GDAX Match 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);
            }

            OnOrderEvent(orderEvent);
        }