| Algonavt 
 
   
 
						
						
					 | Date: 11/27/2012 
 
 
	
			Проблема возникает из-за того, что стакан не успевает запуститься к моменту обращения к BestBid в коде создания стратегии. Для эксперимента сделал две кнопки - одну на запуск стаканов с котировками инструментов, по которым открыты позиции, вторую - на закрытие самих позиций. Всё работает тип-топ, при наличии уже подгруженных стаканов позиции закрываются на "ура".
 Стало быть, перед тем, как создавать страегии котирования (или выставлять заявки), надо как-то дождаться прихода события о появлении стакана для всех инструментов. Как это сделать - почти придумал, если кому интересно - выложу по выполнении.
 
 Велосипед, однако. :)
 | 
			
				|  | 
	
		| Thanks: |   |  | 
			
				|  | 
		
			| 
 | 
		
			
				| vil 
 
   
 
						
						
					 | Date: 12/11/2012 
 
 
	
			Прошу не бросать помидорами. Из меня программист вообще никакой.Но позволю спросить, а что мешает использовать "Семафоры" для временной паузы перед регистрацией заявки или еще чем то до момента прихода события получения стакана ?
 | 
			
				|  | 
	
		| Thanks: |   |  | 
			
				|  | 
		
			| 
 | 
		
			
				| Algonavt 
 
   
 
						
						
					 | Date: 12/17/2012 
						
							|  |  |  |   |  
 
 
	
			Почти так и сделал. Реализовал такой код: Code
public class DepthStarter
    {
        public bool WaitForMarketDepth(ITrader trader, Security security)
        {
            if (security == null)
                throw new ApplicationException("DepthSelector: security == null!");
            var _depthTrigger = false;
            ManualResetEventSlim manualResetEvent = new ManualResetEventSlim(false);
            Action<IEnumerable<MarketDepth>> onDepthsChanged = p =>
            {
                if (FindDepth(trader, security))
                    manualResetEvent.Set();
            };
            try
            {
                trader.NewMarketDepths += onDepthsChanged;
                trader.MarketDepthsChanged += onDepthsChanged;
                trader.RegisterMarketDepth(security);
                _depthTrigger = FindDepth(trader, security);
                if (!_depthTrigger)
                    _depthTrigger = manualResetEvent.Wait(TimeSpan.FromSeconds(10));
                return _depthTrigger;
                //return FindDepth(trader, security) || manualResetEvent.Wait(TimeSpan.FromSeconds(10));   // Это НЕ РАБОТАЕТ!! Оставлено, чтобы помнить, как делать не надо.
            }
            finally
            {
                trader.NewMarketDepths -= onDepthsChanged;
                trader.MarketDepthsChanged -= onDepthsChanged;
            }
        }
        private bool FindDepth(ITrader trader, Security security)
        {
            return trader.RegisteredMarketDepths.Contains(security) ? (security.BestBid != null) || (security.BestAsk != null) : false;
        }
    } | 
			
				|  | 
	
		| Thanks: |   |  | 
			
				|  | 
		
			| 
 | 
		
			
				| VassilSanych 
 
   
 
						
						
					 | Date: 12/18/2012 
 
 
	
			vil Прошу не бросать помидорами. Из меня программист вообще никакой.Но позволю спросить, а что мешает использовать "Семафоры" для временной паузы перед регистрацией заявки или еще чем то до момента прихода события получения стакана ?
 Ничего не мешает. Но проще просто подписаться на событие. Чем короче методы, тем лучше.
			
			
			
			
		
 | 
			
				|  | 
	
		| Thanks: |   |  | 
			
				|  | 
		
			| 
 | 
		
			
				| Algonavt 
 
   
 
						
						
					 | Date: 12/18/2012 
 
 
	
			VassilSanych vil Прошу не бросать помидорами. Из меня программист вообще никакой.Но позволю спросить, а что мешает использовать "Семафоры" для временной паузы перед регистрацией заявки или еще чем то до момента прихода события получения стакана ?
 Ничего не мешает. Но проще просто подписаться на событие. Чем короче методы, тем лучше. Собственно, идея состояла в том, чтобы к моменту, когда потребуется регистрировать заявки по инструменту, стакан уже был запущен. Тогда и ожидать ничего не придется. Запуск стакана - как правило разовая операция (при старте или перезагрузке робота), работа с заявками - многократная. Так что перед каждой заявкой проверять/стартовать стакан - некруто с точки зрения производительности, как я думаю.
			
			
			
			
		
 | 
			
				|  | 
	
		| Thanks: |   |  | 
			
				|  | 
		
			| 
 | 
		
			
				| Игорь Бакулин 
 
   
 
						
						
					 | Date: 12/18/2012 
						
							|  |  |  |   |  
 
 
	
			Algonavt 
 //var _depth = _trader.GetMarketDepth(p.Security).Clone();
 
 //var _close = new LimitQuotingStrategy(_volume > 0 ? OrderDirections.Sell : OrderDirections.Buy, _volume.Abs(), (_depth.BestAsk.Price + _depth.BestBid.Price) / 2)
 // {
 //     Trader = this._trader,
 //     Security = p.Security,
 //     Portfolio = p.Portfolio
 // };
 
 
 
 Попробуйте так. Code
                    var _depth = _trader.GetMarketDepth(p.Security).Clone();
                    if (_depth != null)
                    {
                    var _close = new LimitQuotingStrategy(_volume > 0 ? OrderDirections.Sell : OrderDirections.Buy, _volume.Abs(), (_depth.BestAsk.Price + _depth.BestBid.Price) / 2)
                     {
                         Trader = this._trader,
                         Security = p.Security,
                         Portfolio = p.Portfolio
                     };
                     }
 еще бывает полезно проверять на not null _depth.BestAsk и _depth.BestBid т.к. для получения этих данных системе требуется какое-то время. А пока данные не подгружены эти значения равны null, т.е. не инициализированы. Ну а если вам важно отрабатывать нажатие на кнопку ShowDepthsForPositionsButton когда уже точно стакан подгружен, то можно так в xaml пишем ShowDepthsForPositionsButton.IsEnabled = false т.е. делаем кнопку не активной. а в строки 169-175 добавить ShowDepthsForPositionsButton.IsEnabled = true; Code
