Не правильное значение лучшей цены в стакане

Не правильное значение лучшей цены в стакане
Atom
3/23/2015
RomSunZ


АПИ 4.2.72, коннектор Quik lua.
Периодически получаю неверное значение лучшей цены в стакане, которая находится в середине противоположных котировок:

Code

            var md = this.Connector.GetFilteredMarketDepth(this.Security);
			Sides? badside = null;
			//проверим, есть ли "плохая" лучшая цена
			if (md.Asks.Count() > 1 && md.Bids.Count() > 1)
			{
				if (md.Asks[0].Price<md.Bids[0].Price)
				{
					//есть попандос
					if (md.Asks[0].Price < md.Bids[1].Price) badside = Sides.Sell;
					else if (md.Bids[0].Price > md.Asks[1].Price) badside = Sides.Buy;
				}
			}
			if (badside != null) this.AddErrorLog("В стакане не верная лучшая цена по направлению {0}", badside);


Вместо Asks и Bids можно использовать GetQuotes, GetFilteredQuotes, вместо GetFilteredMarketDepth использовать GetMarketDepth - результат одинаковый. Закономерность появления "плохой" лучшей цены выявить не удалось. Может выскочить с утра, может к вечеру, а может и вообще несколько дней не появляться.

Tags:


Thanks:


< 1 2 3 
RomSunZ

Avatar
Date: 4/24/2015
Reply


Добавил такую проверку:

Code

				case MessageTypes.QuoteChange:
				{
					var quoteMsg = (QuoteChangeMessage)message;
					_sessionHolder.ReplaceSecurityId(quoteMsg.SecurityId, id => quoteMsg.SecurityId = id);
					quoteMsg.ServerTime = _sessionHolder.CurrentTime.Convert(TimeHelper.Moscow);
					var ask = quoteMsg.GetBestAsk().Price;
					var bid = quoteMsg.GetBestBid().Price;
					if (ask <= bid)
					{
						LogReceiver.AddErrorLog("Не верные значения лучших цен! best ask={0} best bid={1} sec={2}", ask, bid, quoteMsg.SecurityId);
					}
					break;
				}

В момент получения ошибки по стакану в роботе в логе луа ошибок нет, т.е. ошибка появляется где-то дальше. Где еще посмотреть можно?

P.S. Периодически в трейдере получаю такую ошибку на сборке, указанной выше:
Quote:

13:54:23.464| |Quik |From server: MarketDataSnapshotFullRefresh
13:54:23.464|Error |QuikTrader|System.InvalidOperationException: Tags should be BodyLength but received BeginString.
в #=qJublOOhstNGuOqciA4pO0IxEbqusgq8AzTUZ$z4_I7QdDamhxix_6xIpo0q08gJs.#=qFSkNH1E6ksrvdnmrGezbbA==(IFixReader #=qyHB14XScGdVE06FHEgMxZQ==, FixTags #=qHKHjSlBEl8dJccjTaFV94Q==)
в #=qJublOOhstNGuOqciA4pO0IxEbqusgq8AzTUZ$z4_I7QdDamhxix_6xIpo0q08gJs.#=qYxLyRp9D4RLNmE615p0bhg==(IFixReader #=qjMUDTw7SUe_0KRt5Hr3OIw==, Boolean #=qeHLVtncL2jAcnczVF92hWEFOYnbsI6LNDKA14vzcvxE=, String #=qnp5_Jgq80L$XMFuCxSTvbuW9g7dT2OzNoyyy4yKpxiY=, ILogReceiver #=qLy6FlbS2B0nlLuQVBJrlLA==, String #=qqHxlCuzlbwviGaQ3NdXv5Q==, Func`3 #=qByjHri7T4qfIYiyMbykVjQ==, Action`1 #=qIoFIKYpJwlJ6XnjSBMM1Mg==)
13:54:23.464|Error |QuikTrader|System.InvalidOperationException: Tags should be BodyLength but received BeginString.
в #=qJublOOhstNGuOqciA4pO0IxEbqusgq8AzTUZ$z4_I7QdDamhxix_6xIpo0q08gJs.#=qFSkNH1E6ksrvdnmrGezbbA==(IFixReader #=qyHB14XScGdVE06FHEgMxZQ==, FixTags #=qHKHjSlBEl8dJccjTaFV94Q==)
в #=qJublOOhstNGuOqciA4pO0IxEbqusgq8AzTUZ$z4_I7QdDamhxix_6xIpo0q08gJs.#=qYxLyRp9D4RLNmE615p0bhg==(IFixReader #=qjMUDTw7SUe_0KRt5Hr3OIw==, Boolean #=qeHLVtncL2jAcnczVF92hWEFOYnbsI6LNDKA14vzcvxE=, String #=qnp5_Jgq80L$XMFuCxSTvbuW9g7dT2OzNoyyy4yKpxiY=, ILogReceiver #=qLy6FlbS2B0nlLuQVBJrlLA==, String #=qqHxlCuzlbwviGaQ3NdXv5Q==, Func`3 #=qByjHri7T4qfIYiyMbykVjQ==, Action`1 #=qIoFIKYpJwlJ6XnjSBMM1Mg==)
13:54:23.464| |QuikTrader|StartExport

