/// <summary>
		/// To convert quotes.
		/// </summary>
		/// <param name="message">Quotes.</param>
		/// <returns>Stream <see cref="ExecutionMessage"/>.</returns>
		public IEnumerable<ExecutionMessage> ToExecutionLog(QuoteChangeMessage message)
		{
			if (message == null)
				throw new ArgumentNullException(nameof(message));

			if (!_priceStepUpdated || !_volumeStepUpdated)
			{
				var quote = message.GetBestBid() ?? message.GetBestAsk();

				if (quote != null)
				{
					_securityDefinition.PriceStep = quote.Price.GetDecimalInfo().EffectiveScale.GetPriceStep();
					_securityDefinition.VolumeStep = quote.Volume.GetDecimalInfo().EffectiveScale.GetPriceStep();
					
					_priceStepUpdated = true;
					_volumeStepUpdated = true;
				}
			}

			_lastDepthDate = message.LocalTime.Date;

			// чтобы склонировать внутренние котировки
			//message = (QuoteChangeMessage)message.Clone();
			// TODO для ускорения идет shallow copy котировок
			var newBids = message.IsSorted ? message.Bids : message.Bids.OrderByDescending(q => q.Price);
			var newAsks = message.IsSorted ? message.Asks : message.Asks.OrderBy(q => q.Price);

			return ProcessQuoteChange(message.LocalTime, message.ServerTime, newBids.ToArray(), newAsks.ToArray());
		}
Esempio n. 2
0
		/// <summary>
		/// Initializes a new instance of the <see cref="TimeQuoteChange"/>.
		/// </summary>
		/// <param name="quote">The quote, from which changes will be copied.</param>
		/// <param name="message">The message with quotes.</param>
		public TimeQuoteChange(QuoteChange quote, QuoteChangeMessage message)
		{
			if (quote == null)
				throw new ArgumentNullException("quote");

			SecurityId = message.SecurityId;
			ServerTime = message.ServerTime;
			LocalTime = message.LocalTime;
			Price = quote.Price;
			Volume = quote.Volume;
			Side = quote.Side;
		}
Esempio n. 3
0
        /// <summary>
        /// Создать копию объекта.
        /// </summary>
        /// <returns>Копия.</returns>
        public override Message Clone()
        {
            var clone = new QuoteChangeMessage
            {
                LocalTime  = LocalTime,
                SecurityId = SecurityId,
                Bids       = Bids.Select(q => q.Clone()).ToArray(),
                Asks       = Asks.Select(q => q.Clone()).ToArray(),
                ServerTime = ServerTime,
                IsSorted   = IsSorted
            };

            this.CopyExtensionInfo(clone);

            return(clone);
        }
Esempio n. 4
0
        private void CreateAssociatedSecurityQuotes(QuoteChangeMessage quoteMsg)
        {
            if (!SessionHolder.CreateAssociatedSecurity)
            {
                return;
            }

            if (quoteMsg.SecurityId.IsDefault())
            {
                return;
            }

            var builder = _quoteChangeDepthBuilders
                          .SafeAdd(quoteMsg.SecurityId.SecurityCode, c => new QuoteChangeDepthBuilder(c, SessionHolder.AssociatedBoardCode));

            NewOutMessage.SafeInvoke(builder.Process(quoteMsg));
        }
