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    = AssociatedBoardCode,
                },
                Asks       = asksUpdate,
                Bids       = bidsUpdate,
                ServerTime = quote.bstrTime.StrToTime(),
            };

            SendOutMessage(message);
        }
示例#2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="DepthCandleBuilderSourceValue"/>.
        /// </summary>
        /// <param name="message">Messages containing quotes.</param>
        /// <param name="type">Type of candle depth based data.</param>
        public QuoteCandleBuilderSourceValue(QuoteChangeMessage message, DepthCandleSourceTypes type)
        {
            QuoteChange = message;
            Type        = type;

            switch (Type)
            {
            case DepthCandleSourceTypes.BestBid:
            {
                var bid = message.GetBestBid();

                if (bid != null)
                {
                    _price  = bid.Price;
                    _volume = bid.Volume;
                }

                break;
            }

            case DepthCandleSourceTypes.BestAsk:
            {
                var ask = message.GetBestAsk();

                if (ask != null)
                {
                    _price  = ask.Price;
                    _volume = ask.Volume;
                }

                break;
            }


            case DepthCandleSourceTypes.Middle:
            {
                var bid = message.GetBestBid();
                var ask = message.GetBestAsk();

                if (bid != null && ask != null)
                {
                    _price = (ask.Price + bid.Price) / 2;
                    //_volume = pair.Bid.Volume;
                }

                break;
            }

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
示例#3
0
        /// <summary>
        /// Initializes a new instance of the <see cref="TimeQuoteChange"/>.
        /// </summary>
        /// <param name="side">Direction (buy or sell).</param>
        /// <param name="quote">The quote, from which changes will be copied.</param>
        /// <param name="message">The message with quotes.</param>
        public TimeQuoteChange(Sides side, QuoteChange quote, QuoteChangeMessage message)
        {
            if (message is null)
            {
                throw new ArgumentNullException(nameof(message));
            }

            SecurityId = message.SecurityId;
            ServerTime = message.ServerTime;
            LocalTime  = message.LocalTime;
            Quote      = quote;
            Side       = side;
        }
        public NullableTimeQuoteChange(QuoteChange quote, QuoteChangeMessage message)
        {
            if (quote == null)
            {
                throw new ArgumentNullException(nameof(quote));
            }

            ServerTime = message.ServerTime;
            LocalTime  = message.LocalTime;
            Price      = quote.Price;
            Volume     = quote.Volume;
            Side       = quote.Side;
        }
        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);
        }
示例#6
0
        /// <summary>
        /// Создать <see cref="TimeQuoteChange"/>.
        /// </summary>
        /// <param name="quote">Котировка, из которой будут скопированы изменения.</param>
        /// <param name="message">Сообщение с котировками.</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;
        }
        public NullableTimeQuoteChange(Sides side, QuoteChange quote, QuoteChangeMessage message)
        {
            if (quote == null)
            {
                throw new ArgumentNullException(nameof(quote));
            }

            ServerTime  = message.ServerTime;
            LocalTime   = message.LocalTime;
            Price       = quote.Price;
            Volume      = quote.Volume;
            Side        = side;
            OrdersCount = quote.OrdersCount;
            Condition   = quote.Condition;
        }
示例#8
0
        private static string QuotesToString(QuoteChangeMessage quotes)
        {
            var sb = new StringBuilder();

            foreach (var quote in quotes.Bids)
            {
                sb.Append($"Bid:{quote.Price}:{quote.Volume};");
            }

            foreach (var quote in quotes.Asks)
            {
                sb.Append($"Ask:{quote.Price}:{quote.Volume};");
            }

            return($"{quotes.ServerTime};{quotes.SecurityId.SecurityCode};{sb}");
        }
示例#9
0
        /// <summary>
        /// Обновить стакан.
        /// </summary>
        /// <param name="message">Стакан.</param>
        public void UpdateDepth(QuoteChangeMessage message)
        {
            if (message == null)
            {
                throw new ArgumentNullException("message");
            }

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

            lock (_lastDepthSync)
                _lastQuoteMsg = clone;
        }
            public QuoteChangeMessage Process(QuoteChangeMessage message)
            {
                if (message == null)
                {
                    throw new ArgumentNullException(nameof(message));
                }

                return(new QuoteChangeMessage
                {
                    SecurityId = message.SecurityId,
                    ServerTime = message.ServerTime,
                    LocalTime = message.LocalTime,
                    IsSorted = message.IsSorted,
                    IsByLevel1 = message.IsByLevel1,
                    IsFiltered = true,
                    Bids = Filter(message.Bids),
                    Asks = Filter(message.Asks),
                });
            }
		private void CreateAssociatedSecurityQuotes(QuoteChangeMessage quoteMsg)
		{
			if (!CreateAssociatedSecurity)
				return;

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

			if (IsAssociated(quoteMsg.SecurityId.BoardCode))
				return;

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

			quoteMsg = builder.Process(quoteMsg);

			var security = LookupSecurity(quoteMsg.SecurityId);
			ProcessQuotesMessage(security, quoteMsg, false);
		}
示例#12
0
        private static string QuotesToString(QuoteChangeMessage quotes)
        {
            var sb = new StringBuilder();

            foreach (var quote in quotes.Bids)
            {
                sb.Append(string.Format("Bid:{0}:{1};", quote.Price, quote.Volume));
            }
            foreach (var quote in quotes.Asks)
            {
                sb.Append(string.Format("Ask:{0}:{1};", quote.Price, quote.Volume));
            }

            return(string.Format("{0};{1};{2}",
                                 quotes.ServerTime,
                                 quotes.SecurityId.SecurityCode,
                                 sb
                                 ));
        }
            public QuoteChangeMessage Process(QuoteChangeMessage message)
            {
                if (message is null)
                {
                    throw new ArgumentNullException(nameof(message));
                }

                return(new QuoteChangeMessage
                {
                    SecurityId = message.SecurityId,
                    ServerTime = message.ServerTime,
                    LocalTime = message.LocalTime,
                    IsSorted = message.IsSorted,
                    BuildFrom = message.BuildFrom,
                    Currency = message.Currency,
                    IsFiltered = true,
                    Bids = Filter(Sides.Buy, message.Bids),
                    Asks = Filter(Sides.Sell, message.Asks),
                });
            }
            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
                });
            }