Thanks:

RomSunZ

Avatar
Date: 4/24/2015
Reply


Михаил, подскажите где в коде устанавливается флаг message.IsSorted для LUA?
Thanks:

RomSunZ

Avatar
Date: 4/28/2015
Reply


А в ответ тишина...
Использую фикс a5aee499, все, что выше работает не стабильно.
1. Код в LuaFixServer функиця public override void SendOutMessage(Message message):
Code

				switch (message.Type)
				{
......
					case MessageTypes.QuoteChange:
					{
						var quoteMsg = (QuoteChangeMessage)message;
						SessionHolder.ReplaceSecurityId(quoteMsg.SecurityId, id => quoteMsg.SecurityId = id);
						quoteMsg.ServerTime = SessionHolder.CurrentTime.Convert(TimeHelper.Moscow);

						var bask = quoteMsg.GetBestAsk().Price;
						var bbid = quoteMsg.GetBestBid().Price;
						if (quoteMsg.SecurityId.SecurityCode == "SRM5")
						{
							if (bask <= bbid)
							{
								SessionHolder.AddErrorLog("(0)Не верные значения лучших цен в message! best ask={0} best bid={1} sec={2}", bask, bbid, quoteMsg.SecurityId.SecurityCode);
							}
							else
							{
								SessionHolder.AddErrorLog("(1)Значения лучших цен в message: best ask={0} best bid={1} sec={2}", bask, bbid, quoteMsg.SecurityId.SecurityCode);
							}
						}
						break;
					}
.....
				}


Лог:
Quote:

2015/04/28 14:21:59.828|Error |Quik |(1)Значения лучших цен в message: best ask=7503 best bid=7502 sec=SRM5
2015/04/28 14:22:00.107|Error |Quik |(1)Значения лучших цен в message: best ask=7504 best bid=7502 sec=SRM5
2015/04/28 14:22:00.401|Error |Quik |(1)Значения лучших цен в message: best ask=7504 best bid=7502 sec=SRM5
2015/04/28 14:22:00.402|Error |Quik |(1)Значения лучших цен в message: best ask=7504 best bid=7502 sec=SRM5
2015/04/28 14:22:00.685|Error |Quik |(1)Значения лучших цен в message: best ask=7504 best bid=7502 sec=SRM5

Ошибок нет.

2.
Connector_ProcessMessage.cs функция private void ProcessQuotesMessage(Security security, QuoteChangeMessage message)
Code

			var md = GetMarketDepth(security);
			var bask = message.GetBestAsk().Price;
			var bbid = message.GetBestBid().Price;
			if (bask <= bbid)
			{
				this.AddErrorLog("(0)Не верные значения лучших цен в message! best ask={0} best bid={1} sec={2}", bask, bbid, security.Id);
			}
			if (md != null && md.BestAsk != null && md.BestBid != null)
			{
				if (md.BestAsk.Price <= md.BestBid.Price ||
					bask <= bbid)
				{
					this.AddErrorLog("(1)Не верные значения лучших цен! best ask={0} best bid={1} sec={2} md ask={3} md bid={4}", bask, bbid, security.Id, md.BestAsk.Price, md.BestBid.Price);
				}
			}
......

Лог:
Quote:

