private static Level1ChangeMessage ToLevel2(string value)
        {
            var parts = value.SplitByComma();

            var isBidValid = parts[10] == "T";
            var isAskValid = parts[11] == "T";

            if (!isBidValid && !isAskValid)
            {
                return(null);
            }

            var date = parts[7].ToDateTime("yyyy-MM-dd");

            var l1Msg = new Level1ChangeMessage
            {
                SecurityId = new SecurityId
                {
                    SecurityCode = parts[0],
                    BoardCode    = parts[1]
                },
            };

            // http://www.iqfeed.net/dev/api/docs/ConditionCodes.cfm
            l1Msg.Add(Level1Fields.IsSystem, parts[8] == "52");

            if (isAskValid)
            {
                l1Msg.ServerTime = date.Add(parts[9].To <TimeSpan>()).ApplyTimeZone(TimeHelper.Est);

                l1Msg
                .TryAdd(Level1Fields.BestAskPrice, parts[3].To <decimal>())
                .TryAdd(Level1Fields.BestAskVolume, parts[5].To <decimal>())
                .Add(Level1Fields.BestAskTime, l1Msg.ServerTime);
            }

            if (isBidValid)
            {
                var bidTime = date.Add(parts[6].To <TimeSpan>()).ApplyTimeZone(TimeHelper.Est);

                if (bidTime > l1Msg.ServerTime)
                {
                    l1Msg.ServerTime = bidTime;
                }

                l1Msg
                .TryAdd(Level1Fields.BestBidPrice, parts[2].To <decimal>())
                .TryAdd(Level1Fields.BestBidVolume, parts[4].To <decimal>())
                .Add(Level1Fields.BestBidTime, bidTime);
            }

            return(l1Msg);
        }
        private void OnSecInfoResponse(SecInfoResponse response)
        {
            var securityId = new SecurityId
            {
                Native       = response.SecId,
                SecurityCode = response.SecCode,
                BoardCode    = _boards[response.Market],
            };

            SendOutMessage(new SecurityMessage
            {
                SecurityId = securityId,
                ExpiryDate = response.MatDate == null ? (DateTimeOffset?)null : response.MatDate.Value.ApplyTimeZone(TimeHelper.Moscow),
                OptionType = response.PutCall == null ? (OptionTypes?)null : response.PutCall.Value.FromTransaq(),
            });

            var l1Msg = new Level1ChangeMessage
            {
                SecurityId = new SecurityId {
                    Native = response.SecId
                },
                ServerTime = SessionHolder.CurrentTime.Convert(TimeHelper.Moscow),
            };

            l1Msg.TryAdd(Level1Fields.MinPrice, response.MinPrice);
            l1Msg.TryAdd(Level1Fields.MaxPrice, response.MaxPrice);

            var marginBuy = response.BuyDeposit;

            if (marginBuy == null || marginBuy == 0m)
            {
                marginBuy = response.BgoBuy;
            }

            var marginSell = response.SellDeposit;

            if (marginSell == null || marginSell == 0m)
            {
                marginSell = response.BgoC;
            }

            l1Msg.TryAdd(Level1Fields.MarginBuy, marginBuy);
            l1Msg.TryAdd(Level1Fields.MarginSell, marginSell);

            SendOutMessage(l1Msg);
        }
        private void FlushQuotes(SecurityId secId)
        {
            var quotes = _quotes.TryGetValue(secId);

            if (quotes == null)
            {
                return;
            }

            _quotes.Remove(secId);

            foreach (var pair in quotes.CachedPairs)
            {
                var message = new Level1ChangeMessage
                {
                    SecurityId = secId,
                    ServerTime = pair.Key
                };

                var bid = pair.Value.First;

                if (bid != null)
                {
                    message
                    .TryAdd(Level1Fields.BestBidPrice, bid.Price.ToDecimal())
                    .TryAdd(Level1Fields.BestBidVolume, (decimal)bid.Size);
                }

                var ask = pair.Value.Second;

                if (ask != null)
                {
                    message
                    .TryAdd(Level1Fields.BestAskPrice, ask.Price.ToDecimal())
                    .TryAdd(Level1Fields.BestAskVolume, (decimal)ask.Size);
                }

                SendOutMessage(message);
            }
        }
Ejemplo n.º 4
0
        private void EmulationConnectorOnNewSecurity(Security security)
        {
            var level1Info = new Level1ChangeMessage
            {
                SecurityId = security.ToSecurityId(),
                ServerTime = EmulationSettings.StartTime
            };

            if (security.PriceStep != null)
            {
                level1Info.TryAdd(Level1Fields.PriceStep, security.PriceStep.Value);
            }

            if (security.StepPrice != null)
            {
                level1Info.TryAdd(Level1Fields.StepPrice, security.StepPrice.Value);
            }

            level1Info.TryAdd(Level1Fields.MinPrice, security.MinPrice ?? 1m);
            level1Info.TryAdd(Level1Fields.MaxPrice, security.MaxPrice ?? 1000000m);

            if (security.MarginBuy != null)
            {
                level1Info.TryAdd(Level1Fields.MarginBuy, security.MarginBuy.Value);
            }

            if (security.MarginSell != null)
            {
                level1Info.TryAdd(Level1Fields.MarginSell, security.MarginSell.Value);
            }

            // fill level1 values
            EmulationConnector.SendInMessage(level1Info);
        }