示例#15
0
        /// <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)
                {
                    if (!_priceStepUpdated)
                    {
                        _securityDefinition.PriceStep = quote.Price.GetDecimalInfo().EffectiveScale.GetPriceStep();
                        _priceStepUpdated             = true;
                    }

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

            _lastDepthDate = message.LocalTime.Date;

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

            return(ProcessQuoteChange(message.LocalTime, message.ServerTime, newBids.ToArray(), newAsks.ToArray()));
        }
示例#16
0
        /// <inheritdoc />
        protected override void OnInnerAdapterNewOutMessage(Message message)
        {
            switch (message.Type)
            {
            case MessageTypes.SubscriptionResponse:
            {
                var responseMsg = (SubscriptionResponseMessage)message;

                if (!_infos.TryGetValue(responseMsg.OriginalTransactionId, out var info))
                {
                    break;
                }

                if (responseMsg.Error == null)
                {
                    info.State = SubscriptionStates.Active;
                }
                else
                {
                    info.State = SubscriptionStates.Error;

                    _infos.Remove(responseMsg.OriginalTransactionId);
                    _infosBySecId.TryGetValue(info.Origin.SecurityId)?.Remove(responseMsg.OriginalTransactionId);
                }

                break;
            }

            case MessageTypes.SubscriptionFinished:
            {
                var finishMsg = (SubscriptionFinishedMessage)message;

                if (_infos.TryGetAndRemove(finishMsg.OriginalTransactionId, out var info))
                {
                    info.State = SubscriptionStates.Finished;
                    _infosBySecId.TryGetValue(info.Origin.SecurityId)?.Remove(finishMsg.OriginalTransactionId);
                }

                break;
            }

            case MessageTypes.SubscriptionOnline:
            {
                var onlineMsg = (SubscriptionOnlineMessage)message;

                if (_infos.TryGetValue(onlineMsg.OriginalTransactionId, out var info))
                {
                    info.State = SubscriptionStates.Online;
                }

                break;
            }

            case MessageTypes.QuoteChange:
            {
                if (_infos.Count == 0)
                {
                    break;
                }

                var quoteMsg = (QuoteChangeMessage)message;

                var ids = quoteMsg.GetSubscriptionIds();
                var set = new HashSet <long>(quoteMsg.GetSubscriptionIds());

                QuoteChangeMessage filtered = null;

                foreach (var id in ids)
                {
                    if (_infos.TryGetValue(id, out var info) && info.State.IsActive())
                    {
                        var newIds = _infosBySecId[info.Origin.SecurityId].Cache;

                        filtered = info.Process(quoteMsg);
                        filtered.SetSubscriptionIds(newIds);

                        set.RemoveRange(newIds);
                        break;
                    }
                }

                if (set.Count > 0)
                {
                    quoteMsg.SetSubscriptionIds(set.ToArray());
                }
                else
                {
                    // subscription for origin book was initialized only by filtered book
                    message = null;
                }

                if (filtered != null)
                {
                    base.OnInnerAdapterNewOutMessage(filtered);
                }

                break;
            }

            case MessageTypes.Execution:
            {
                if (_infosBySecId.Count == 0 || _infos.Count == 0)
                {
                    break;
                }

                var execMsg = (ExecutionMessage)message;

                if (
                    execMsg.ExecutionType != ExecutionTypes.Transaction ||
                    !execMsg.HasOrderInfo() ||
                    execMsg.OrderPrice == 0 ||                             // ignore market orders
                    execMsg.OriginalTransactionId == 0                     // ignore unknown orders
                    )
                {
                    break;
                }

                if (execMsg.OrderState == OrderStates.Active || execMsg.OrderState == OrderStates.Done)
                {
                    if (!_infosBySecId.TryGetValue(execMsg.SecurityId, out var set))
                    {
                        break;
                    }

                    foreach (var id in set.Cache)
                    {
                        _infos.TryGetValue(id)?.Process(execMsg);
                    }
                }

                break;
            }
            }

            if (message != null)
            {
                base.OnInnerAdapterNewOutMessage(message);
            }
        }
        /// <summary>
        /// Try create full book.
        /// </summary>
        /// <param name="change">Book change.</param>
        /// <param name="subscriptionId">Subscription.</param>
        /// <returns>Full book.</returns>
        public QuoteChangeMessage TryApply(QuoteChangeMessage change, long subscriptionId = default)
        {
            if (change is null)
            {
                throw new ArgumentNullException(nameof(change));
            }

            if (change.State is null)
            {
                throw new ArgumentException(nameof(change));
            }

            var currState = _state;
            var newState  = change.State.Value;

            void WriteWarning()
            {
                var postfix = string.Empty;

                if (subscriptionId != default)
                {
                    if (!_invalidSubscriptions.Add(subscriptionId))
                    {
                        return;
                    }

                    postfix = $" (sub={subscriptionId})";
                }

                this.AddWarningLog($"{currState}->{newState}{postfix}");
            }

            bool CheckSwitch()
            {
                switch (currState)
                {
                case _none:
                case QuoteChangeStates.SnapshotStarted:
                {
                    if (newState != QuoteChangeStates.SnapshotBuilding && newState != QuoteChangeStates.SnapshotComplete)
                    {
                        WriteWarning();
                        return(false);
                    }

                    break;
                }

                case QuoteChangeStates.SnapshotBuilding:
                {
                    if (newState != QuoteChangeStates.SnapshotBuilding && newState != QuoteChangeStates.SnapshotComplete)
                    {
                        WriteWarning();
                        return(false);
                    }

                    break;
                }

                case QuoteChangeStates.SnapshotComplete:
                case QuoteChangeStates.Increment:
                {
                    if (newState == QuoteChangeStates.SnapshotBuilding)
                    {
                        WriteWarning();
                        return(false);
                    }

                    break;
                }
                }

                return(true);
            }

            var resetState = newState == QuoteChangeStates.SnapshotStarted || newState == QuoteChangeStates.SnapshotComplete;

            if (currState != newState || resetState)
            {
                if (!CheckSwitch())
                {
                    return(null);
                }

                if (currState == _none || resetState)
                {
                    _bids.Clear();
                    _asks.Clear();

                    _bidsByPos.Clear();
                    _asksByPos.Clear();
                }

                _state = currState = newState;
            }
		private void ProcessQuotesMessage(Security security, QuoteChangeMessage message, bool fromLevel1)
		{
			if (MarketDepthChanged != null || MarketDepthsChanged != null)
			{
				var marketDepth = GetMarketDepth(security);

				message.ToMarketDepth(marketDepth, GetSecurity);

				if (_subscriptionManager.IsFilteredMarketDepthRegistered(security))
					GetFilteredMarketDepthInfo(security).Process(message);

				RaiseMarketDepthChanged(marketDepth);
			}
			else
			{
				lock (_marketDepths.SyncRoot)
				{
					var info = _marketDepths.SafeAdd(security, key => new MarketDepthInfo(EntityFactory.CreateMarketDepth(security)));

					info.First.LocalTime = message.LocalTime;
					info.First.LastChangeTime = message.ServerTime;

					info.Second = message.Bids;
					info.Third = message.Asks;
				}
			}

			var bestBid = message.GetBestBid();
			var bestAsk = message.GetBestAsk();

			if (!fromLevel1 && (bestBid != null || bestAsk != null))
			{
				var values = GetSecurityValues(security);
				var changes = new List<KeyValuePair<Level1Fields, object>>(4);

				lock (values.SyncRoot)
				{
					if (bestBid != null)
					{
						values[(int)Level1Fields.BestBidPrice] = bestBid.Price;
						changes.Add(new KeyValuePair<Level1Fields, object>(Level1Fields.BestBidPrice, bestBid.Price));

						if (bestBid.Volume != 0)
						{
							values[(int)Level1Fields.BestBidVolume] = bestBid.Volume;
							changes.Add(new KeyValuePair<Level1Fields, object>(Level1Fields.BestBidVolume, bestBid.Volume));
						}
					}

					if (bestAsk != null)
					{
						values[(int)Level1Fields.BestAskPrice] = bestAsk.Price;
						changes.Add(new KeyValuePair<Level1Fields, object>(Level1Fields.BestAskPrice, bestAsk.Price));

						if (bestAsk.Volume != 0)
						{
							values[(int)Level1Fields.BestAskVolume] = bestAsk.Volume;
							changes.Add(new KeyValuePair<Level1Fields, object>(Level1Fields.BestAskVolume, bestAsk.Volume));
						}
					}
				}

				RaiseValuesChanged(security, changes, message.ServerTime, message.LocalTime);
			}

			if (UpdateSecurityLastQuotes)
			{
				var updated = false;

				if (!fromLevel1 || bestBid != null)
				{
					updated = true;
					security.BestBid = bestBid == null ? null : new Quote(security, bestBid.Price, bestBid.Volume, Sides.Buy);
				}

				if (!fromLevel1 || bestAsk != null)
				{
					updated = true;
					security.BestAsk = bestAsk == null ? null : new Quote(security, bestAsk.Price, bestAsk.Volume, Sides.Sell);
				}

				if (updated)
				{
					security.LocalTime = message.LocalTime;
					security.LastChangeTime = message.ServerTime;

					RaiseSecurityChanged(security);

					// стаканы по ALL обновляют BestXXX по конкретным инструментам
					if (security.Board.Code == AssociatedBoardCode)
					{
						var changedSecurities = new Dictionary<Security, RefPair<bool, bool>>();

						foreach (var bid in message.Bids)
						{
							if (bid.BoardCode.IsEmpty())
								continue;

							var innerSecurity = GetSecurity(new SecurityId
							{
								SecurityCode = security.Code,
								BoardCode = bid.BoardCode
							});

							var info = changedSecurities.SafeAdd(innerSecurity);

							if (info.First)
								continue;

							info.First = true;

							innerSecurity.BestBid = new Quote(innerSecurity, bid.Price, bid.Volume, Sides.Buy);
							innerSecurity.LocalTime = message.LocalTime;
							innerSecurity.LastChangeTime = message.ServerTime;
						}

						foreach (var ask in message.Asks)
						{
							if (ask.BoardCode.IsEmpty())
								continue;

							var innerSecurity = GetSecurity(new SecurityId
							{
								SecurityCode = security.Code,
								BoardCode = ask.BoardCode
							});

							var info = changedSecurities.SafeAdd(innerSecurity);

							if (info.Second)
								continue;

							info.Second = true;

							innerSecurity.BestAsk = new Quote(innerSecurity, ask.Price, ask.Volume, Sides.Sell);
							innerSecurity.LocalTime = message.LocalTime;
							innerSecurity.LastChangeTime = message.ServerTime;
						}

						RaiseSecuritiesChanged(changedSecurities.Keys.ToArray());
					}
				}
			}

			if (CreateDepthFromLevel1)
				GetBuilder(message.SecurityId).HasDepth = true;

			CreateAssociatedSecurityQuotes(message);
		}
		private void ProcessQuotesMessage(QuoteChangeMessage message, bool fromLevel1)
		{
			var security = LookupSecurity(message.SecurityId);

			ProcessQuotesMessage(security, message, fromLevel1);
		}
示例#20
0
        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);
        }