14:21:59.541|Error |QuikTrader|(0)Не верные значения лучших цен в message! best ask=7503 best bid=7538 sec=SRM5@FORTS
14:21:59.541|Error |QuikTrader|(1)Не верные значения лучших цен! best ask=7503 best bid=7538 sec=SRM5@FORTS md ask=7503 md bid=7538
14:22:00.121|Error |QuikTrader|(0)Не верные значения лучших цен в message! best ask=7504 best bid=7538 sec=SRM5@FORTS
14:22:00.121|Error |QuikTrader|(1)Не верные значения лучших цен! best ask=7504 best bid=7538 sec=SRM5@FORTS md ask=7503 md bid=7538
14:22:00.411|Error |QuikTrader|(0)Не верные значения лучших цен в message! best ask=7504 best bid=7538 sec=SRM5@FORTS
14:22:00.411|Error |QuikTrader|(1)Не верные значения лучших цен! best ask=7504 best bid=7538 sec=SRM5@FORTS md ask=7504 md bid=7538
14:22:00.695|Error |QuikTrader|(0)Не верные значения лучших цен в message! best ask=7504 best bid=7538 sec=SRM5@FORTS
14:22:00.695|Error |QuikTrader|(1)Не верные значения лучших цен! best ask=7504 best bid=7538 sec=SRM5@FORTS md ask=7504 md bid=7538

Ошибка есть.
От куда вызывается ProcessQuotesMessage и что происходит с message между luaserver и коннектором пока не выяснил.
Вызывается из private void MarketDataAdapterOnNewOutMessage(Message message), там message тоже с ошибкой. MarketDataAdapterOnNewOutMessage вызывается по подписке в _marketDataAdapter.NewOutMessage...
Thanks:

Mikhail Sukhov

Avatar
Date: 4/28/2015
Reply


RomSunZ

В момент получения ошибки по стакану в роботе в логе луа ошибок нет, т.е. ошибка появляется где-то дальше.


Получается, что из Луа приходит нормальные стакана. Видимо порча идет дальше. Выставите в скрипте IncrementalDepthUpdates=false Стакан должен слаться как есть.

Подписка на стаканы идет по одному инструменту или по нескольким?
Thanks:

RomSunZ

Avatar
Date: 4/29/2015
Reply


Вообще загадка...
luafixserver public override void SendOutMessage(Message message) получает message без ошибок, далее в ней вызывается base.SendOutMessage(message), который как я понимаю находится в messageadapter.cs и вызывает public virtual void SendOutMessage(Message message) для постановки message в очередь на обработку. А там уже ошибка есть...
Код в messageadapter.cs:
Code

		public virtual void SendOutMessage(Message message)
		{
			InitMessageLocalTime(message);

			if (message.Type == MessageTypes.QuoteChange)
			{
				var quoteMsg = (QuoteChangeMessage)message;

				if (quoteMsg.SecurityId.SecurityCode == "SRM5")
				{
					var bask = quoteMsg.GetBestAsk().Price;
					var bbid = quoteMsg.GetBestBid().Price;
					if (bask <= bbid)
					{
						SessionHolder.AddErrorLog("(2)Не верные значения лучших цен в messageAdapter! best ask={0} best bid={1} sec={2}", bask, bbid, quoteMsg.SecurityId.SecurityCode);
					}
					else
					{
						SessionHolder.AddErrorLog("(3)Значения лучших цен в messageAdapter: best ask={0} best bid={1} sec={2}", bask, bbid, quoteMsg.SecurityId.SecurityCode);
					}
				}
			}

			_outMessageProcessor.EnqueueMessage(message, this, false);
....
}

Лог луа-сервер:
Quote:

