/// <summary>
        /// сообщение содержит котировку: одну цену либо бид и аск сразу
        /// </summary>
        public static void ProcessMsgQuote(FixMessage msg)
        {
            loggerNoFlood.LogMessageFormatCheckFlood(LogEntryType.Info,
                                                     LogMagicMarketData, 1000 * 60 * 60 * 2, "Quote: {0}", msg.ToString());

            string symbol = msg.GetValueString(FixMessage.TAG_SYMBOL);

            if (string.IsNullOrEmpty(symbol))
            {
                Logger.Debug("Quote msg: no symbol tag");
                return;
            }

            if (!ConvertFromProviderSymbolNaming(ref symbol))
            {
                return;
            }

            var bid = msg.GetValueFloat(FixMessage.TAG_BID_PRICE);
            var ask = msg.GetValueFloat(FixMessage.TAG_OFFER_PRICE);

            if (!bid.HasValue && ask.HasValue == false)
            {
                Logger.Debug("Quote msg: no bid - ask");
                return;
            }
            QuoteDistributor.Instance.UpdateQuote(symbol, bid, ask);
        }
        public static void ProcessMsgMarketDataIncrRefresh(Message msgOrig, FixMessage msg)
        {
            loggerNoFlood.LogMessageFormatCheckFlood(LogEntryType.Info,
                                                     LogMagicMarketData, 1000 * 60 * 60 * 2, "Quote incr: {0}", msg.ToString());

            try
            {
                // информация по тикерам разбита на группы, каждому тикеру - по группе
                var groupHeader = new NoMDEntries();
                msgOrig.getField(groupHeader);
                int numGroups = groupHeader.getValue();

                var group = FixMessage.FixVersion == FixVersion.Fix42
                                ? new QuickFix42.MarketDataIncrementalRefresh.NoMDEntries()
                                : FixMessage.FixVersion == FixVersion.Fix43
                                      ? (Group) new QuickFix43.MarketDataIncrementalRefresh.NoMDEntries()
                                      : new QuickFix44.MarketDataIncrementalRefresh.NoMDEntries();

                var lastQuotes = new System.Collections.Generic.Dictionary <string, QuoteData>();

                for (var i = 1; i <= numGroups; i++)
                {
                    var groupTicker = msgOrig.getGroup((uint)i, group);
                    var symbol      = groupTicker.getField(new Symbol()).getValue();

                    if (!ConvertFromProviderSymbolNaming(ref symbol))
                    {
                        return;
                    }

                    var entType     = new MDEntryType();
                    var entTypeChar = groupTicker.getField(entType).getValue();
                    var priceType   = entTypeChar == FixMessage.VALUE_MD_ENTRY_TYPE_BID[0]
                                        ? Contract.Entity.QuoteType.Bid
                                        : entTypeChar == FixMessage.VALUE_MD_ENTRY_TYPE_OFFER[0]
                                              ? Contract.Entity.QuoteType.Ask
                                              : Contract.Entity.QuoteType.NonSpecified;
                    if (priceType == Contract.Entity.QuoteType.NonSpecified)
                    {
                        continue;
                    }
                    var price = msg.GetValueFloat(FixMessage.TAG_MD_ENTRY_PX) ?? 0;
                    if (price == 0)
                    {
                        continue;
                    }

                    if (lastQuotes.ContainsKey(symbol))
                    {
                        var quote = lastQuotes[symbol];
                        if (priceType == Contract.Entity.QuoteType.Bid)
                        {
                            quote.bid = price;
                        }
                        else
                        {
                            quote.ask = price;
                        }
                    }
                    else
                    {
                        lastQuotes.Add(symbol, new QuoteData(
                                           priceType == Contract.Entity.QuoteType.Bid ? price : 0,
                                           priceType == Contract.Entity.QuoteType.Ask ? price : 0, DateTime.Now));
                    }
                }

                foreach (var quote in lastQuotes)
                {
                    loggerNoFlood.LogMessageFormatCheckFlood(LogEntryType.Info,
                                                             LogMagicQuote, 1000 * 60 * 15,
                                                             "Котировка {0}: {1} - {2}",
                                                             quote.Key, quote.Value.bid, quote.Value.ask);

                    QuoteDistributor.Instance.UpdateQuote(quote.Key,
                                                          quote.Value.bid == 0 ? (float?)null : quote.Value.bid,
                                                          quote.Value.ask == 0 ? (float?)null : quote.Value.ask);
                }

                loggerNoFlood.LogMessageFormatCheckFlood(LogEntryType.Info,
                                                         LogMagicParseMarketDataSuccess,
                                                         1000 * 60 * 10, "Обработан пакет MarketDataIncrRefresh");
            }
            catch (Exception ex)
            {
                loggerNoFlood.LogMessageFormatCheckFlood(LogEntryType.Info,
                                                         LogMagicParseMarketDataError,
                                                         1000 * 60 * 10, "Ошибка разбора MarketDataIncrRefresh: {0}", ex);
            }
        }
        /// <summary>
        /// сообщение содержит котировку: одну цену либо бид и аск сразу
        /// </summary>        
        public static void ProcessMsgQuote(FixMessage msg)
        {
            loggerNoFlood.LogMessageFormatCheckFlood(LogEntryType.Info,
                LogMagicMarketData, 1000 * 60 * 60 * 2, "Quote: {0}", msg.ToString());

            string symbol = msg.GetValueString(FixMessage.TAG_SYMBOL);
            if (string.IsNullOrEmpty(symbol))
            {
                Logger.Debug("Quote msg: no symbol tag");
                return;
            }

            if (!ConvertFromProviderSymbolNaming(ref symbol)) return;

            var bid = msg.GetValueFloat(FixMessage.TAG_BID_PRICE);
            var ask = msg.GetValueFloat(FixMessage.TAG_OFFER_PRICE);
            if (!bid.HasValue && ask.HasValue == false)
            {
                Logger.Debug("Quote msg: no bid - ask");
                return;
            }
            QuoteDistributor.Instance.UpdateQuote(symbol, bid, ask);
        }
        public static void ProcessMsgMarketDataIncrRefresh(Message msgOrig, FixMessage msg)
        {
            loggerNoFlood.LogMessageFormatCheckFlood(LogEntryType.Info,
                LogMagicMarketData, 1000 * 60 * 60 * 2, "Quote incr: {0}", msg.ToString());

            try
            {
                // информация по тикерам разбита на группы, каждому тикеру - по группе
                var groupHeader = new NoMDEntries();
                msgOrig.getField(groupHeader);
                int numGroups = groupHeader.getValue();

                var group = FixMessage.FixVersion == FixVersion.Fix42
                                ? new QuickFix42.MarketDataIncrementalRefresh.NoMDEntries()
                                : FixMessage.FixVersion == FixVersion.Fix43
                                      ? (Group)new QuickFix43.MarketDataIncrementalRefresh.NoMDEntries()
                                      : new QuickFix44.MarketDataIncrementalRefresh.NoMDEntries();

                var lastQuotes = new System.Collections.Generic.Dictionary<string, QuoteData>();

                for (var i = 1; i <= numGroups; i++)
                {
                    var groupTicker = msgOrig.getGroup((uint)i, group);
                    var symbol = groupTicker.getField(new Symbol()).getValue();

                    if (!ConvertFromProviderSymbolNaming(ref symbol)) return;

                    var entType = new MDEntryType();
                    var entTypeChar = groupTicker.getField(entType).getValue();
                    var priceType = entTypeChar == FixMessage.VALUE_MD_ENTRY_TYPE_BID[0]
                                        ? Contract.Entity.QuoteType.Bid
                                        : entTypeChar == FixMessage.VALUE_MD_ENTRY_TYPE_OFFER[0]
                                              ? Contract.Entity.QuoteType.Ask
                                              : Contract.Entity.QuoteType.NonSpecified;
                    if (priceType == Contract.Entity.QuoteType.NonSpecified) continue;
                    var price = msg.GetValueFloat(FixMessage.TAG_MD_ENTRY_PX) ?? 0;
                    if (price == 0) continue;

                    if (lastQuotes.ContainsKey(symbol))
                    {
                        var quote = lastQuotes[symbol];
                        if (priceType == Contract.Entity.QuoteType.Bid)
                            quote.bid = price;
                        else
                            quote.ask = price;
                    }
                    else
                    {
                        lastQuotes.Add(symbol, new QuoteData(
                            priceType == Contract.Entity.QuoteType.Bid ? price : 0,
                            priceType == Contract.Entity.QuoteType.Ask ? price : 0, DateTime.Now));
                    }
                }

                foreach (var quote in lastQuotes)
                {
                    loggerNoFlood.LogMessageFormatCheckFlood(LogEntryType.Info,
                                                             LogMagicQuote, 1000 * 60 * 15,
                                                             "Котировка {0}: {1} - {2}",
                                                             quote.Key, quote.Value.bid, quote.Value.ask);

                    QuoteDistributor.Instance.UpdateQuote(quote.Key,
                        quote.Value.bid == 0 ? (float?)null : quote.Value.bid,
                        quote.Value.ask == 0 ? (float?)null : quote.Value.ask);
                }

                loggerNoFlood.LogMessageFormatCheckFlood(LogEntryType.Info,
                                                         LogMagicParseMarketDataSuccess,
                                                         1000 * 60 * 10, "Обработан пакет MarketDataIncrRefresh");
            }
            catch (Exception ex)
            {
                loggerNoFlood.LogMessageFormatCheckFlood(LogEntryType.Info,
                                                         LogMagicParseMarketDataError,
                                                         1000 * 60 * 10, "Ошибка разбора MarketDataIncrRefresh: {0}", ex);
            }
        }