示例#21
0
        /// <inheritdoc />
        protected override bool OnSendInMessage(Message message)
        {
            switch (message.Type)
            {
            case MessageTypes.Reset:
            {
                lock (_syncObject)
                    _infos.Clear();

                break;
            }

            case MessageTypes.MarketData:
            {
                var mdMsg = (MarketDataMessage)message;

                if (mdMsg.DataType != MarketDataTypes.MarketDepth)
                {
                    break;
                }

                var isFilteredMsg = mdMsg is FilteredMarketDepthMessage;
                var transId       = mdMsg.TransactionId;

                if (mdMsg.IsSubscribe)
                {
                    if (!isFilteredMsg)
                    {
                        break;
                    }

                    var data = (Tuple <QuoteChangeMessage, ExecutionMessage[]>)mdMsg.Arg;

                    QuoteChangeMessage filtered = null;

                    lock (_syncObject)
                    {
                        var info = _infos.SafeAdd(mdMsg.SecurityId, key => new FilteredMarketDepthInfo(transId, data.Item2));
                        info.Subscriptions.Add(transId);

                        if (info.Subscriptions.Count == 1)
                        {
                            var clone = new MarketDataMessage();
                            mdMsg.CopyTo(clone);
                            message = clone;

                            filtered = info.Process(data.Item1);
                        }
                    }

                    if (filtered == null)
                    {
                        RaiseNewOutMessage(new SubscriptionResponseMessage {
                                OriginalTransactionId = transId
                            });
                        return(true);
                    }
                    else
                    {
                        RaiseNewOutMessage(filtered);
                    }
                }
                else
                {
                    SubscriptionResponseMessage reply;

                    lock (_syncObject)
                    {
                        var info = _infos.FirstOrDefault(p => p.Value.Subscriptions.Contains(mdMsg.OriginalTransactionId)).Value;

                        if (info != null)
                        {
                            info.Subscriptions.Remove(mdMsg.OriginalTransactionId);

                            if (info.Subscriptions.Count > 0)
                            {
                                reply = new SubscriptionResponseMessage
                                {
                                    OriginalTransactionId = transId,
                                };
                            }
                            else
                            {
                                message = new MarketDataMessage
                                {
                                    IsSubscribe           = false,
                                    TransactionId         = transId,
                                    OriginalTransactionId = info.TransactionId,
                                };

                                break;
                            }
                        }
                        else
                        {
                            if (!isFilteredMsg)
                            {
                                break;
                            }

                            reply = transId.CreateSubscriptionResponse(new InvalidOperationException(LocalizedStrings.SubscriptionNonExist.Put(mdMsg.OriginalTransactionId)));
                        }
                    }

                    RaiseNewOutMessage(reply);
                    return(true);
                }

                break;
            }
            }

            return(base.OnSendInMessage(message));
        }
