Algonavt
|
Дата: 27.11.2012
Проблема возникает из-за того, что стакан не успевает запуститься к моменту обращения к BestBid в коде создания стратегии. Для эксперимента сделал две кнопки - одну на запуск стаканов с котировками инструментов, по которым открыты позиции, вторую - на закрытие самих позиций. Всё работает тип-топ, при наличии уже подгруженных стаканов позиции закрываются на "ура".
Стало быть, перед тем, как создавать страегии котирования (или выставлять заявки), надо как-то дождаться прихода события о появлении стакана для всех инструментов. Как это сделать - почти придумал, если кому интересно - выложу по выполнении.
Велосипед, однако. :)
|
|
Спасибо:
|
|
|
|
|
vil
|
Дата: 11.12.2012
Прошу не бросать помидорами. Из меня программист вообще никакой. Но позволю спросить, а что мешает использовать "Семафоры" для временной паузы перед регистрацией заявки или еще чем то до момента прихода события получения стакана ?
|
|
Спасибо:
|
|
|
|
|
Algonavt
|
Дата: 17.12.2012
|
|
|
|
Почти так и сделал. Реализовал такой код: Код
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;
}
}
|
|
Спасибо:
|
|
|
|
|
VassilSanych
|
Дата: 18.12.2012
vil Прошу не бросать помидорами. Из меня программист вообще никакой. Но позволю спросить, а что мешает использовать "Семафоры" для временной паузы перед регистрацией заявки или еще чем то до момента прихода события получения стакана ? Ничего не мешает. Но проще просто подписаться на событие. Чем короче методы, тем лучше.
|
|
Спасибо:
|
|
|
|
|
Algonavt
|
Дата: 18.12.2012
VassilSanych vil Прошу не бросать помидорами. Из меня программист вообще никакой. Но позволю спросить, а что мешает использовать "Семафоры" для временной паузы перед регистрацией заявки или еще чем то до момента прихода события получения стакана ? Ничего не мешает. Но проще просто подписаться на событие. Чем короче методы, тем лучше. Собственно, идея состояла в том, чтобы к моменту, когда потребуется регистрировать заявки по инструменту, стакан уже был запущен. Тогда и ожидать ничего не придется. Запуск стакана - как правило разовая операция (при старте или перезагрузке робота), работа с заявками - многократная. Так что перед каждой заявкой проверять/стартовать стакан - некруто с точки зрения производительности, как я думаю.
|
|
Спасибо:
|
|
|
|
|
Игорь Бакулин
|
Дата: 18.12.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 // };
Попробуйте так. Код
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; Код
this._trader.NewMarketDepths += depths => this.GuiAsync(() =>
{
depths.ForEach(d =>
{
WriteLogMessage (string.Format ( "Появился стакан для инструмента {0}. Бид: {1}", d.Security.Code, d.BestBid.Price));
});
ShowDepthsForPositionsButton.IsEnabled = true;
});
|
|
Спасибо:
|
|
|
|
|
Algonavt
|
Дата: 18.12.2012
|
|
|
|
Собственно, я перед тем, как создавать дочерние стратегии распродажи портфеля запускаю стаканы для всех инструментов. Дочерние стратегии я начинаю создавать только если все стаканы запустились. То есть, для каждого из инструментов, по которому есть ненулевая позиция, сперва создается стакан через метод DepthStarter.WaitForMarketDepth(ITrader trader, Security security).
По поводу проверки _depth.BestAsk и _depth.BestBid на != null - согласен, в "боевом" режиме это надо делать, т.к. в теории в стакане могут исчезнуть все биды или все аски (для наиболее ликвидных инструментов это, конечно, маловероятно, но тем не менее лучше страховаться) - в документации на стокшарп такой тип "экстремальных" случаев также упоминается как возможный и, след-но, подлежащий обработке. Просто в примере не стал его включать.
А вот по поводу "для получения этих данных системе требуется какое-то время" вопрос на самом деле очень интересный. Тут я хочу спросить у разработчиков библиотеки, как задумана в логике библиотеки обработка ситуаций, когда стакан запущен, но новые данные по стакану из трейдера ещё не прибежали. Полагаю, что в качестве BestPair (и, соответственно, BestBid и BestAsk) предоставляется последнее закешированное значение. Так ли это?
|
|
Спасибо:
|
|
|
|
|
VassilSanych
|
Дата: 04.02.2013
|
|
|
|
Какое-то странное поведение Если подписаться на лог стратегии котирования Код
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 - мой класс, который ловит события шлюза). А вот если не подписываться: Код
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;' вернул неправильное сообщение 'Не найдена активная заявка для перестановки' по передвинутым заявкам.
Позиция закрывается, а вот в процессе - косяки.
|
|
Спасибо:
|
|
|
|