Esempio n. 5
0
            public QuoteChangeMessage Process(QuoteChangeMessage message)
            {
                _feeds[message.SecurityId] = message;

                var bids = _feeds.SelectMany(f => f.Value.Bids).ToArray();
                var asks = _feeds.SelectMany(f => f.Value.Asks).ToArray();

                return(new QuoteChangeMessage
                {
                    SecurityId = new SecurityId
                    {
                        SecurityCode = _securityCode,
                        BoardCode = _boardCode
                    },
                    ServerTime = message.ServerTime,
                    LocalTime = message.LocalTime,
                    Bids = bids,
                    Asks = asks
                });
            }
		/// <summary>
		/// Создать <see cref="OrderLogMarketDepthBuilder"/>.
		/// </summary>
		/// <param name="depth">Стакан.</param>
		/// <param name="maxDepth">Максимальная глубина стакана. По-умолчанию равно <see cref="int.MaxValue"/>, что означает бесконечную глубину.</param>
		public OrderLogMarketDepthBuilder(QuoteChangeMessage depth, int maxDepth = int.MaxValue)
		{
			if (depth == null)
				throw new ArgumentNullException("depth");

			if (!depth.IsSorted)
				throw new ArgumentException(LocalizedStrings.Str942, "depth");

			_depth = depth;
			_maxDepth = maxDepth;

			foreach (var bid in depth.Bids)
				_bids.Add(bid.Price, bid);

			foreach (var ask in depth.Asks)
				_asks.Add(ask.Price, ask);

			_exchange = depth.SecurityId.BoardCode.IsEmpty()
				? ExchangeBoard.Forts
				: ExchangeBoard.GetBoard(depth.SecurityId.BoardCode) ?? ExchangeBoard.Forts;
		}
		private void SessionOnStil2Reply(ref Array arrayL2Update)
		{
			var asksUpdate = new List<QuoteChange>();
			var bidsUpdate = new List<QuoteChange>();

			foreach (structSTIL2Update structL2Update in arrayL2Update)
			{
				switch (structL2Update.bstrSide.ToSide())
				{
					case Sides.Buy:
					{
						bidsUpdate.Add(new QuoteChange(structL2Update.bstrSide.ToSide(), (decimal)structL2Update.fPrice, structL2Update.nQty) { BoardCode = structL2Update.bstrMaker });
						break;
					}
					case Sides.Sell:
					{
						asksUpdate.Add(new QuoteChange(structL2Update.bstrSide.ToSide(), (decimal)structL2Update.fPrice, structL2Update.nQty) { BoardCode = structL2Update.bstrMaker });
						break;
					}
				}
			}

			var quote = (structSTIL2Update)arrayL2Update.GetValue(0);

			_depths[quote.bstrSymbol] = Tuple.Create(asksUpdate, bidsUpdate);

			var message = new QuoteChangeMessage
			{
				SecurityId = new SecurityId
				{
					SecurityCode = quote.bstrSymbol,
					BoardCode = AssociatedBoardCode,
				},
				Asks = asksUpdate,
				Bids = bidsUpdate,
				ServerTime = quote.bstrTime.StrToTime(),
			};

			SendOutMessage(message);			
		}
		private void SessionOnStil2Update(ref structSTIL2Update structL2Update)
		{
			var depth = _depths[structL2Update.bstrSymbol];

			var quote = new QuoteChange(structL2Update.bstrSide.ToSide(), (decimal)structL2Update.fPrice, structL2Update.nQty);

			var quotes = quote.Side == Sides.Sell ? depth.Item1 : depth.Item2;

			switch (structL2Update.bstrAction)
			{
				case "A": // add
				{
					quotes.Add(quote);
					break;
				}
				case "C": // change
				{
					quotes.RemoveWhere(q => q.Price == quote.Price && q.BoardCode == quote.BoardCode);
					quotes.Add(quote);
					break;
				}
				case "D": // delete
				{
					quotes.RemoveWhere(q => q.Price == quote.Price && q.BoardCode == quote.BoardCode);
					break;
				}
			}

			var board = structL2Update.bstrMaker;

			if (board.IsEmpty())
				board = AssociatedBoardCode;

			var message = new QuoteChangeMessage
			{
				SecurityId = new SecurityId
				{
					SecurityCode = structL2Update.bstrSymbol,
					BoardCode = board,
				},
				Asks = depth.Item1.ToArray(),
				Bids = depth.Item2.ToArray(),
				ServerTime = structL2Update.bstrTime.StrToTime(),
			};

			SendOutMessage(message);			
		}
		/// <summary>
		/// Process message.
		/// </summary>
		/// <param name="message">Message.</param>
		/// <returns>The result of processing. If <see langword="null" /> is returned, then generator has no sufficient data to generate new message.</returns>
		protected override Message OnProcess(Message message)
		{
			if (_boardDefinition == null)
			{
				if (message.Type == MessageTypes.Board)
					_boardDefinition = (BoardMessage)message.Clone();
				
				return null;
			}

			DateTimeOffset time;

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

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

					if (value != null)
						_lastTradePrice = (decimal)value;

					value = l1Msg.Changes.TryGetValue(Level1Fields.BestBidPrice);

					if (value != null)
						_bestBidPrice = (decimal)value;

					value = l1Msg.Changes.TryGetValue(Level1Fields.BestAskPrice);

					if (value != null)
						_bestAskPrice = (decimal)value;

					time = l1Msg.ServerTime;

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

					switch (execMsg.ExecutionType)
					{
						case ExecutionTypes.Tick:
						{
							var tradePrice = execMsg.TradePrice;

							if (null == _prevTradePrice)
							{
								_prevTradePrice = tradePrice;
								_bestAskPrice = tradePrice;
								_bestBidPrice = tradePrice;
							}

							switch (execMsg.OriginSide)
							{
								case null:
								{
									if (tradePrice > _prevTradePrice)
									{
										_bestAskPrice = tradePrice;
										//BestBid = PrevTrade;
										_prevTradePrice = tradePrice;
									}
									else if (tradePrice < _prevTradePrice)
									{
										_bestBidPrice = tradePrice;
										//BestAsk = PrevTrade;
										_prevTradePrice = tradePrice;
									}

									break;
								}
								case Sides.Buy:
									_bestAskPrice = tradePrice;
									break;
								default:
									_bestBidPrice = tradePrice;
									break;
							}

							_lastTradePrice = tradePrice;
							_newTrades = true;

							break;
						}
						default:
							return null;
					}

					time = execMsg.ServerTime;

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

					time = timeMsg.ServerTime;

					break;
				}
				default:
					return null;
			}

			if (_currGenerations == 0 || _bestBidPrice == null || _bestAskPrice == null)
				return null;

			var isTradeTime = _boardDefinition.IsTradeTime(time);

			var canProcess = GenerateDepthOnEachTrade && _newTrades
				? isTradeTime
				: (IsTimeToGenerate(time) && isTradeTime);

			if (!canProcess)
				return null;

			_currGenerations = MaxGenerations;

			var depth = new QuoteChangeMessage
			{
				SecurityId = SecurityId,
				ServerTime = time,
				LocalTime = time.LocalDateTime,
			};

			if (_bestBidPrice == null || _bestAskPrice == null)
			{
				if (_lastTradePrice == null)
					throw new InvalidOperationException(LocalizedStrings.Str1142);

				_bestBidPrice = _bestAskPrice = _lastTradePrice;
			}

			if (_currGenerations == 0)
				throw new InvalidOperationException(LocalizedStrings.Str1143);

			var bidPrice = _bestBidPrice;
			var askPrice = _bestAskPrice;

			var minSpred = MinSpreadStepCount * SecurityDefinition.PriceStep;
			var maxStread = MaxSpreadStepCount * SecurityDefinition.PriceStep;

			if ((askPrice - bidPrice) < minSpred)
			{
				if (_bestBidPrice == _lastTradePrice) // up trend
					askPrice = bidPrice + minSpred;
				else
					bidPrice = askPrice - minSpred;
			}
			else if ((askPrice - bidPrice) > maxStread)
			{
				if (_bestBidPrice == _lastTradePrice) // down trend
					askPrice = bidPrice + maxStread;
				else
					bidPrice = askPrice - maxStread;
			}

			var bids = new List<QuoteChange>
			{
				new QuoteChange(Sides.Buy, bidPrice.Value, Volumes.Next())
			};

			var count = MaxBidsDepth - bids.Count;

			for (var i = 0; i < count; i++)
			{
				var quote = CreateQuote(bidPrice.Value, Sides.Buy);

				if (quote.Price <= 0)
					break;

				bids.Add(quote);
				bidPrice = quote.Price;
			}

			var asks = new List<QuoteChange>
			{
				new QuoteChange(Sides.Sell, askPrice.Value, Volumes.Next())
			};

			count = MaxAsksDepth - asks.Count;

			for (var i = 0; i < count; i++)
			{
				var quote = CreateQuote(askPrice.Value, Sides.Sell);

				if (quote.Price <= 0)
					break;

				asks.Add(quote);
				askPrice = quote.Price;
			}

			depth.Bids = bids;
			depth.Asks = asks;

			_newTrades = false;

			_currGenerations--;

			return depth;
		}