示例#22
0
        private void ConvertFile(string fileName, IStorageRegistry registry, StorageFormats format, ExchangeBoard board, string securityLike, Dictionary <SecurityId, IOrderLogMarketDepthBuilder> orderLog2OrderBookBuilders, int orderBookMaxDepth, TimeZoneInfo tz, TimeZoneInfo mz)
        {
            if (!_isStarted)
            {
                return;
            }

            var fileNameKey = format + "_" + fileName;

            if (_convertedFiles.Contains(fileNameKey))
            {
                return;
            }

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

            var securitiesStrings = securityLike.Split(",");

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

            DateTimeOffset ToLocalDto(DateTime dt) => dt.ApplyTimeZone(tz);
            DateTimeOffset ToServerDto(DateTime dt) => dt.ApplyTimeZone(mz);

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

                for (var i = 0; i < qr.StreamCount; i++)
                {
                    var stream            = (ISecurityStream)qr[i];
                    var securityId        = GetSecurityId(stream.Security, board.Code);
                    var priceStep         = (decimal)stream.Security.Step;
                    var lastTransactionId = 0L;
                    var builder           = orderLog2OrderBookBuilders?.SafeAdd(securityId, key => new PlazaOrderLogMarketDepthBuilder(key));

                    if (securitiesStrings.Length > 0)
                    {
                        var secCode = securityId.SecurityCode;

                        var streamContainsSecurityFromMask = securitiesStrings.Any(mask =>
                        {
                            var isEndMulti   = mask.EndsWith("*");
                            var isStartMulti = mask.StartsWith("*");

                            if (isStartMulti)
                            {
                                mask = mask.Substring(1);
                            }

                            if (isEndMulti)
                            {
                                mask = mask.Substring(0, mask.Length - 1);
                            }

                            if (isEndMulti)
                            {
                                if (isStartMulti)
                                {
                                    return(secCode.ContainsIgnoreCase(mask));
                                }
                                else
                                {
                                    return(secCode.StartsWith(mask, StringComparison.InvariantCultureIgnoreCase));
                                }
                            }
                            else if (isStartMulti)
                            {
                                return(secCode.EndsWith(mask, StringComparison.InvariantCultureIgnoreCase));
                            }
                            else
                            {
                                return(secCode.CompareIgnoreCase(mask));
                            }
                        });

                        if (!streamContainsSecurityFromMask)
                        {
                            continue;
                        }
                    }

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

                    switch (stream.Type)
                    {
                    case StreamType.Quotes:
                    {
                        ((IQuotesStream)stream).Handler += quotes =>
                        {
                            var bids = new List <QuoteChange>();
                            var asks = new List <QuoteChange>();

                            foreach (var q in quotes)
                            {
                                switch (q.Type)
                                {
                                //case QuoteType.Unknown:
                                //case QuoteType.Free:
                                //case QuoteType.Spread:
                                //	throw new ArgumentException(q.Type.ToString());
                                case QuoteType.Ask:
                                case QuoteType.BestAsk:
                                    asks.Add(new QuoteChange(priceStep * q.Price, q.Volume));
                                    break;

                                case QuoteType.Bid:
                                case QuoteType.BestBid:
                                    bids.Add(new QuoteChange(priceStep * q.Price, q.Volume));
                                    break;

                                default:
                                {
                                    continue;
                                    //throw new ArgumentException(q.Type.ToString());
                                }
                                }
                            }

                            var md = new QuoteChangeMessage
                            {
                                LocalTime  = ToLocalDto(reader.CurrentDateTime),
                                SecurityId = securityId,
                                ServerTime = ToLocalDto(reader.CurrentDateTime),
                                Bids       = bids.ToArray(),
                                Asks       = asks.ToArray(),
                            };

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

                            TryFlushData(registry, securityId, format, null, secData.Item1, reader);

                            //}
                            //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
                                {
                                    LocalTime     = ToLocalDto(reader.CurrentDateTime),
                                    HasTradeInfo  = true,
                                    ExecutionType = ExecutionTypes.Tick,
                                    SecurityId    = securityId,
                                    OpenInterest  = deal.OI == 0 ? (long?)null : deal.OI,
                                    ServerTime    = ToServerDto(deal.DateTime),
                                    TradeVolume   = deal.Volume,
                                    TradeId       = deal.Id == 0 ? (long?)null : deal.Id,
                                    TradePrice    = deal.Price * priceStep,
                                    OriginSide    =
                                        deal.Type == DealType.Buy
                                                                                        ? Sides.Buy
                                                                                        : (deal.Type == DealType.Sell ? Sides.Sell : (Sides?)null)
                                });

                            TryFlushData(registry, securityId, format, ExecutionTypes.Tick, secData.Item2, reader);
                        };
                        break;
                    }

                    case StreamType.OrdLog:
                    {
                        ((IOrdLogStream)stream).Handler += ol =>
                        {
                            var currTransactionId = ol.DateTime.Ticks;

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

                            var msg = new ExecutionMessage
                            {
                                LocalTime     = ToLocalDto(reader.CurrentDateTime),
                                ExecutionType = ExecutionTypes.OrderLog,
                                SecurityId    = securityId,
                                OpenInterest  = ol.OI == 0 ? (long?)null : ol.OI,
                                OrderId       = ol.OrderId,
                                OrderPrice    = priceStep * ol.Price,
                                ServerTime    = ToServerDto(ol.DateTime),
                                OrderVolume   = 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 = status;

                            if (builder == null)
                            {
                                secData.Item4.Add(msg);

                                TryFlushData(registry, securityId, format, ExecutionTypes.OrderLog, secData.Item4, reader);
                            }
                            else
                            {
                                //if (builder.Depth.Bids.Any() || builder.Depth.Asks.Any() || msg.ServerTime.TimeOfDay >= new TimeSpan(0, 18, 45, 00, 1))
                                {
                                    bool updated;

                                    try
                                    {
                                        updated = builder.Update(msg);
                                    }
                                    catch
                                    {
                                        updated = false;
                                    }

                                    if (updated)
                                    {
                                        secData.Item1.Add(new QuoteChangeMessage
                                            {
                                                SecurityId = securityId,
                                                ServerTime = builder.Depth.ServerTime,
                                                Bids       = builder.Depth.Bids.Take(orderBookMaxDepth).ToArray(),
                                                Asks       = builder.Depth.Asks.Take(orderBookMaxDepth).ToArray(),
                                                IsSorted   = builder.Depth.IsSorted,
                                                LocalTime  = builder.Depth.LocalTime,
                                            });

                                        TryFlushData(registry, securityId, format, null, secData.Item1, reader);
                                    }
                                }
                            }
                        };
                        break;
                    }

                    case StreamType.AuxInfo:
                    {
                        ((IAuxInfoStream)stream).Handler += info =>
                        {
                            var l1Msg = new Level1ChangeMessage
                            {
                                LocalTime  = ToLocalDto(reader.CurrentDateTime),
                                SecurityId = securityId,
                                ServerTime = ToLocalDto(reader.CurrentDateTime),
                            }
                            .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.StepPrice, (decimal)info.Rate)
                            .TryAdd(Level1Fields.OperatingMargin, (decimal)info.Deposit)
                            .TryAdd(Level1Fields.OpenInterest, (decimal)info.OI);

                            if (l1Msg.Changes.Count == 0)
                            {
                                return;
                            }

                            secData.Item3.Add(l1Msg);

                            TryFlushData(registry, securityId, format, null, secData.Item3, reader);
                        };
                        break;
                    }

                    case StreamType.OwnOrders:
                    case StreamType.OwnTrades:
                    case StreamType.Messages:
                    case StreamType.None:
                    {
                        continue;
                    }

                    default:
                        throw new ArgumentOutOfRangeException("Неподдерживаемый тип потока {0}.".Put(stream.Type));
                    }
                }

                if (data.Count > 0)
                {
                    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, registry.DefaultDrive, format).Save(pair.Value.Item1);
                }

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

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

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

            if (data.Count > 0)
            {
                //File.AppendAllLines(_convertedFilesFile, new[] { fileNameKey });
                _convertedFiles.Add(fileNameKey);
                _convertedPerTaskPoolFiles.Add(fileNameKey);
            }

            _logManager.Application.AddInfoLog("Завершена конвертация файла {0}.", fileName);
        }