Ejemplo n.º 5
0
        private void SessionOnStiGreeksUpdate(ref structSTIGreeksUpdate structGreeksUpdate)
        {
            var message = new Level1ChangeMessage
            {
                SecurityId = new SecurityId
                {
                    SecurityCode = structGreeksUpdate.bstrSymbol,
                    BoardCode    = AssociatedBoardCode,
                },
                ServerTime = CurrentTime,
            };

            message.TryAdd(Level1Fields.Delta, (decimal)structGreeksUpdate.fDelta);
            message.TryAdd(Level1Fields.Gamma, (decimal)structGreeksUpdate.fGamma);
            message.TryAdd(Level1Fields.Theta, (decimal)structGreeksUpdate.fTheta);
            message.TryAdd(Level1Fields.Vega, (decimal)structGreeksUpdate.fVega);
            message.TryAdd(Level1Fields.Rho, (decimal)structGreeksUpdate.fRho);
            message.TryAdd(Level1Fields.TheorPrice, (decimal)structGreeksUpdate.fTheoPrice);
            message.TryAdd(Level1Fields.ImpliedVolatility, (decimal)structGreeksUpdate.fImpVol);

            SendOutMessage(message);
        }
        private void OnQuotationsResponse(QuotationsResponse response)
        {
            foreach (var quote in response.Quotations)
            {
                var message = new Level1ChangeMessage
                {
                    SecurityId = new SecurityId {
                        Native = quote.SecId
                    },
                    ServerTime = SessionHolder.CurrentTime.Convert(TimeHelper.Moscow),
                };

                message.TryAdd(Level1Fields.AccruedCouponIncome, quote.AccruedIntValue);
                message.TryAdd(Level1Fields.OpenPrice, quote.Open);
                message.TryAdd(Level1Fields.HighPrice, quote.High);
                message.TryAdd(Level1Fields.LowPrice, quote.Low);
                message.TryAdd(Level1Fields.ClosePrice, quote.ClosePrice);
                message.TryAdd(Level1Fields.BidsCount, quote.BidsCount);
                message.TryAdd(Level1Fields.BidsVolume, (decimal?)quote.BidsVolume);
                message.TryAdd(Level1Fields.AsksCount, quote.AsksCount);
                message.TryAdd(Level1Fields.AsksVolume, (decimal?)quote.AsksVolume);
                message.TryAdd(Level1Fields.HighBidPrice, quote.HighBid);
                message.TryAdd(Level1Fields.LowAskPrice, quote.LowAsk);
                message.TryAdd(Level1Fields.Yield, quote.Yield);
                message.TryAdd(Level1Fields.MarginBuy, quote.BuyDeposit);
                message.TryAdd(Level1Fields.MarginSell, quote.SellDeposit);
                message.TryAdd(Level1Fields.HistoricalVolatility, quote.Volatility);
                message.TryAdd(Level1Fields.TheorPrice, quote.TheoreticalPrice);
                message.TryAdd(Level1Fields.Change, quote.Change);
                message.TryAdd(Level1Fields.Volume, (decimal?)quote.VolToday);
                message.TryAdd(Level1Fields.StepPrice, quote.PointCost);
                message.TryAdd(Level1Fields.OpenInterest, (decimal?)quote.OpenInterest);
                message.TryAdd(Level1Fields.TradesCount, quote.TradesCount);

                if (quote.Status != null)
                {
                    message.Add(Level1Fields.State, quote.Status.Value.FromTransaq());
                }


                // Transaq передает только изменения (например, передать только цену сделки, если объем при этом не изменился)

                message.TryAdd(Level1Fields.LastTradePrice, quote.LastTradePrice);
                message.TryAdd(Level1Fields.LastTradeVolume, (decimal?)quote.LastTradeVolume);

                if (quote.LastTradeTime != null)
                {
                    message.Add(Level1Fields.LastTradeTime, quote.LastTradeTime.Value.ApplyTimeZone(TimeHelper.Moscow));
                }

                message.TryAdd(Level1Fields.BestBidPrice, quote.BestBidPrice);
                message.TryAdd(Level1Fields.BestBidVolume, (decimal?)quote.BestBidVolume);

                message.TryAdd(Level1Fields.BestAskPrice, quote.BestAskPrice);
                message.TryAdd(Level1Fields.BestAskVolume, (decimal?)quote.BestAskVolume);

                SendOutMessage(message);
            }
        }
        private void OnProcessLevel1(string[] data)
        {
            var f = Wrapper.FieldsLevel1;

            foreach (var row in data)
            {
                var cols    = row.ToColumns();
                var paperNo = f.PaperNo.GetValue(cols);
                var secId   = new SecurityId {
                    Native = paperNo
                };

                var l1Msg = new Level1ChangeMessage
                {
                    SecurityId = secId,
                    ServerTime = (f.LastUpdateDate.GetValue(cols).Date + f.LastUpdateTime.GetValue(cols).TimeOfDay).ApplyTimeZone(TimeHelper.Moscow)
                };

                l1Msg.Add(Level1Fields.State, f.TradingStatus.GetValue(cols));

                l1Msg.TryAdd(Level1Fields.MarginBuy, f.GoBuy.GetValue(cols));
                l1Msg.TryAdd(Level1Fields.MarginSell, f.GoSell.GetValue(cols));

                l1Msg.TryAdd(Level1Fields.OpenInterest, (decimal)f.OpenPosQty.GetValue(cols));

                var minPrice = f.MinDeal.GetValue(cols);
                var maxPrice = f.MaxDeal.GetValue(cols);

                l1Msg.TryAdd(Level1Fields.OpenPrice, f.OpenPrice.GetValue(cols));
                l1Msg.TryAdd(Level1Fields.ClosePrice, f.ClosePrice.GetValue(cols));
                l1Msg.TryAdd(Level1Fields.HighPrice, maxPrice);
                l1Msg.TryAdd(Level1Fields.LowPrice, minPrice);

                l1Msg.TryAdd(Level1Fields.BestBidPrice, f.Buy.GetValue(cols));
                l1Msg.TryAdd(Level1Fields.BestBidVolume, (decimal)f.BuyQty.GetValue(cols));
                l1Msg.TryAdd(Level1Fields.BestAskPrice, f.Sell.GetValue(cols));
                l1Msg.TryAdd(Level1Fields.BestAskVolume, (decimal)f.SellQty.GetValue(cols));

                l1Msg.TryAdd(Level1Fields.MinPrice, minPrice);
                l1Msg.TryAdd(Level1Fields.MaxPrice, maxPrice);

                l1Msg.TryAdd(Level1Fields.Multiplier, (decimal)f.LotSize.GetValue(cols));

                l1Msg.TryAdd(Level1Fields.ImpliedVolatility, f.Volatility.GetValue(cols));
                l1Msg.TryAdd(Level1Fields.TheorPrice, f.TheorPrice.GetValue(cols));

                l1Msg.TryAdd(Level1Fields.LastTradePrice, f.LastPrice.GetValue(cols));
                l1Msg.TryAdd(Level1Fields.LastTradeVolume, (decimal)f.LastQty.GetValue(cols));

                l1Msg.TryAdd(Level1Fields.PriceStep, f.PriceStep.GetValue(cols));

                l1Msg.TryAdd(Level1Fields.BidsVolume, (decimal)f.BuySQty.GetValue(cols));
                l1Msg.TryAdd(Level1Fields.BidsCount, f.BuyCount.GetValue(cols));
                l1Msg.TryAdd(Level1Fields.AsksVolume, (decimal)f.SellSQty.GetValue(cols));
                l1Msg.TryAdd(Level1Fields.AsksCount, f.SellCount.GetValue(cols));

                SendOutMessage(l1Msg);
            }
        }
        private void OnProcessSecurities(long transactionId, string[] data)
        {
            var f              = Wrapper.FieldsSecurities;
            var secMessages    = new List <Tuple <int, SecurityMessage> >();
            var level1Messages = new List <Level1ChangeMessage>();

            foreach (var row in data)
            {
                var cols = row.ToColumns();

                var secType = f.ATCode.GetValue(cols);
                if (secType == null)
                {
                    continue;
                }

                var paperNo = f.PaperNo.GetValue(cols);
                var code    = f.PaperCode.GetValue(cols);
                var name    = f.AnsiName.GetValue(cols);
                var time    = f.ILastUpdate.GetValue(cols);

                _securityCodes[paperNo] = code;

                var secId = new SecurityId
                {
                    Native       = paperNo,
                    SecurityCode = code,
                    BoardCode    = this.GetBoardCode(f.PlaceCode.GetValue(cols))
                };

                var msg = new SecurityMessage
                {
                    SecurityId   = secId,
                    Name         = name,
                    ShortName    = name,
                    SecurityType = secType,
                    Multiplier   = f.LotSize.GetValue(cols),
                    PriceStep    = f.PriceStep.GetValue(cols),
                    //LocalTime = time,
                    Currency = f.CurrCode.GetValue(cols),
                    Strike   = f.Strike.GetValue(cols)
                };

                if (msg.SecurityType == SecurityTypes.Option || msg.SecurityType == SecurityTypes.Future)
                {
                    msg.ExpiryDate = f.MatDate.GetValue(cols).ApplyTimeZone(TimeHelper.Moscow);
                }

                if (msg.SecurityType == SecurityTypes.Option)
                {
                    msg.OptionType = f.ATCode.GetStrValue(cols).ATCodeToOptionType();
                    msg.Strike     = f.Strike.GetValue(cols);
                }

                secMessages.Add(Tuple.Create(f.BasePaperNo.GetValue(cols), msg));

                var l1Msg = new Level1ChangeMessage
                {
                    SecurityId = secId,
                    ServerTime = time.ApplyTimeZone(TimeHelper.Moscow)
                };

                l1Msg.TryAdd(Level1Fields.MarginBuy, f.GoBuy.GetValue(cols));
                l1Msg.TryAdd(Level1Fields.MarginSell, f.GoSell.GetValue(cols));
                l1Msg.TryAdd(Level1Fields.StepPrice, f.PriceStepCost.GetValue(cols));

                level1Messages.Add(l1Msg);
            }

            secMessages.Where(t => t.Item2.SecurityType == SecurityTypes.Option).ForEach(t =>
                                                                                         t.Item2.UnderlyingSecurityCode = _securityCodes.TryGetValue(t.Item1));

            secMessages.ForEach(t => SendOutMessage(t.Item2));
            level1Messages.ForEach(SendOutMessage);

            if (transactionId > 0)
            {
                SendOutMessage(new SecurityLookupResultMessage
                {
                    OriginalTransactionId = transactionId,
                });
            }
        }