Esempio n. 10
0
        private void ConvertFile(string fileName, IStorageRegistry registry, StorageFormats format, ExchangeBoard board)
        {
            if (!_isStarted)
                return;

            var fileNameKey = format + "_" + fileName;

            if (_convertedFiles.Contains(fileNameKey))
                return;

            _logManager.Application.AddInfoLog("Конвертация файла {0}.", fileName);

            const int maxBufCount = 1000;

            var data = new Dictionary<Security, Tuple<List<QuoteChangeMessage>, List<ExecutionMessage>, List<Level1ChangeMessage>, List<ExecutionMessage>>>();

            using (var qr = QshReader.Open(fileName))
            {
                var currentDate = qr.CurrentDateTime;

                for (var i = 0; i < qr.StreamCount; i++)
                {
                    var stream = (ISecurityStream)qr[i];
                    var security = GetSecurity(stream.Security, board);
                    var priceStep = security.PriceStep ?? 1;
                    var securityId = security.ToSecurityId();
                    var lastTransactionId = 0L;

                    var secData = data.SafeAdd(security, key => Tuple.Create(new List<QuoteChangeMessage>(), new List<ExecutionMessage>(), new List<Level1ChangeMessage>(), new List<ExecutionMessage>()));

                    switch (stream.Type)
                    {
                        case StreamType.Stock:
                        {
                            ((IStockStream)stream).Handler += (key, quotes, spread) =>
                            {
                                var quotes2 = quotes.Select(q =>
                                {
                                    Sides side;

                                    switch (q.Type)
                                    {
                                        case QuoteType.Unknown:
                                        case QuoteType.Free:
                                        case QuoteType.Spread:
                                            throw new ArgumentException(q.Type.ToString());
                                        case QuoteType.Ask:
                                        case QuoteType.BestAsk:
                                            side = Sides.Sell;
                                            break;
                                        case QuoteType.Bid:
                                        case QuoteType.BestBid:
                                            side = Sides.Buy;
                                            break;
                                        default:
                                            throw new ArgumentOutOfRangeException();
                                    }

                                    return new QuoteChange(side, priceStep * q.Price, q.Volume);
                                }).ToArray();

                                var md = new QuoteChangeMessage
                                {
                                    SecurityId = securityId,
                                    ServerTime = currentDate.ApplyTimeZone(TimeHelper.Moscow),
                                    Bids = quotes2.Where(q => q.Side == Sides.Buy),
                                    Asks = quotes2.Where(q => q.Side == Sides.Sell),
                                };

                                //if (md.Verify())
                                //{
                                secData.Item1.Add(md);

                                if (secData.Item1.Count > maxBufCount)
                                {
                                    registry.GetQuoteMessageStorage(security).Save(secData.Item1);
                                    secData.Item1.Clear();
                                }
                                //}
                                //else
                                //	_logManager.Application.AddErrorLog("Стакан для {0} в момент {1} не прошел валидацию. Лучший бид {2}, Лучший офер {3}.", security, qr.CurrentDateTime, md.BestBid, md.BestAsk);
                            };
                            break;
                        }
                        case StreamType.Deals:
                        {
                            ((IDealsStream)stream).Handler += deal =>
                            {
                                secData.Item2.Add(new ExecutionMessage
                                {
                                    ExecutionType = ExecutionTypes.Tick,
                                    SecurityId = securityId,
                                    OpenInterest = deal.OI == 0 ? (long?)null : deal.OI,
                                    ServerTime = deal.DateTime.ApplyTimeZone(TimeHelper.Moscow),
                                    Volume = deal.Volume,
                                    TradeId = deal.Id == 0 ? (long?)null : deal.Id,
                                    TradePrice = (decimal)deal.Price,
                                    OriginSide =
                                        deal.Type == DealType.Buy
                                            ? Sides.Buy
                                            : (deal.Type == DealType.Sell ? Sides.Sell : (Sides?)null)
                                });

                                if (secData.Item2.Count > maxBufCount)
                                {
                                    registry.GetTickMessageStorage(security).Save(secData.Item2);
                                    secData.Item2.Clear();
                                }
                            };
                            break;
                        }
                        case StreamType.OrdLog:
                        {
                            ((IOrdLogStream)stream).Handler += (key, ol) =>
                            {
                                var currTransactionId = ol.DateTime.Ticks;

                                if (lastTransactionId < currTransactionId)
                                    lastTransactionId = currTransactionId;
                                else if (lastTransactionId >= currTransactionId)
                                    lastTransactionId++;

                                var msg = new ExecutionMessage
                                {
                                    ExecutionType = ExecutionTypes.OrderLog,
                                    SecurityId = securityId,
                                    OpenInterest = ol.OI == 0 ? (long?)null : ol.OI,
                                    OrderId = ol.OrderId,
                                    Price = priceStep * ol.Price,
                                    ServerTime = ol.DateTime.ApplyTimeZone(TimeHelper.Moscow),
                                    Volume = ol.Amount,
                                    Balance = ol.AmountRest,
                                    TradeId = ol.DealId == 0 ? (long?)null : ol.DealId,
                                    TradePrice = ol.DealPrice == 0 ? (decimal?)null : priceStep * ol.DealPrice,
                                    TransactionId = lastTransactionId
                                };

                                var status = 0;

                                if (ol.Flags.Contains(OrdLogFlags.Add))
                                {
                                    msg.OrderState = OrderStates.Active;
                                }
                                else if (ol.Flags.Contains(OrdLogFlags.Fill))
                                {
                                    msg.OrderState = OrderStates.Done;
                                }
                                else if (ol.Flags.Contains(OrdLogFlags.Canceled))
                                {
                                    msg.OrderState = OrderStates.Done;
                                    status |= 0x200000;
                                }
                                else if (ol.Flags.Contains(OrdLogFlags.CanceledGroup))
                                {
                                    msg.OrderState = OrderStates.Done;
                                    status |= 0x400000;
                                }
                                else if (ol.Flags.Contains(OrdLogFlags.Moved))
                                {
                                    status |= 0x100000;
                                }

                                if (ol.Flags.Contains(OrdLogFlags.Buy))
                                {
                                    msg.Side = Sides.Buy;
                                }
                                else if (ol.Flags.Contains(OrdLogFlags.Sell))
                                {
                                    msg.Side = Sides.Sell;
                                }

                                if (ol.Flags.Contains(OrdLogFlags.FillOrKill))
                                {
                                    msg.TimeInForce = TimeInForce.MatchOrCancel;
                                    status |= 0x00080000;
                                }

                                if (ol.Flags.Contains(OrdLogFlags.Quote))
                                {
                                    msg.TimeInForce = TimeInForce.PutInQueue;
                                    status |= 0x01;
                                }

                                if (ol.Flags.Contains(OrdLogFlags.Counter))
                                {
                                    status |= 0x02;
                                }

                                if (ol.Flags.Contains(OrdLogFlags.CrossTrade))
                                {
                                    status |= 0x20000000;
                                }

                                if (ol.Flags.Contains(OrdLogFlags.NonSystem))
                                {
                                    msg.IsSystem = false;
                                    status |= 0x04;
                                }

                                if (ol.Flags.Contains(OrdLogFlags.EndOfTransaction))
                                {
                                    status |= 0x1000;
                                }

                                msg.OrderStatus = (OrderStatus)status;

                                secData.Item4.Add(msg);

                                if (secData.Item4.Count > maxBufCount)
                                {
                                    registry.GetOrderLogMessageStorage(security).Save(secData.Item4);
                                    secData.Item4.Clear();
                                }
                            };
                            break;
                        }
                        case StreamType.AuxInfo:
                        {
                            ((IAuxInfoStream)stream).Handler += (key, info) =>
                            {
                                secData.Item3.Add(new Level1ChangeMessage
                                {
                                    SecurityId = securityId,
                                    ServerTime = info.DateTime.ApplyTimeZone(TimeHelper.Moscow),
                                }
                                .TryAdd(Level1Fields.LastTradePrice, priceStep * info.Price)
                                .TryAdd(Level1Fields.BidsVolume, (decimal)info.BidTotal)
                                .TryAdd(Level1Fields.AsksVolume, (decimal)info.AskTotal)
                                .TryAdd(Level1Fields.HighPrice, priceStep * info.HiLimit)
                                .TryAdd(Level1Fields.LowPrice, priceStep * info.LoLimit)
                                .TryAdd(Level1Fields.OpenInterest, (decimal)info.OI));

                                if (secData.Item3.Count > maxBufCount)
                                {
                                    registry.GetLevel1MessageStorage(security).Save(secData.Item3);
                                    secData.Item3.Clear();
                                }
                            };
                            break;
                        }
                        case StreamType.Orders:
                        case StreamType.Trades:
                        case StreamType.Messages:
                        case StreamType.None:
                        {
                            continue;
                        }
                        default:
                            throw new ArgumentOutOfRangeException("Неподдерживаемый тип потока {0}.".Put(stream.Type));
                    }
                }

                while (qr.CurrentDateTime != DateTime.MaxValue && _isStarted)
                    qr.Read(true);
            }

            if (!_isStarted)
                return;

            foreach (var pair in data)
            {
                if (pair.Value.Item1.Any())
                {
                    registry.GetQuoteMessageStorage(pair.Key, format: format).Save(pair.Value.Item1);
                }

                if (pair.Value.Item2.Any())
                {
                    registry.GetTickMessageStorage(pair.Key, format: format).Save(pair.Value.Item2);
                }

                if (pair.Value.Item3.Any())
                {
                    registry.GetLevel1MessageStorage(pair.Key, format: format).Save(pair.Value.Item3);
                }

                if (pair.Value.Item4.Any())
                {
                    registry.GetOrderLogMessageStorage(pair.Key, format: format).Save(pair.Value.Item4);
                }
            }

            File.AppendAllLines(_convertedFilesFile, new[] { fileNameKey });
            _convertedFiles.Add(fileNameKey);
        }
		/// <summary>
		/// To upfate the order book.
		/// </summary>
		/// <param name="message">Market depth.</param>
		public void UpdateDepth(QuoteChangeMessage message)
		{
			if (message == null)
				throw new ArgumentNullException(nameof(message));

			var clone = new QuoteChangeMessage
			{
				Bids = message.Bids,
				Asks = message.Asks,
				IsSorted = message.IsSorted,
			};

			lock (_lastDepthSync)
				_lastQuoteMsg = clone;
		}