示例#23
0
        /// <inheritdoc />
        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.TryGetDecimal(Level1Fields.LastTradePrice);

                if (value != null)
                {
                    _lastTradePrice = value.Value;
                }

                value = l1Msg.TryGetDecimal(Level1Fields.BestBidPrice);

                if (value != null)
                {
                    _bestBidPrice = value.Value;
                }

                value = l1Msg.TryGetDecimal(Level1Fields.BestAskPrice);

                if (value != null)
                {
                    _bestAskPrice = value.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,
            };

            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.ToArray();
            depth.Asks = asks.ToArray();

            _newTrades = false;

            _currGenerations--;

            return(depth);
        }
示例#24
0
        private QuoteChangeMessage ApplyNewState(BookInfo info, QuoteChangeMessage quoteMsg, QuoteChangeStates newState)
        {
            var currState = info.State;

            if (currState != newState)
            {
                switch (currState)
                {
                case _none:
                case QuoteChangeStates.SnapshotStarted:
                {
                    if (newState != QuoteChangeStates.SnapshotBuilding && newState != QuoteChangeStates.SnapshotComplete)
                    {
                        this.AddDebugLog($"{currState}->{newState}");
                        return(null);
                    }

                    info.Bids.Clear();
                    info.Asks.Clear();

                    break;
                }

                case QuoteChangeStates.SnapshotBuilding:
                {
                    if (newState != QuoteChangeStates.SnapshotComplete)
                    {
                        this.AddDebugLog($"{currState}->{newState}");
                        return(null);
                    }

                    break;
                }

                case QuoteChangeStates.SnapshotComplete:
                case QuoteChangeStates.Increment:
                {
                    if (newState == QuoteChangeStates.SnapshotBuilding)
                    {
                        this.AddDebugLog($"{currState}->{newState}");
                        return(null);
                    }

                    break;
                }

                default:
                    throw new ArgumentOutOfRangeException(currState.ToString());
                }

                info.State = currState = newState;
            }

            void Copy(IEnumerable <QuoteChange> from, QuotesDict to)
            {
                foreach (var quote in from)
                {
                    if (quote.Volume == 0)
                    {
                        to.Remove(quote.Price);
                    }
                    else
                    {
                        to[quote.Price] = quote.Volume;
                    }
                }
            }

            Copy(quoteMsg.Bids, info.Bids);
            Copy(quoteMsg.Asks, info.Asks);

            if (currState == QuoteChangeStates.SnapshotStarted || currState == QuoteChangeStates.SnapshotBuilding)
            {
                return(null);
            }

            return(new QuoteChangeMessage
            {
                SecurityId = quoteMsg.SecurityId,
                Bids = info.Bids.Select(p => new QuoteChange(Sides.Buy, p.Key, p.Value)).ToArray(),
                Asks = info.Asks.Select(p => new QuoteChange(Sides.Sell, p.Key, p.Value)).ToArray(),
                IsSorted = true,
                ServerTime = quoteMsg.ServerTime,
                OriginalTransactionId = quoteMsg.OriginalTransactionId,
            });
        }