2015/04/29 13:12:13.622|Error |Quik |(1)Значения лучших цен в message: best ask=7635 best bid=7633 sec=SRM5
2015/04/29 13:12:13.625|Error |Quik |(1)Значения лучших цен в message: best ask=7634 best bid=7631 sec=SRM5
2015/04/29 13:12:13.628|Error |Quik |(1)Значения лучших цен в message: best ask=7634 best bid=7631 sec=SRM5
2015/04/29 13:12:13.896|Error |Quik |(1)Значения лучших цен в message: best ask=7634 best bid=7632 sec=SRM5
2015/04/29 13:12:13.898|Error |Quik |(1)Значения лучших цен в message: best ask=7634 best bid=7632 sec=SRM5
2015/04/29 13:12:13.908|Error |Quik |(1)Значения лучших цен в message: best ask=7634 best bid=7632 sec=SRM5
2015/04/29 13:12:13.978|Error |Quik |(1)Значения лучших цен в message: best ask=7634 best bid=7632 sec=SRM5
2015/04/29 13:12:14.260|Error |Quik |(1)Значения лучших цен в message: best ask=7634 best bid=7631 sec=SRM5
2015/04/29 13:12:14.265|Error |Quik |(1)Значения лучших цен в message: best ask=7634 best bid=7632 sec=SRM5
2015/04/29 13:12:14.745|Error |Quik |(1)Значения лучших цен в message: best ask=7634 best bid=7632 sec=SRM5
2015/04/29 13:12:15.025|Error |Quik |(1)Значения лучших цен в message: best ask=7634 best bid=7632 sec=SRM5
2015/04/29 13:12:15.305|Error |Quik |(1)Значения лучших цен в message: best ask=7634 best bid=7632 sec=SRM5
2015/04/29 13:12:16.110|Error |Quik |(1)Значения лучших цен в message: best ask=7634 best bid=7632 sec=SRM5
2015/04/29 13:12:16.509|Error |Quik |(1)Значения лучших цен в message: best ask=7634 best bid=7632 sec=SRM5
2015/04/29 13:12:17.670|Error |Quik |(1)Значения лучших цен в message: best ask=7634 best bid=7632 sec=SRM5
2015/04/29 13:12:17.767|Error |Quik |(1)Значения лучших цен в message: best ask=7634 best bid=7632 sec=SRM5
2015/04/29 13:12:18.045|Error |Quik |(1)Значения лучших цен в message: best ask=7634 best bid=7632 sec=SRM5
2015/04/29 13:12:18.050|Error |Quik |(1)Значения лучших цен в message: best ask=7634 best bid=7632 sec=SRM5
2015/04/29 13:12:18.325|Error |Quik |(1)Значения лучших цен в message: best ask=7634 best bid=7632 sec=SRM5
2015/04/29 13:12:18.606|Error |Quik |(1)Значения лучших цен в message: best ask=7634 best bid=7631 sec=SRM5
2015/04/29 13:12:18.665|Error |Quik |(1)Значения лучших цен в message: best ask=7634 best bid=7632 sec=SRM5
2015/04/29 13:12:18.947|Error |Quik |(1)Значения лучших цен в message: best ask=7634 best bid=7631 sec=SRM5
2015/04/29 13:12:18.956|Error |Quik |(1)Значения лучших цен в message: best ask=7632 best bid=7630 sec=SRM5


лог messageadapter
Quote:

13:12:13.635|Error |Quik |(3)Значения лучших цен в messageAdapter: best ask=7635 best bid=7634 sec=SRM5
13:12:13.912|Error |Quik |(2)Не верные значения лучших цен в messageAdapter! best ask=7634 best bid=7634 sec=SRM5
13:12:14.278|Error |Quik |(2)Не верные значения лучших цен в messageAdapter! best ask=7634 best bid=7634 sec=SRM5
13:12:14.760|Error |Quik |(2)Не верные значения лучших цен в messageAdapter! best ask=7634 best bid=7634 sec=SRM5
13:12:15.038|Error |Quik |(2)Не верные значения лучших цен в messageAdapter! best ask=7634 best bid=7634 sec=SRM5
13:12:15.318|Error |Quik |(2)Не верные значения лучших цен в messageAdapter! best ask=7634 best bid=7634 sec=SRM5
13:12:16.122|Error |Quik |(2)Не верные значения лучших цен в messageAdapter! best ask=7634 best bid=7634 sec=SRM5
13:12:16.522|Error |Quik |(2)Не верные значения лучших цен в messageAdapter! best ask=7634 best bid=7634 sec=SRM5
13:12:17.686|Error |Quik |(2)Не верные значения лучших цен в messageAdapter! best ask=7634 best bid=7634 sec=SRM5
13:12:18.622|Error |Quik |(2)Не верные значения лучших цен в messageAdapter! best ask=7634 best bid=7634 sec=SRM5
13:12:18.960|Error |Quik |(2)Не верные значения лучших цен в messageAdapter! best ask=7634 best bid=7634 sec=SRM5


И еще похоже на то, что часть message теряется и не проходит в принципе судя по количеству вызовов в луа-сервере и в адаптере...
Этот вариант без IncrementalDepthUpdates=false, позже попробую с ней. Подписка на несколько стаканов, просто чтобы было меньше каши в логах сделал выгрузку только по одному.

P.S. включение флага IncrementalDepthUpdates=false не помогает.
P.P.S. Для luafixserver SessionHolder пишет лог в файл сервера StockSharp.QuikLua.log, а для messageadapter SessionHolder пишет лог в файл трейдера QuikTrader.txt. И как тогда поймать передачу данных от одного к другому?
P.P.P.S. Михаил, может быть для лучшего быстродействия имеет смысл сделать отдельную очередь и отдельные обработчики для сообщений стакана и для прочих сообщений?
Thanks:
< 1 2 3 

Attach files by dragging & dropping, , or pasting from the clipboard.

loading
clippy