Esempio n. 12
0
		/// <summary>
		/// To process the message, containing data on order book.
		/// </summary>
		/// <param name="quoteMsg">The message, containing data on order book.</param>
		public void ProcessQuotes(QuoteChangeMessage quoteMsg)
		{
			var ask = quoteMsg.GetBestAsk();
			AskPrice = ask != null ? ask.Price : 0;

			var bid = quoteMsg.GetBestBid();
			BidPrice = bid != null ? bid.Price : 0;

			_unrealizedPnL = null;
		}
Esempio n. 13
0
		/// <summary>
		/// Create a copy of <see cref="QuoteChangeMessage"/>.
		/// </summary>
		/// <returns>Copy.</returns>
		public override Message Clone()
		{
			var clone = new QuoteChangeMessage
			{
				LocalTime = LocalTime,
				SecurityId = SecurityId,
				Bids = Bids.Select(q => q.Clone()).ToArray(),
				Asks = Asks.Select(q => q.Clone()).ToArray(),
				ServerTime = ServerTime,
				IsSorted = IsSorted,
				Currency = Currency,
			};

			this.CopyExtensionInfo(clone);

			return clone;
		}
		private void SessionOnStil2Update(ref structSTIL2Update structL2Update)
		{
			var asksUpdate = _depths[structL2Update.bstrSymbol].Item1;
			var bidsUpdate = _depths[structL2Update.bstrSymbol].Item2;

			var quote = new QuoteChange(structL2Update.bstrSide.ToSide(), (decimal) structL2Update.fPrice, structL2Update.nQty) {BoardCode = structL2Update.bstrMaker};

			switch (structL2Update.bstrSide.ToSide())
			{
				case Sides.Buy:
				{
					switch (structL2Update.bstrAction)
					{
						case "A": // add
						{
							bidsUpdate.Add(quote);
							break;
						}
						case "C": // change
						{
							bidsUpdate.RemoveWhere(q => q.Price == quote.Price && q.BoardCode == quote.BoardCode);
							bidsUpdate.Add(quote);
							break;
						}
						case "D": // delete
						{
							bidsUpdate.RemoveWhere(q => q.Price == quote.Price && q.BoardCode == quote.BoardCode);
							break;
						}
					}

					break;
				}

				case Sides.Sell:
				{
					switch (structL2Update.bstrAction)
					{
						case "A": // add
						{
							asksUpdate.Add(quote);
							break;
						}
						case "C": // change
						{
							asksUpdate.RemoveWhere(q => q.Price == quote.Price && q.BoardCode == quote.BoardCode);
							asksUpdate.Add(quote);
							break;
						}
						case "D": // delete
						{
							asksUpdate.RemoveWhere(q => q.Price == quote.Price && q.BoardCode == quote.BoardCode);
							break;
						}
					}

					break;
				}
			}

			var message = new QuoteChangeMessage
			{
				SecurityId = new SecurityId
				{
					SecurityCode = structL2Update.bstrSymbol,
					BoardCode = "All",
				},
				Asks = asksUpdate,
				Bids = bidsUpdate,
				ServerTime = structL2Update.bstrTime.StrToTime(),
			};

			SendOutMessage(message);			
		}