示例#25
0
        /// <inheritdoc />
        protected override void OnInnerAdapterNewOutMessage(Message message)
        {
            switch (message.Type)
            {
            case MessageTypes.SubscriptionResponse:
            {
                var responseMsg = (SubscriptionResponseMessage)message;
                var id          = responseMsg.OriginalTransactionId;

                if (!responseMsg.IsOk())
                {
                    if (TryRemoveSubscription(id, out var info))
                    {
                        lock (info.Lock)
                            info.State = info.State.ChangeSubscriptionState(SubscriptionStates.Error, id, this);
                    }
                }
                else
                {
                    if (_subscriptionIds.TryGetValue(id, out var info))
                    {
                        lock (info.Lock)
                            info.State = info.State.ChangeSubscriptionState(SubscriptionStates.Active, id, this);
                    }
                }

                break;
            }

            case MessageTypes.SubscriptionFinished:
            {
                var id = ((SubscriptionFinishedMessage)message).OriginalTransactionId;

                if (TryRemoveSubscription(id, out var info))
                {
                    lock (info.Lock)
                        info.State = info.State.ChangeSubscriptionState(SubscriptionStates.Finished, id, this);
                }

                break;
            }

            case MessageTypes.SubscriptionOnline:
            {
                var onlineMsg = (SubscriptionOnlineMessage)message;
                var id        = onlineMsg.OriginalTransactionId;

                QuoteChangeMessage snapshot = null;

                if (_subscriptionIds.TryGetValue(id, out var info))
                {
                    lock (info.Lock)
                    {
                        info.State = info.State.ChangeSubscriptionState(SubscriptionStates.Online, id, this);

                        if (!info.IsTicks)
                        {
                            snapshot = info.Builder.Snapshot?.TypedClone();
                        }
                    }
                }

                if (snapshot != null)
                {
                    snapshot.SetSubscriptionIds(subscriptionId: id);
                    base.OnInnerAdapterNewOutMessage(snapshot);
                }

                break;
            }

            case MessageTypes.Execution:
            {
                if (_subscriptionIds.Count == 0)
                {
                    break;
                }

                var execMsg = (ExecutionMessage)message;

                if (execMsg.ExecutionType == ExecutionTypes.OrderLog && execMsg.IsSystem != false)
                {
                    message = ProcessBuilders(execMsg);
                }

                break;
            }
            }

            if (message != null)
            {
                base.OnInnerAdapterNewOutMessage(message);
            }
        }
示例#26
0
        private static string QuotesToString(QuoteChangeMessage quotes)
        {
            var sb = new StringBuilder();

            foreach (var quote in quotes.Bids)
                sb.Append($"Bid:{quote.Price}:{quote.Volume};");

            foreach (var quote in quotes.Asks)
                sb.Append($"Ask:{quote.Price}:{quote.Volume};");

            return $"{quotes.ServerTime};{quotes.SecurityId.SecurityCode};{sb}";
        }
示例#27
0
        private static string QuotesToString(QuoteChangeMessage quotes)
        {
            var sb = new StringBuilder();
            foreach (var quote in quotes.Bids)
                sb.Append(string.Format("Bid:{0}:{1};", quote.Price, quote.Volume));
            foreach (var quote in quotes.Asks)
                sb.Append(string.Format("Ask:{0}:{1};", quote.Price, quote.Volume));

            return string.Format("{0};{1};{2}",
                quotes.ServerTime,
                quotes.SecurityId.SecurityCode,
                sb
                );
        }
示例#28
0
        private void ConvertFile(string fileName, IStorageRegistry registry, StorageFormats format, ExchangeBoard board, string securityLike)
        {
            if (!_isStarted)
            {
                return;
            }

            var fileNameKey = format + "_" + fileName;

            if (_convertedFiles.Contains(fileNameKey))
            {
                return;
            }

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

            var isExact = !securityLike.EndsWith("*");

            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;

                    if (!securityLike.IsEmpty() &&
                        (isExact
                                                        ? !securityId.SecurityCode.CompareIgnoreCase(securityLike)
                                                        : !securityId.SecurityCode.ContainsIgnoreCase(securityLike)))
                    {
                        continue;
                    }

                    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, format: format).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, format: format).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,
                                OrderPrice    = 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, format: format).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, format: format).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));
                    }
                }

                if (data.Count > 0)
                {
                    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);
                }
            }

            if (data.Count > 0)
            {
                File.AppendAllLines(_convertedFilesFile, new[] { fileNameKey });
                _convertedFiles.Add(fileNameKey);
            }
        }