this._trader.NewMarketDepths += depths => this.GuiAsync(() =>
     {
       depths.ForEach(d =>
           {		    
               WriteLogMessage (string.Format ( "Появился стакан для инструмента {0}. Бид: {1}", d.Security.Code, d.BestBid.Price));
           });
       ShowDepthsForPositionsButton.IsEnabled = true;
     });
 | 
			
				|  | 
	
		| Thanks: |   |  | 
			
				|  | 
		
			| 
 | 
		
			
				| Algonavt 
 
   
 
						
						
					 | Date: 12/18/2012 
						
							|  |  |  |   |  
 
 
	
			Собственно, я перед тем, как создавать дочерние стратегии распродажи портфеля запускаю стаканы для всех инструментов. Дочерние стратегии я начинаю создавать только если все стаканы запустились. То есть, для каждого из инструментов, по которому есть ненулевая позиция, сперва создается стакан через метод DepthStarter.WaitForMarketDepth(ITrader trader, Security security).
 По поводу проверки _depth.BestAsk и _depth.BestBid на != null - согласен, в "боевом" режиме это надо делать, т.к. в теории в стакане могут исчезнуть все биды или все аски (для наиболее ликвидных инструментов это, конечно, маловероятно, но тем не менее лучше страховаться) - в документации на стокшарп такой тип "экстремальных" случаев также упоминается как возможный и, след-но, подлежащий обработке. Просто в примере не стал его включать.
 
 А вот по поводу "для получения этих данных системе требуется какое-то время" вопрос на самом деле очень интересный. Тут я хочу спросить у разработчиков библиотеки, как задумана в логике библиотеки обработка ситуаций, когда стакан запущен, но новые данные по стакану из трейдера ещё не прибежали. Полагаю, что в качестве BestPair (и, соответственно, BestBid и BestAsk) предоставляется последнее закешированное значение. Так ли это?
 | 
			
				|  | 
	
		| Thanks: |   |  | 
			
				|  | 
		
			| 
 | 
		
			
				| VassilSanych 
 
   
 
						
						
					 | Date: 2/4/2013 
						
							|  |  |  |   |  
 
 
	
			Какое-то странное поведение Если подписаться на лог стратегии котирования Code
