/// <summary>
        /// Обработать сообщение.
        /// </summary>
        /// <param name="message">Сообщение.</param>
        /// <returns>Результат обработки. Если будет возрвщено <see langword="null"/>,
        /// то генератору пока недостаточно данных для генерации нового сообщения.</returns>
        public override Message Process(Message message)
        {
            if (message.Type == MessageTypes.Security)
            {
                TradeGenerator.Process(message);
            }

            return(base.Process(message));
        }
        /// <summary>
        /// Обработать сообщение.
        /// </summary>
        /// <param name="message">Сообщение.</param>
        /// <returns>Результат обработки. Если будет возрвщено <see langword="null"/>,
        /// то генератору пока недостаточно данных для генерации нового сообщения.</returns>
        protected override Message OnProcess(Message message)
        {
            DateTimeOffset time;

            switch (message.Type)
            {
            case MessageTypes.Level1Change:
            {
                var l1Msg = (Level1ChangeMessage)message;

                var value = l1Msg.Changes.TryGetValue(Level1Fields.LastTradePrice);

                if (value != null)
                {
                    _lastOrderPrice = (decimal)value;
                }

                TradeGenerator.Process(message);

                time = l1Msg.ServerTime;
                break;
            }

            case MessageTypes.Execution:
            {
                var execMsg = (ExecutionMessage)message;

                switch (execMsg.ExecutionType)
                {
                case ExecutionTypes.Tick:
                    _lastOrderPrice = execMsg.GetTradePrice();
                    break;

                default:
                    return(null);
                }

                time = execMsg.ServerTime;
                break;
            }

            case MessageTypes.Time:
            {
                var timeMsg = (TimeMessage)message;

                time = timeMsg.ServerTime;

                break;
            }

            default:
                return(null);
            }

            if (!IsTimeToGenerate(time))
            {
                return(null);
            }

            // TODO более реалистичную генерацию, так как сейчас объемы, цены и сделки c потолка

            var action = RandomGen.GetInt(0, 5);

            var isNew = action < 3 || _activeOrders.IsEmpty();

            ExecutionMessage item;

            if (isNew)
            {
                var priceStep = SecurityDefinition.PriceStep ?? 0.01m;

                _lastOrderPrice += RandomGen.GetInt(-MaxPriceStepCount, MaxPriceStepCount) * priceStep;

                if (_lastOrderPrice <= 0)
                {
                    _lastOrderPrice = priceStep;
                }

                item = new ExecutionMessage
                {
                    OrderId       = IdGenerator.GetNextId(),
                    SecurityId    = SecurityId,
                    ServerTime    = time,
                    OrderState    = OrderStates.Active,
                    Volume        = Volumes.Next(),
                    Side          = RandomGen.GetEnum <Sides>(),
                    Price         = _lastOrderPrice,
                    ExecutionType = ExecutionTypes.OrderLog,
                };

                _activeOrders.Enqueue((ExecutionMessage)item.Clone());
            }
            else
            {
                var activeOrder = _activeOrders.Peek();

                item            = (ExecutionMessage)activeOrder.Clone();
                item.ServerTime = time;

                var isMatched = action == 5;

                ExecutionMessage trade = null;

                if (isMatched)
                {
                    trade = (ExecutionMessage)TradeGenerator.Process(message);
                }

                if (isMatched && trade != null)
                {
                    item.Volume = RandomGen.GetInt(1, (int)activeOrder.GetVolume());

                    item.TradeId     = trade.TradeId;
                    item.TradePrice  = trade.TradePrice;
                    item.TradeStatus = trade.TradeStatus;

                    // TODO
                    //quote.Trade = TradeGenerator.Generate(time);
                    //item.Volume = activeOrder.Volume;

                    //if (item.Side == Sides.Buy && quote.Trade.Price > quote.Order.Price)
                    //	item.TradePrice = item.Price;
                    //else if (item.Side == Sides.Sell && quote.Trade.Price < quote.Order.Price)
                    //	item.TradePrice = item.Price;

                    activeOrder.Volume -= item.Volume;

                    if (activeOrder.Volume == 0)
                    {
                        item.OrderState = OrderStates.Done;
                        _activeOrders.Dequeue();
                    }
                    else
                    {
                        item.OrderState = OrderStates.Active;
                    }
                }
                else
                {
                    item.OrderState  = OrderStates.Done;
                    item.IsCancelled = true;
                    _activeOrders.Dequeue();
                }
            }

            LastGenerationTime = time;

            return(item);
        }