示例#29
0
        private QuoteChangeMessage ApplyNewState(BookInfo info, QuoteChangeMessage quoteMsg, QuoteChangeStates newState)
        {
            var currState = info.State;

            void CheckSwitch()
            {
                switch (currState)
                {
                case _none:
                case QuoteChangeStates.SnapshotStarted:
                {
                    if (newState != QuoteChangeStates.SnapshotBuilding && newState != QuoteChangeStates.SnapshotComplete)
                    {
                        this.AddDebugLog($"{currState}->{newState}");
                    }

                    break;
                }

                case QuoteChangeStates.SnapshotBuilding:
                {
                    if (newState != QuoteChangeStates.SnapshotBuilding && newState != QuoteChangeStates.SnapshotComplete)
                    {
                        this.AddDebugLog($"{currState}->{newState}");
                    }

                    break;
                }

                case QuoteChangeStates.SnapshotComplete:
                case QuoteChangeStates.Increment:
                {
                    if (newState == QuoteChangeStates.SnapshotBuilding)
                    {
                        this.AddDebugLog($"{currState}->{newState}");
                    }

                    break;
                }
                }
            }

            if (currState != newState)
            {
                CheckSwitch();

                if (newState == QuoteChangeStates.SnapshotStarted)
                {
                    info.Bids.Clear();
                    info.Asks.Clear();
                }

                switch (currState)
                {
                case _none:
                {
                    info.Bids.Clear();
                    info.Asks.Clear();

                    break;
                }

                case QuoteChangeStates.SnapshotStarted:
                    break;

                case QuoteChangeStates.SnapshotBuilding:
                    break;

                case QuoteChangeStates.SnapshotComplete:
                {
                    if (newState == QuoteChangeStates.SnapshotComplete)
                    {
                        info.Bids.Clear();
                        info.Asks.Clear();
                    }

                    break;
                }

                case QuoteChangeStates.Increment:
                    break;

                default:
                    throw new ArgumentOutOfRangeException(currState.ToString());
                }

                info.State = currState = newState;
            }

            void Apply(IEnumerable <QuoteChange> from, QuotesDict to)
            {
                foreach (var quote in from)
                {
                    if (quote.Volume == 0)
                    {
                        to.Remove(quote.Price);
                    }
                    else
                    {
                        to[quote.Price] = Tuple.Create(quote.Volume, quote.OrdersCount, quote.Condition);
                    }
                }
            }

            void ApplyByPos(IEnumerable <QuoteChange> from, QuotesByPosList to)
            {
                foreach (var quote in from)
                {
                    var startPos = quote.StartPosition.Value;

                    switch (quote.Action)
                    {
                    case QuoteChangeActions.New:
                    {
                        var tuple = Tuple.Create(quote.Price, quote.Volume, quote.OrdersCount, quote.Condition);

                        if (startPos > to.Count)
                        {
                            throw new InvalidOperationException($"Pos={startPos}>Count={to.Count}");
                        }
                        else if (startPos == to.Count)
                        {
                            to.Add(tuple);
                        }
                        else
                        {
                            to.Insert(startPos, tuple);
                        }

                        break;
                    }

                    case QuoteChangeActions.Update:
                    {
                        to[startPos] = Tuple.Create(quote.Price, quote.Volume, quote.OrdersCount, quote.Condition);
                        break;
                    }

                    case QuoteChangeActions.Delete:
                    {
                        if (quote.EndPosition == null)
                        {
                            to.RemoveAt(startPos);
                        }
                        else
                        {
                            to.RemoveRange(startPos, (quote.EndPosition.Value - startPos) + 1);
                        }

                        break;
                    }

                    default:
                        throw new ArgumentOutOfRangeException(nameof(from), quote.Action, LocalizedStrings.Str1219);
                    }
                }
            }

            if (quoteMsg.HasPositions)
            {
                ApplyByPos(quoteMsg.Bids, info.BidsByPos);
                ApplyByPos(quoteMsg.Asks, info.AsksByPos);
            }
            else
            {
                Apply(quoteMsg.Bids, info.Bids);
                Apply(quoteMsg.Asks, info.Asks);
            }

            if (currState == QuoteChangeStates.SnapshotStarted || currState == QuoteChangeStates.SnapshotBuilding)
            {
                return(null);
            }

            IEnumerable <QuoteChange> bids;
            IEnumerable <QuoteChange> asks;

            if (quoteMsg.HasPositions)
            {
                bids = info.BidsByPos.Select(p => new QuoteChange(p.Item1, p.Item2, p.Item3, p.Item4));
                asks = info.AsksByPos.Select(p => new QuoteChange(p.Item1, p.Item2, p.Item3, p.Item4));
            }
            else
            {
                bids = info.Bids.Select(p => new QuoteChange(p.Key, p.Value.Item1, p.Value.Item2, p.Value.Item3));
                asks = info.Asks.Select(p => new QuoteChange(p.Key, p.Value.Item1, p.Value.Item2, p.Value.Item3));
            }

            return(new QuoteChangeMessage
            {
                SecurityId = quoteMsg.SecurityId,
                Bids = bids.ToArray(),
                Asks = asks.ToArray(),
                IsSorted = true,
                ServerTime = quoteMsg.ServerTime,
                OriginalTransactionId = quoteMsg.OriginalTransactionId,
            });
        }