2013/02/04 17:37:43.749|       |LQS_RIH3@RTS_SPBFUT00066|Стратегия запущена. [0,-1]. Позиция при старте 0.
2013/02/04 17:37:43.752|       |LQS_RIH3@RTS_SPBFUT00066|Котирование на Sell объема 1.
2013/02/04 17:37:43.753|       |LQS_RIH3@RTS_SPBFUT00066|Приостановка правил. _rulesSuspendCount 1.
2013/02/04 17:37:43.771|       |LQS_RIH3@RTS_SPBFUT00066|Возобновление правил. _rulesSuspendCount 0.
2013/02/04 17:37:43.779|       |LQS_RIH3@RTS_SPBFUT00066|Цена текущей NULL и лучшей 161120.
2013/02/04 17:37:43.779|       |LQS_RIH3@RTS_SPBFUT00066|Лучший бид 161110 и лучший аск 161130.
2013/02/04 17:37:43.786|       |LQS_RIH3@RTS_SPBFUT00066|Регистрация новой Limit (0x159ADC6) заявки на Sell с ценой 161120 и объемом 1. 
2013/02/04 17:37:44.121|Warning|LQS_RIH3@RTS_SPBFUT00066|Заявка 63437501 в процессе регистрации.
2013/02/04 17:37:44.123|       |LQS_RIH3@RTS_SPBFUT00066|Заявка 63437501 принята биржей.
2013/02/04 17:37:44.124|       |LQS_RIH3@RTS_SPBFUT00066|Сброс счетчика ошибок регистрации с 0 до нуля.
2013/02/04 17:37:44.127|       |QuikManager|316 Заявка 63437501/1981856709 Продажа Цена=161120 Объем=1 Сост=Active Бал=1
2013/02/04 17:37:48.768|       |QuikManager|768 Сделка 04.02.2013 17:37:48 82247758 161120 1 от заявки 63437501/1981856709 Продажа Цена=161120 Объем=1 Сост=Done Бал=0
2013/02/04 17:37:48.771|       |LQS_RIH3@RTS_SPBFUT00066|Новая Sell сделка 82247758 по цене 161120 на 1 заявки 63437501.
2013/02/04 17:37:48.770|       |QuikManager|316 Заявка 63437501/1981856709 Продажа Цена=161120 Объем=1 Сост=Done Бал=0
2013/02/04 17:37:48.772|       |LQS_RIH3@RTS_SPBFUT00066|Новая позиция: SPBFUT00066-RIH3@RTS=-1.
2013/02/04 17:37:48.773|       |LQS_RIH3@RTS_SPBFUT00066|Позиция изменилась на -1. Оставшийся объем 0.
2013/02/04 17:37:48.773|       |LQS_RIH3@RTS_SPBFUT00066|Заканчиваем котирование.
2013/02/04 17:37:48.773|       |LQS_RIH3@RTS_SPBFUT00066|Стратегия останавливается. [0,-1]. Позиция при старте -1.
2013/02/04 17:37:48.775|       |LQS_RIH3@RTS_SPBFUT00066|Правило 'Изменение стакана инструмента RIH3@RTS (0x2790E95)'. Приостановлено.
2013/02/04 17:37:48.775|       |LQS_RIH3@RTS_SPBFUT00066|Ожидание снятия всех активных заявок.
2013/02/04 17:37:48.780|       |LQS_RIH3@RTS_SPBFUT00066|Стратегия остановлена. [0,-1]. Позиция при старте -1. Вроде нормально (QuikManager - мой класс, который ловит события шлюза). А вот если не подписываться: Code
2013/02/04 17:25:05.735|       |QuikManager|196 Заявка 62514036/1981813976 Покупка Цена=161230 Объем=1 Сост=Done Бал=1
2013/02/04 17:25:05.970|       |QuikManager|196 Заявка 62514036/1981813976 Покупка Цена=161230 Объем=1 Сост=Done Бал=1
2013/02/04 17:25:05.971|       |QuikManager|235 Заявка 62514037/1981814003 Покупка Цена=161230 Объем=1 Сост=Active Бал=1
2013/02/04 17:25:06.171|       |QuikManager|235 Заявка 62514037/1981814003 Покупка Цена=161230 Объем=1 Сост=Done Бал=1
2013/02/04 17:25:06.172|       |QuikManager|200 Заявка 62514038/1981814030 Покупка Цена=161230 Объем=1 Сост=Done Бал=0
2013/02/04 17:25:06.250|       |QuikManager|251 Сделка 04.02.2013 17:25:06 82246193 161230 1 от заявки 62514038/1981814030 Покупка Цена=161230 Объем=1 Сост=Done Бал=0
2013/02/04 17:25:06.250|       |QuikManager|200 Заявка 62514038/1981814030 Покупка Цена=161230 Объем=1 Сост=Done Бал=0
2013/02/04 17:25:06.326|Error  |QuikManager|Ошибка регистрации заявки: System.InvalidOperationException: Сервер для транзакции 'ACTION=MOVE_ORDERS; CLASSCODE=SPBFUT; SECCODE=RIH3; MODE=0; FIRST_ORDER_NUMBER=1981814030; FIRST_ORDER_NEW_PRICE=161230; FIRST_ORDER_NEW_QUANTITY=0; TRANS_ID=62514039;' вернул неправильное сообщение 'Не найдена активная заявка для перестановки' по передвинутым заявкам. Позиция закрывается, а вот в процессе - косяки.
			
			
			
			
		
 | 
			
				|  | 
	
		| Thanks: |   |  | 
			
				|  |