Ejemplo n.º 9
0
        private void SessionOnStiQuoteUpdate(ref structSTIQuoteUpdate structQuoteUpdate)
        {
            var message = new Level1ChangeMessage
            {
                SecurityId = new SecurityId
                {
                    SecurityCode = structQuoteUpdate.bstrSymbol,
                    BoardCode    = structQuoteUpdate.bstrExch,
                },
                ServerTime = structQuoteUpdate.bstrUpdateTime.StrToTime(),
            };

            message.TryAdd(Level1Fields.BestAskPrice, (decimal)structQuoteUpdate.fAskPrice);
            message.TryAdd(Level1Fields.BestBidPrice, (decimal)structQuoteUpdate.fAskPrice);
            message.TryAdd(Level1Fields.BestAskVolume, (decimal)structQuoteUpdate.nAskSize);
            message.TryAdd(Level1Fields.BestBidVolume, (decimal)structQuoteUpdate.nBidSize);

            message.TryAdd(Level1Fields.OpenPrice, (decimal)structQuoteUpdate.fOpenPrice);
            message.TryAdd(Level1Fields.HighPrice, (decimal)structQuoteUpdate.fHighPrice);
            message.TryAdd(Level1Fields.LowPrice, (decimal)structQuoteUpdate.fLowPrice);

            message.TryAdd(Level1Fields.LastTradePrice, (decimal)structQuoteUpdate.fLastPrice);
            message.TryAdd(Level1Fields.LastTradeVolume, (decimal)structQuoteUpdate.nLastSize);

            message.TryAdd(Level1Fields.OpenInterest, (decimal)structQuoteUpdate.nOpenInterest);
            message.TryAdd(Level1Fields.Volume, (decimal)structQuoteUpdate.nCumVolume);
            message.TryAdd(Level1Fields.VWAP, (decimal)structQuoteUpdate.fVwap);

            SendOutMessage(message);

            if (_subscribedSecuritiesToTrade.Cache.Contains(structQuoteUpdate.bstrSymbol) && structQuoteUpdate.fLastPrice != 0)
            {
                var tickMsg = new ExecutionMessage
                {
                    ExecutionType = ExecutionTypes.Tick,
                    SecurityId    = new SecurityId {
                        SecurityCode = structQuoteUpdate.bstrSymbol, BoardCode = structQuoteUpdate.bstrExch
                    },
                    //TradeId = structQuoteSnap.,
                    TradePrice = (decimal)structQuoteUpdate.fLastPrice,
                    Volume     = structQuoteUpdate.nLastSize,
                    //OriginSide = action.ToSide(),
                    ServerTime = structQuoteUpdate.bstrUpdateTime.StrToTime()
                };

                SendOutMessage(tickMsg);
            }
        }
		private void OnSecurityChanged(string smartId, Tuple<decimal, decimal, DateTime> lastTrade, decimal open, decimal high, decimal low, decimal close, decimal volume, QuoteChange bid, QuoteChange ask,
			decimal openInt, Tuple<decimal, decimal> goBuySell, Tuple<decimal, decimal> goBase, Tuple<decimal, decimal> limits, int tradingStatus, Tuple<decimal, decimal> volatTheorPrice)
		{
			var secId = new SecurityId { Native = smartId };

			var message = new Level1ChangeMessage
			{
				SecurityId = secId,
				ExtensionInfo = new Dictionary<object, object>
				{
					{ SmartComExtensionInfoHelper.SecurityOptionsMargin, goBase.Item1 },
					{ SmartComExtensionInfoHelper.SecurityOptionsSyntheticMargin, goBase.Item2 }
				},
				ServerTime = CurrentTime.Convert(TimeHelper.Moscow),
			};

			message.TryAdd(Level1Fields.LastTradePrice, lastTrade.Item1);
			message.TryAdd(Level1Fields.LastTradeVolume, lastTrade.Item2);
			message.Add(Level1Fields.LastTradeTime, lastTrade.Item3.ApplyTimeZone(TimeHelper.Moscow));

			var prevQuotes = _bestQuotes.TryGetValue(secId);

			if (bid.Price != 0)
			{
				message.Add(Level1Fields.BestBidPrice, bid.Price);

				if (prevQuotes != null && prevQuotes.First != null && prevQuotes.First.Item1 == bid.Price)
					message.Add(Level1Fields.BestBidVolume, prevQuotes.First.Item2);
			}

			if (ask.Price != 0)
			{
				message.Add(Level1Fields.BestAskPrice, ask.Price);

				if (prevQuotes != null && prevQuotes.Second != null && prevQuotes.Second.Item1 == ask.Price)
					message.Add(Level1Fields.BestAskVolume, prevQuotes.Second.Item2);
			}

			message.TryAdd(Level1Fields.BidsVolume, bid.Volume);
			message.TryAdd(Level1Fields.AsksVolume, ask.Volume);

			message.TryAdd(Level1Fields.OpenPrice, open);
			message.TryAdd(Level1Fields.LowPrice, low);
			message.TryAdd(Level1Fields.HighPrice, high);
			message.TryAdd(Level1Fields.ClosePrice, close);

			message.TryAdd(Level1Fields.MinPrice, limits.Item1);
			message.TryAdd(Level1Fields.MaxPrice, limits.Item2);

			message.TryAdd(Level1Fields.MarginBuy, goBuySell.Item1);
			message.TryAdd(Level1Fields.MarginSell, goBuySell.Item2);
			message.TryAdd(Level1Fields.OpenInterest, openInt);

			message.TryAdd(Level1Fields.ImpliedVolatility, volatTheorPrice.Item1);
			message.TryAdd(Level1Fields.TheorPrice, volatTheorPrice.Item2);

			message.TryAdd(Level1Fields.Volume, volume);

			message.Add(Level1Fields.State, tradingStatus == 0 ? SecurityStates.Trading : SecurityStates.Stoped);

			SendOutMessage(message);
		}
		private void OnSecInfoResponse(SecInfoResponse response)
		{
			var securityId = new SecurityId
			{
				Native = response.SecId,
				SecurityCode = response.SecCode,
				BoardCode = _boards[response.Market],
			};

			SendOutMessage(new SecurityMessage
			{
				SecurityId = securityId,
				ExpiryDate = response.MatDate?.ApplyTimeZone(TimeHelper.Moscow),
				OptionType = response.PutCall?.FromTransaq(),
			});

			var l1Msg = new Level1ChangeMessage
			{
				SecurityId = new SecurityId { Native = response.SecId },
				ServerTime = CurrentTime.Convert(TimeHelper.Moscow),
			};

			l1Msg.TryAdd(Level1Fields.MinPrice, response.MinPrice);
			l1Msg.TryAdd(Level1Fields.MaxPrice, response.MaxPrice);

			var marginBuy = response.BuyDeposit;

			if (marginBuy == null || marginBuy == 0m)
				marginBuy = response.BgoBuy;

			var marginSell = response.SellDeposit;

			if (marginSell == null || marginSell == 0m)
				marginSell = response.BgoC;

			l1Msg.TryAdd(Level1Fields.MarginBuy, marginBuy);
			l1Msg.TryAdd(Level1Fields.MarginSell, marginSell);

			SendOutMessage(l1Msg);
		}
		private void OnQuotationsResponse(QuotationsResponse response)
		{
			foreach (var quote in response.Quotations)
			{
				var message = new Level1ChangeMessage
				{
					SecurityId = new SecurityId { Native = quote.SecId },
					ServerTime = CurrentTime.Convert(TimeHelper.Moscow),
				};

				message.TryAdd(Level1Fields.AccruedCouponIncome, quote.AccruedIntValue);
				message.TryAdd(Level1Fields.OpenPrice, quote.Open);
				message.TryAdd(Level1Fields.HighPrice, quote.High);
				message.TryAdd(Level1Fields.LowPrice, quote.Low);
				message.TryAdd(Level1Fields.ClosePrice, quote.ClosePrice);
				message.TryAdd(Level1Fields.BidsCount, quote.BidsCount);
				message.TryAdd(Level1Fields.BidsVolume, (decimal?)quote.BidsVolume);
				message.TryAdd(Level1Fields.AsksCount, quote.AsksCount);
				message.TryAdd(Level1Fields.AsksVolume, (decimal?)quote.AsksVolume);
				message.TryAdd(Level1Fields.HighBidPrice, quote.HighBid);
				message.TryAdd(Level1Fields.LowAskPrice, quote.LowAsk);
				message.TryAdd(Level1Fields.Yield, quote.Yield);
				message.TryAdd(Level1Fields.MarginBuy, quote.BuyDeposit);
				message.TryAdd(Level1Fields.MarginSell, quote.SellDeposit);
				message.TryAdd(Level1Fields.HistoricalVolatility, quote.Volatility);
				message.TryAdd(Level1Fields.TheorPrice, quote.TheoreticalPrice);
				message.TryAdd(Level1Fields.Change, quote.Change);
				message.TryAdd(Level1Fields.Volume, (decimal?)quote.VolToday);
				message.TryAdd(Level1Fields.StepPrice, quote.PointCost);
				message.TryAdd(Level1Fields.OpenInterest, (decimal?)quote.OpenInterest);
				message.TryAdd(Level1Fields.TradesCount, quote.TradesCount);

				if (quote.Status != null)
					message.Add(Level1Fields.State, quote.Status.Value.FromTransaq());

				
				// Transaq передает только изменения (например, передать только цену сделки, если объем при этом не изменился)

				message.TryAdd(Level1Fields.LastTradePrice, quote.LastTradePrice);
				message.TryAdd(Level1Fields.LastTradeVolume, (decimal?)quote.LastTradeVolume);

				if (quote.LastTradeTime != null)
					message.Add(Level1Fields.LastTradeTime, quote.LastTradeTime.Value.ToDto());

				message.TryAdd(Level1Fields.BestBidPrice, quote.BestBidPrice);
				message.TryAdd(Level1Fields.BestBidVolume, (decimal?)quote.BestBidVolume);

				message.TryAdd(Level1Fields.BestAskPrice, quote.BestAskPrice);
				message.TryAdd(Level1Fields.BestAskVolume, (decimal?)quote.BestAskVolume);

				SendOutMessage(message);
			}
		}
		private void OnProcessLevel1(string[] data)
		{
			var f = Wrapper.FieldsLevel1;

			foreach (var row in data)
			{
				var cols = row.ToColumns();
				var paperNo = f.PaperNo.GetValue(cols);
				var secId = new SecurityId { Native = paperNo };

				var l1Msg = new Level1ChangeMessage
				{
					SecurityId = secId,
					ServerTime = (f.LastUpdateDate.GetValue(cols).Date + f.LastUpdateTime.GetValue(cols).TimeOfDay).ApplyTimeZone(TimeHelper.Moscow)
				};

				l1Msg.Add(Level1Fields.State, f.TradingStatus.GetValue(cols));

				l1Msg.TryAdd(Level1Fields.MarginBuy, f.GoBuy.GetValue(cols));
				l1Msg.TryAdd(Level1Fields.MarginSell, f.GoSell.GetValue(cols));

				l1Msg.TryAdd(Level1Fields.OpenInterest, (decimal)f.OpenPosQty.GetValue(cols));

				var minPrice = f.MinDeal.GetValue(cols);
				var maxPrice = f.MaxDeal.GetValue(cols);

				l1Msg.TryAdd(Level1Fields.OpenPrice, f.OpenPrice.GetValue(cols));
				l1Msg.TryAdd(Level1Fields.ClosePrice, f.ClosePrice.GetValue(cols));
				l1Msg.TryAdd(Level1Fields.HighPrice, maxPrice);
				l1Msg.TryAdd(Level1Fields.LowPrice, minPrice);

				l1Msg.TryAdd(Level1Fields.BestBidPrice, f.Buy.GetValue(cols));
				l1Msg.TryAdd(Level1Fields.BestBidVolume, (decimal)f.BuyQty.GetValue(cols));
				l1Msg.TryAdd(Level1Fields.BestAskPrice, f.Sell.GetValue(cols));
				l1Msg.TryAdd(Level1Fields.BestAskVolume, (decimal)f.SellQty.GetValue(cols));

				l1Msg.TryAdd(Level1Fields.MinPrice, minPrice);
				l1Msg.TryAdd(Level1Fields.MaxPrice, maxPrice);

				l1Msg.TryAdd(Level1Fields.Multiplier, (decimal)f.LotSize.GetValue(cols));

				l1Msg.TryAdd(Level1Fields.ImpliedVolatility, f.Volatility.GetValue(cols));
				l1Msg.TryAdd(Level1Fields.TheorPrice, f.TheorPrice.GetValue(cols));

				l1Msg.TryAdd(Level1Fields.LastTradePrice, f.LastPrice.GetValue(cols));
				l1Msg.TryAdd(Level1Fields.LastTradeVolume, (decimal)f.LastQty.GetValue(cols));

				l1Msg.TryAdd(Level1Fields.PriceStep, f.PriceStep.GetValue(cols));

				l1Msg.TryAdd(Level1Fields.BidsVolume, (decimal)f.BuySQty.GetValue(cols));
				l1Msg.TryAdd(Level1Fields.BidsCount, f.BuyCount.GetValue(cols));
				l1Msg.TryAdd(Level1Fields.AsksVolume, (decimal)f.SellSQty.GetValue(cols));
				l1Msg.TryAdd(Level1Fields.AsksCount, f.SellCount.GetValue(cols));

				SendOutMessage(l1Msg);
			}
		}
		private void OnProcessSecurities(long transactionId, string[] data)
		{
			var f = Wrapper.FieldsSecurities;
			var secMessages = new List<Tuple<int, SecurityMessage>>();
			var level1Messages = new List<Level1ChangeMessage>();

			foreach (var row in data)
			{
				var cols = row.ToColumns();

				var secType = f.ATCode.GetValue(cols);
				if(secType == null)
					continue;

				var paperNo = f.PaperNo.GetValue(cols);
				var code = f.PaperCode.GetValue(cols);
				var name = f.AnsiName.GetValue(cols);
				var time = f.ILastUpdate.GetValue(cols);

				_securityCodes[paperNo] = code;

				var secId = new SecurityId
				{
					Native = paperNo,
					SecurityCode = code,
					BoardCode = this.GetBoardCode(f.PlaceCode.GetValue(cols))
				};

				var msg = new SecurityMessage
				{
					SecurityId = secId,
					Name = name,
					ShortName = name,
					SecurityType = secType,
					Multiplier = f.LotSize.GetValue(cols),
					PriceStep = f.PriceStep.GetValue(cols),
					//LocalTime = time,
					Currency = f.CurrCode.GetValue(cols),
					Strike = f.Strike.GetValue(cols)
				};

				if(msg.SecurityType == SecurityTypes.Option || msg.SecurityType == SecurityTypes.Future)
					msg.ExpiryDate = f.MatDate.GetValue(cols).ApplyTimeZone(TimeHelper.Moscow);

				if (msg.SecurityType == SecurityTypes.Option)
				{
					msg.OptionType = f.ATCode.GetStrValue(cols).ATCodeToOptionType();
					msg.Strike = f.Strike.GetValue(cols);
				}

				secMessages.Add(Tuple.Create(f.BasePaperNo.GetValue(cols), msg));

				var l1Msg = new Level1ChangeMessage
				{
					SecurityId = secId,
					ServerTime = time.ApplyTimeZone(TimeHelper.Moscow)
				};

				l1Msg.TryAdd(Level1Fields.MarginBuy, f.GoBuy.GetValue(cols));
				l1Msg.TryAdd(Level1Fields.MarginSell, f.GoSell.GetValue(cols));
				l1Msg.TryAdd(Level1Fields.StepPrice, f.PriceStepCost.GetValue(cols));

				level1Messages.Add(l1Msg);
			}

			secMessages.Where(t => t.Item2.SecurityType == SecurityTypes.Option).ForEach(t => 
				t.Item2.UnderlyingSecurityCode = _securityCodes.TryGetValue(t.Item1));

			secMessages.ForEach(t => SendOutMessage(t.Item2));
			level1Messages.ForEach(SendOutMessage);

			if (transactionId > 0)
			{
				SendOutMessage(new SecurityLookupResultMessage
				{
					OriginalTransactionId = transactionId,
				});
			}
		}
		private void FlushQuotes(SecurityId secId)
		{
			var quotes = _quotes.TryGetValue(secId);

			if (quotes == null)
				return;

			_quotes.Remove(secId);

			foreach (var pair in quotes.CachedPairs)
			{
				var message = new Level1ChangeMessage
				{
					SecurityId = secId,
					ServerTime = pair.Key
				};

				var bid = pair.Value.First;

				if (bid != null)
				{
					message
						.TryAdd(Level1Fields.BestBidPrice, bid.Price.ToDecimal())
						.TryAdd(Level1Fields.BestBidVolume, (decimal)bid.Size);
				}

				var ask = pair.Value.Second;

				if (ask != null)
				{
					message
						.TryAdd(Level1Fields.BestAskPrice, ask.Price.ToDecimal())
						.TryAdd(Level1Fields.BestAskVolume, (decimal)ask.Size);
				}

				SendOutMessage(message);
			}
		}
		private static Level1ChangeMessage ToLevel2(string value)
		{
			var parts = value.SplitByComma();

			var isBidValid = parts[10] == "T";
			var isAskValid = parts[11] == "T";

			if (!isBidValid && !isAskValid)
				return null;

			var date = parts[7].ToDateTime("yyyy-MM-dd");

			var l1Msg = new Level1ChangeMessage
			{
				SecurityId = new SecurityId
				{
					SecurityCode = parts[0],
					BoardCode = parts[1]
				},
			};

			// http://www.iqfeed.net/dev/api/docs/ConditionCodes.cfm
			l1Msg.Add(Level1Fields.IsSystem, parts[8] == "52");

			if (isAskValid)
			{
				l1Msg.ServerTime = date.Add(parts[9].To<TimeSpan>()).ApplyTimeZone(TimeHelper.Est);

				l1Msg
					.TryAdd(Level1Fields.BestAskPrice, parts[3].To<decimal>())
					.TryAdd(Level1Fields.BestAskVolume, parts[5].To<decimal>())
					.Add(Level1Fields.BestAskTime, l1Msg.ServerTime);
			}

			if (isBidValid)
			{
				var bidTime = date.Add(parts[6].To<TimeSpan>()).ApplyTimeZone(TimeHelper.Est);

				if (bidTime > l1Msg.ServerTime)
					l1Msg.ServerTime = bidTime;

				l1Msg
					.TryAdd(Level1Fields.BestBidPrice, parts[2].To<decimal>())
					.TryAdd(Level1Fields.BestBidVolume, parts[4].To<decimal>())
					.Add(Level1Fields.BestBidTime, bidTime);
			}

			return l1Msg;
		}
		private void SessionOnStiQuoteSnap(ref structSTIQuoteSnap structQuoteSnap)
		{
			var l1CngMsg = new Level1ChangeMessage
			{
				SecurityId = new SecurityId
				{
					SecurityCode = structQuoteSnap.bstrSymbol,
					BoardCode = structQuoteSnap.bstrExch
				},
				ServerTime = structQuoteSnap.bstrUpdateTime.StrToTime(),
			};

			if (structQuoteSnap.bAskPrice != 0)
				l1CngMsg.TryAdd(Level1Fields.BestAskPrice, (decimal)structQuoteSnap.fAskPrice);

			if (structQuoteSnap.bBidPrice != 0)
				l1CngMsg.TryAdd(Level1Fields.BestBidPrice, (decimal)structQuoteSnap.fBidPrice);

			l1CngMsg.TryAdd(Level1Fields.BestAskVolume, (decimal)structQuoteSnap.nAskSize);
			l1CngMsg.TryAdd(Level1Fields.BestBidVolume, (decimal)structQuoteSnap.nBidSize);

			if (structQuoteSnap.bOpenPrice != 0)
				l1CngMsg.TryAdd(Level1Fields.OpenPrice, (decimal)structQuoteSnap.fOpenPrice);

			if (structQuoteSnap.bHighPrice != 0)
				l1CngMsg.TryAdd(Level1Fields.HighPrice, (decimal)structQuoteSnap.fHighPrice);

			if (structQuoteSnap.bLowPrice != 0)
				l1CngMsg.TryAdd(Level1Fields.LowPrice, (decimal)structQuoteSnap.fLowPrice);

			if (structQuoteSnap.bLastPrice != 0)
				l1CngMsg.TryAdd(Level1Fields.LastTradePrice, (decimal)structQuoteSnap.fLastPrice);

			l1CngMsg.TryAdd(Level1Fields.LastTradeVolume, (decimal)structQuoteSnap.nLastSize);

			l1CngMsg.TryAdd(Level1Fields.OpenInterest, (decimal)structQuoteSnap.nOpenInterest);
			l1CngMsg.TryAdd(Level1Fields.Volume, (decimal)structQuoteSnap.nCumVolume);
			l1CngMsg.TryAdd(Level1Fields.VWAP, (decimal)structQuoteSnap.fVwap);

			l1CngMsg.TryAdd(Level1Fields.ClosePrice, (decimal)structQuoteSnap.fClosePrice); // öåíà çàêðûòèÿ ïðîøëîãî äíÿ.

			SendOutMessage(l1CngMsg);

			if (_subscribedSecuritiesToTrade.Cache.Contains(structQuoteSnap.bstrSymbol) && structQuoteSnap.fLastPrice != 0)
			{
				var tickMsg= new ExecutionMessage
				{
					ExecutionType = ExecutionTypes.Tick,
					SecurityId = new SecurityId{SecurityCode = structQuoteSnap.bstrSymbol,BoardCode = structQuoteSnap.bstrExch},
					//TradeId = structQuoteSnap.,
					TradePrice = (decimal)structQuoteSnap.fLastPrice,
					TradeVolume = structQuoteSnap.nLastSize,
					//OriginSide = action.ToSide(),
					ServerTime = structQuoteSnap.bstrUpdateTime.StrToTime()
				};

				SendOutMessage(tickMsg);
			}
		}
		private void SessionOnStiGreeksUpdate(ref structSTIGreeksUpdate structGreeksUpdate)
		{
			var message = new Level1ChangeMessage
			{
				SecurityId = new SecurityId
				{
					SecurityCode = structGreeksUpdate.bstrSymbol,
					BoardCode = AssociatedBoardCode,
				},
				ServerTime = CurrentTime,
			};

			message.TryAdd(Level1Fields.Delta, (decimal)structGreeksUpdate.fDelta);
			message.TryAdd(Level1Fields.Gamma, (decimal)structGreeksUpdate.fGamma);
			message.TryAdd(Level1Fields.Theta, (decimal)structGreeksUpdate.fTheta);
			message.TryAdd(Level1Fields.Vega, (decimal)structGreeksUpdate.fVega);
			message.TryAdd(Level1Fields.Rho, (decimal)structGreeksUpdate.fRho);
			message.TryAdd(Level1Fields.TheorPrice, (decimal)structGreeksUpdate.fTheoPrice);
			message.TryAdd(Level1Fields.ImpliedVolatility, (decimal)structGreeksUpdate.fImpVol);

			SendOutMessage(message);			
		}
        private void OnSecurityChanged(string smartId, Tuple <decimal?, decimal?, DateTime> lastTrade, decimal?open, decimal?high, decimal?low, decimal?close, decimal?volume, QuoteChange bid, QuoteChange ask,
                                       decimal?openInt, Tuple <decimal?, decimal?> goBuySell, Tuple <decimal?, decimal?> goBase, Tuple <decimal?, decimal?> limits, int tradingStatus, Tuple <decimal?, decimal?> volatTheorPrice)
        {
            var secId = new SecurityId {
                Native = smartId
            };

            var message = new Level1ChangeMessage
            {
                SecurityId    = secId,
                ExtensionInfo = new Dictionary <object, object>
                {
                    { SmartComExtensionInfoHelper.SecurityOptionsMargin, goBase.Item1 },
                    { SmartComExtensionInfoHelper.SecurityOptionsSyntheticMargin, goBase.Item2 }
                },
                ServerTime = CurrentTime.Convert(TimeHelper.Moscow),
            };

            message.TryAdd(Level1Fields.LastTradePrice, lastTrade.Item1);
            message.TryAdd(Level1Fields.LastTradeVolume, lastTrade.Item2);
            message.Add(Level1Fields.LastTradeTime, lastTrade.Item3.ApplyTimeZone(TimeHelper.Moscow));

            var prevQuotes = _bestQuotes.TryGetValue(secId);

            if (bid.Price != 0)
            {
                message.Add(Level1Fields.BestBidPrice, bid.Price);

                if (prevQuotes != null && prevQuotes.First != null && prevQuotes.First.Item1 == bid.Price)
                {
                    message.Add(Level1Fields.BestBidVolume, prevQuotes.First.Item2);
                }
            }

            if (ask.Price != 0)
            {
                message.Add(Level1Fields.BestAskPrice, ask.Price);

                if (prevQuotes != null && prevQuotes.Second != null && prevQuotes.Second.Item1 == ask.Price)
                {
                    message.Add(Level1Fields.BestAskVolume, prevQuotes.Second.Item2);
                }
            }

            message.TryAdd(Level1Fields.BidsVolume, bid.Volume);
            message.TryAdd(Level1Fields.AsksVolume, ask.Volume);

            message.TryAdd(Level1Fields.OpenPrice, open);
            message.TryAdd(Level1Fields.LowPrice, low);
            message.TryAdd(Level1Fields.HighPrice, high);
            message.TryAdd(Level1Fields.ClosePrice, close);

            message.TryAdd(Level1Fields.MinPrice, limits.Item1);
            message.TryAdd(Level1Fields.MaxPrice, limits.Item2);

            message.TryAdd(Level1Fields.MarginBuy, goBuySell.Item1);
            message.TryAdd(Level1Fields.MarginSell, goBuySell.Item2);
            message.TryAdd(Level1Fields.OpenInterest, openInt);

            message.TryAdd(Level1Fields.ImpliedVolatility, volatTheorPrice.Item1);
            message.TryAdd(Level1Fields.TheorPrice, volatTheorPrice.Item2);

            message.TryAdd(Level1Fields.Volume, volume);

            message.Add(Level1Fields.State, tradingStatus == 0 ? SecurityStates.Trading : SecurityStates.Stoped);

            SendOutMessage(message);
        }
        private void SessionOnStiQuoteSnap(ref structSTIQuoteSnap structQuoteSnap)
        {
            var l1CngMsg = new Level1ChangeMessage
            {
                SecurityId = new SecurityId
                {
                    SecurityCode = structQuoteSnap.bstrSymbol,
                    BoardCode    = structQuoteSnap.bstrExch
                },
                ServerTime = structQuoteSnap.bstrUpdateTime.StrToTime(),
            };

            if (structQuoteSnap.bAskPrice != 0)
            {
                l1CngMsg.TryAdd(Level1Fields.BestAskPrice, (decimal)structQuoteSnap.fAskPrice);
            }

            if (structQuoteSnap.bBidPrice != 0)
            {
                l1CngMsg.TryAdd(Level1Fields.BestBidPrice, (decimal)structQuoteSnap.fBidPrice);
            }

            l1CngMsg.TryAdd(Level1Fields.BestAskVolume, (decimal)structQuoteSnap.nAskSize);
            l1CngMsg.TryAdd(Level1Fields.BestBidVolume, (decimal)structQuoteSnap.nBidSize);

            if (structQuoteSnap.bOpenPrice != 0)
            {
                l1CngMsg.TryAdd(Level1Fields.OpenPrice, (decimal)structQuoteSnap.fOpenPrice);
            }

            if (structQuoteSnap.bHighPrice != 0)
            {
                l1CngMsg.TryAdd(Level1Fields.HighPrice, (decimal)structQuoteSnap.fHighPrice);
            }

            if (structQuoteSnap.bLowPrice != 0)
            {
                l1CngMsg.TryAdd(Level1Fields.LowPrice, (decimal)structQuoteSnap.fLowPrice);
            }

            if (structQuoteSnap.bLastPrice != 0)
            {
                l1CngMsg.TryAdd(Level1Fields.LastTradePrice, (decimal)structQuoteSnap.fLastPrice);
            }

            l1CngMsg.TryAdd(Level1Fields.LastTradeVolume, (decimal)structQuoteSnap.nLastSize);

            l1CngMsg.TryAdd(Level1Fields.OpenInterest, (decimal)structQuoteSnap.nOpenInterest);
            l1CngMsg.TryAdd(Level1Fields.Volume, (decimal)structQuoteSnap.nCumVolume);
            l1CngMsg.TryAdd(Level1Fields.VWAP, (decimal)structQuoteSnap.fVwap);

            l1CngMsg.TryAdd(Level1Fields.ClosePrice, (decimal)structQuoteSnap.fClosePrice);             // öåíà çàêðûòèÿ ïðîøëîãî äíÿ.

            SendOutMessage(l1CngMsg);

            if (_subscribedSecuritiesToTrade.Cache.Contains(structQuoteSnap.bstrSymbol) && structQuoteSnap.fLastPrice != 0)
            {
                var tickMsg = new ExecutionMessage
                {
                    ExecutionType = ExecutionTypes.Tick,
                    SecurityId    = new SecurityId {
                        SecurityCode = structQuoteSnap.bstrSymbol, BoardCode = structQuoteSnap.bstrExch
                    },
                    //TradeId = structQuoteSnap.,
                    TradePrice  = (decimal)structQuoteSnap.fLastPrice,
                    TradeVolume = structQuoteSnap.nLastSize,
                    //OriginSide = action.ToSide(),
                    ServerTime = structQuoteSnap.bstrUpdateTime.StrToTime()
                };

                SendOutMessage(tickMsg);
            }
        }