示例#30
0
        /// <summary>
        /// Try create full book.
        /// </summary>
        /// <param name="change">Book change.</param>
        /// <returns>Full book.</returns>
        public QuoteChangeMessage TryApply(QuoteChangeMessage change)
        {
            if (change is null)
            {
                throw new ArgumentNullException(nameof(change));
            }

            if (change.State is null)
            {
                throw new ArgumentException(nameof(change));
            }

            var currState = _state;
            var newState  = change.State.Value;

            bool CheckSwitch()
            {
                switch (currState)
                {
                case _none:
                case QuoteChangeStates.SnapshotStarted:
                {
                    if (newState != QuoteChangeStates.SnapshotBuilding && newState != QuoteChangeStates.SnapshotComplete)
                    {
                        this.AddDebugLog($"{currState}->{newState}");
                        return(false);
                    }

                    break;
                }

                case QuoteChangeStates.SnapshotBuilding:
                {
                    if (newState != QuoteChangeStates.SnapshotBuilding && newState != QuoteChangeStates.SnapshotComplete)
                    {
                        this.AddDebugLog($"{currState}->{newState}");
                        return(false);
                    }

                    break;
                }

                case QuoteChangeStates.SnapshotComplete:
                case QuoteChangeStates.Increment:
                {
                    if (newState == QuoteChangeStates.SnapshotBuilding)
                    {
                        this.AddDebugLog($"{currState}->{newState}");
                        return(false);
                    }

                    break;
                }
                }

                return(true);
            }

            var resetState = newState == QuoteChangeStates.SnapshotStarted || newState == QuoteChangeStates.SnapshotComplete;

            if (currState != newState || resetState)
            {
                if (!CheckSwitch())
                {
                    return(null);
                }

                if (currState == _none || resetState)
                {
                    _bids.Clear();
                    _asks.Clear();

                    _bidsByPos.Clear();
                    _asksByPos.Clear();
                }

                _state = currState = newState;
            }
示例#31
0
        /// <summary>
        /// Try create full book.
        /// </summary>
        /// <param name="change">Book change.</param>
        /// <returns>Full book.</returns>
        public QuoteChangeMessage TryApply(QuoteChangeMessage change)
        {
            if (change is null)
            {
                throw new ArgumentNullException(nameof(change));
            }

            if (change.State == null)
            {
                throw new ArgumentException(nameof(change));
            }

            var currState = _state;
            var newState  = change.State.Value;

            void CheckSwitch()
            {
                switch (currState)
                {
                case _none:
                case QuoteChangeStates.SnapshotStarted:
                {
                    if (newState != QuoteChangeStates.SnapshotBuilding && newState != QuoteChangeStates.SnapshotComplete)
                    {
                        _logs.AddDebugLog($"{currState}->{newState}");
                    }

                    break;
                }

                case QuoteChangeStates.SnapshotBuilding:
                {
                    if (newState != QuoteChangeStates.SnapshotBuilding && newState != QuoteChangeStates.SnapshotComplete)
                    {
                        _logs.AddDebugLog($"{currState}->{newState}");
                    }

                    break;
                }

                case QuoteChangeStates.SnapshotComplete:
                case QuoteChangeStates.Increment:
                {
                    if (newState == QuoteChangeStates.SnapshotBuilding)
                    {
                        _logs.AddDebugLog($"{currState}->{newState}");
                    }

                    break;
                }
                }
            }

            if (currState != newState || newState == QuoteChangeStates.SnapshotComplete)
            {
                CheckSwitch();

                if (newState == QuoteChangeStates.SnapshotStarted)
                {
                    _bids.Clear();
                    _asks.Clear();
                }

                switch (currState)
                {
                case _none:
                {
                    _bids.Clear();
                    _asks.Clear();

                    break;
                }

                case QuoteChangeStates.SnapshotStarted:
                    break;

                case QuoteChangeStates.SnapshotBuilding:
                    break;

                case QuoteChangeStates.SnapshotComplete:
                {
                    if (newState == QuoteChangeStates.SnapshotComplete)
                    {
                        _bids.Clear();
                        _asks.Clear();
                    }

                    break;
                }

                case QuoteChangeStates.Increment:
                    break;

                default:
                    throw new ArgumentOutOfRangeException(currState.ToString());
                }

                _state = currState = newState;
            }

            void Apply(IEnumerable <QuoteChange> from, SortedList <decimal, QuoteChange> to)
            {
                foreach (var quote in from)
                {
                    if (quote.Volume == 0)
                    {
                        to.Remove(quote.Price);
                    }
                    else
                    {
                        to[quote.Price] = quote;
                    }
                }
            }

            void ApplyByPos(IEnumerable <QuoteChange> from, List <QuoteChange> to)
            {
                foreach (var quote in from)
                {
                    var startPos = quote.StartPosition.Value;

                    switch (quote.Action)
                    {
                    case QuoteChangeActions.New:
                    {
                        var tuple = new QuoteChange(quote.Price, quote.Volume, quote.OrdersCount, quote.Condition);

                        if (startPos > to.Count)
                        {
                            throw new InvalidOperationException($"Pos={startPos}>Count={to.Count}");
                        }
                        else if (startPos == to.Count)
                        {
                            to.Add(tuple);
                        }
                        else
                        {
                            to.Insert(startPos, tuple);
                        }

                        break;
                    }

                    case QuoteChangeActions.Update:
                    {
                        to[startPos] = new QuoteChange(quote.Price, quote.Volume, quote.OrdersCount, quote.Condition);
                        break;
                    }

                    case QuoteChangeActions.Delete:
                    {
                        if (quote.EndPosition == null)
                        {
                            to.RemoveAt(startPos);
                        }
                        else
                        {
                            to.RemoveRange(startPos, (quote.EndPosition.Value - startPos) + 1);
                        }

                        break;
                    }

                    default:
                        throw new ArgumentOutOfRangeException(nameof(from), quote.Action, LocalizedStrings.Str1219);
                    }
                }
            }

            if (change.HasPositions)
            {
                ApplyByPos(change.Bids, _bidsByPos);
                ApplyByPos(change.Asks, _asksByPos);
            }
            else
            {
                Apply(change.Bids, _bids);
                Apply(change.Asks, _asks);
            }

            if (currState == QuoteChangeStates.SnapshotStarted || currState == QuoteChangeStates.SnapshotBuilding)
            {
                return(null);
            }

            QuoteChange[] bids;
            QuoteChange[] asks;

            if (change.HasPositions)
            {
                bids = _bidsByPos.ToArray();
                asks = _asksByPos.ToArray();
            }
            else
            {
                bids = _bids.Values.ToArray();
                asks = _asks.Values.ToArray();
            }

            return(new QuoteChangeMessage
            {
                SecurityId = SecurityId,
                Bids = bids,
                Asks = asks,
                ServerTime = change.ServerTime,
                OriginalTransactionId = change.OriginalTransactionId,
            });
        }
示例#32
0
 public static void WriteMarketDepth(this QuoteChangeMessage quotes)
 {
     MemoryToFile(QuotesToString(quotes), Path.Combine(_outputFolder, string.Format("{0}_depth.txt", quotes.SecurityId.SecurityCode)));
 }