Esempio n. 15
0
        QuoteChangeMessage IOrderLogMarketDepthBuilder.Update(ExecutionMessage item)
        {
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }

            if (item.ExecutionType != ExecutionTypes.OrderLog)
            {
                throw new ArgumentException(nameof(item));
            }

            if (item.OrderPrice == 0)
            {
                return(null);
            }

            _depth.ServerTime = item.ServerTime;
            _depth.LocalTime  = item.LocalTime;

            QuoteChange?changedQuote = null;

            var quotes = item.Side == Sides.Buy ? _bids : _asks;

            if (item.IsOrderLogRegistered())
            {
                if (item.OrderVolume != null)
                {
                    QuoteChange ProcessRegister <T>(T id, Dictionary <T, decimal> orders)
                    {
                        var quote = quotes.SafeAdd(item.OrderPrice, key => new QuoteChange(key, 0));

                        var volume = item.OrderVolume.Value;

                        if (orders.TryGetValue(id, out var prevVolume))
                        {
                            quote.Volume += (volume - prevVolume);
                            orders[id]    = volume;
                        }
                        else
                        {
                            quote.Volume += volume;
                            orders.Add(id, volume);
                        }

                        quotes[item.OrderPrice] = quote;
                        return(quote);
                    }

                    if (item.OrderId != null)
                    {
                        changedQuote = ProcessRegister(item.OrderId.Value, _ordersByNum);
                    }
                    else if (!item.OrderStringId.IsEmpty())
                    {
                        changedQuote = ProcessRegister(item.OrderStringId, _ordersByString);
                    }
                }
            }
            else if (item.IsOrderLogMatched())
            {
                var volume = item.TradeVolume ?? item.OrderVolume;

                if (volume != null)
                {
                    QuoteChange?ProcessMatched <T>(T id, Dictionary <T, decimal> orders)
                    {
                        if (orders.TryGetValue(id, out var prevVolume))
                        {
                            orders[id] = prevVolume - volume.Value;

                            if (quotes.TryGetValue(item.OrderPrice, out var quote))
                            {
                                quote.Volume -= volume.Value;

                                if (quote.Volume <= 0)
                                {
                                    quotes.Remove(item.OrderPrice);
                                }

                                quotes[item.OrderPrice] = quote;
                                return(quote);
                            }
                        }

                        return(null);
                    }

                    if (item.OrderId != null)
                    {
                        changedQuote = ProcessMatched(item.OrderId.Value, _ordersByNum);
                    }
                    else if (!item.OrderStringId.IsEmpty())
                    {
                        changedQuote = ProcessMatched(item.OrderStringId, _ordersByString);
                    }
                }
            }
            else if (item.IsOrderLogCanceled())
            {
                QuoteChange?ProcessCanceled <T>(T id, Dictionary <T, decimal> orders)
                {
                    if (orders.TryGetAndRemove(id, out var prevVolume))
                    {
                        if (quotes.TryGetValue(item.OrderPrice, out var quote))
                        {
                            quote.Volume -= prevVolume;

                            if (quote.Volume <= 0)
                            {
                                quotes.Remove(item.OrderPrice);
                            }

                            quotes[item.OrderPrice] = quote;
                            return(quote);
                        }
                    }

                    return(null);
                }

                if (item.OrderId != null)
                {
                    changedQuote = ProcessCanceled(item.OrderId.Value, _ordersByNum);
                }
                else if (!item.OrderStringId.IsEmpty())
                {
                    changedQuote = ProcessCanceled(item.OrderStringId, _ordersByString);
                }
            }

            if (changedQuote == null)
            {
                return(null);
            }

            var increment = new QuoteChangeMessage
            {
                ServerTime = item.ServerTime,
                LocalTime  = item.LocalTime,
                SecurityId = _depth.SecurityId,
                State      = QuoteChangeStates.Increment,
            };

            var q = changedQuote.Value;

            if (item.Side == Sides.Buy)
            {
                increment.Bids = new[] { q }
            }
            ;
            else
            {
                increment.Asks = new[] { q }
            };

            return(increment);
        }
    }
		private void SessionOnStil2Reply(ref Array arrayL2Update)
		{
			var asksUpdate = new List<QuoteChange>();
			var bidsUpdate = new List<QuoteChange>();

			foreach (structSTIL2Update structL2Update in arrayL2Update)
			{
				switch (structL2Update.bstrSide.ToSide())
				{
					case Sides.Buy:
					{
						bidsUpdate.Add(new QuoteChange(structL2Update.bstrSide.ToSide(), (decimal) structL2Update.fPrice, structL2Update.nQty) {BoardCode = structL2Update.bstrMaker});
						break;
					}
					case Sides.Sell:
					{
						asksUpdate.Add(new QuoteChange(structL2Update.bstrSide.ToSide(), (decimal)structL2Update.fPrice, structL2Update.nQty) { BoardCode = structL2Update.bstrMaker});
						break;
					}
				}
			}

			var quote = (structSTIL2Update)arrayL2Update.GetValue(0);

			if (_depths.ContainsKey(quote.bstrSymbol))
			{
				_depths.Remove(quote.bstrSymbol);
			}

			_depths.Add(quote.bstrSymbol, new Tuple<List<QuoteChange>, List<QuoteChange>>(asksUpdate, bidsUpdate));

			var message = new QuoteChangeMessage
			{
				SecurityId = new SecurityId
				{
					SecurityCode = quote.bstrSymbol,
					BoardCode = "All",
				},
				Asks = asksUpdate,
				Bids = bidsUpdate,
				ServerTime = quote.bstrTime.StrToTime(),
			};

			SendOutMessage(message);			
		}