Наблюдаю на 4.1.8
Проявляет себя как не вызывание события NewMyTrades у объекта EmulationTrader as ITrader (существует и такой по мимо RealTimeEmulationTrader).
Схема такая: ( прошу не задавать вопросы зачем это нужно :) )
- создаем объект EmulationTrader, нацеленный на некоторую базу гидры.
- создаем объект new RealTimeEmulationTrader<ITrader> (EmulationTrader as ITrader)
- Создаем стратегию new MyStrategy(EmulationTrader as ITrader) с примерно следующим конструктором.
MyStrategy(ITrader iDataSource)
{
iDataSource.NewMyTrades += (obj) => { MessageBox.Show("Приехали сделки"); };
}
запускаем и наблюдаем, что сделки то не приезжают.
Дальше веселее. Если поменять пункт 2 и 3 по порядку то есть сделать так:
- создаем объект EmulationTrader, нацеленный на некоторую базу гидры.
- Создаем стратегию new MyStrategy(EmulationTrader as ITrader)
- создаем объект new RealTimeEmulationTrader<ITrader> (EmulationTrader as ITrader). Сделки приедут.
В логах можно обнаружить следующее.
2012/02/24 10:06:10.000|Error |EmulationTrader|System.InvalidOperationException: Ордер с transactionId=101 не найден at StockSharp.Algo.Testing.RealTimeEmulationTrader
1.#=qoYen7SIGXXIHC5yDoBmtakvI8ajVk$YMRTG2hIXiflw=(Int64 #=qO9iU2Mv29dcXgUc$4EMffw==) at StockSharp.Algo.Testing.RealTimeEmulationTrader1.#=qW_NOGPO8hUy5l8I2xNZCL$oRPjjivnoDpJ2KizA3TPo=(IEnumerable1 #=qA0Q6xXtG5Oyta7t6dDl7yg==) at System.Action1.Invoke(T obj) at Ecng.Common.DelegateHelper.SafeInvoke(Action1 handler, T arg) at Ecng.ComponentModel.EventsContainer1.Raise(IEnumerable1 items) 2012/02/24 10:06:10.000| |EmulationTrader|New order: 102/2 Покупка Цена=7025,00000 Объем=1 Сост=Active Бал=1 2012/02/24 10:06:10.000|Error |EmulationTrader|System.InvalidOperationException: Ордер с transactionId=102 не найден at StockSharp.Algo.Testing.RealTimeEmulationTrader1.#=qoYen7SIGXXIHC5yDoBmtakvI8ajVk$YMRTG2hIXiflw=(Int64 #=qO9iU2Mv29dcXgUc$4EMffw==) at StockSharp.Algo.Testing.RealTimeEmulationTrader1.#=qW_NOGPO8hUy5l8I2xNZCL$oRPjjivnoDpJ2KizA3TPo=(IEnumerable1 #=qA0Q6xXtG5Oyta7t6dDl7yg==) at System.Action1.Invoke(T obj) at Ecng.Common.DelegateHelper.SafeInvoke(Action1 handler, T arg) at Ecng.ComponentModel.EventsContainer1.Raise(IEnumerable1 items)
Что наводит нас на мысли о том, что мы отправляем заявки через EmulationTrader он их обрабатывает и генерирует MyTrade которые выдает ее через событие NewMyTrades. Данные MyTrades перехватываются RealTimeEmulationTrader и обрабатываются в методе.
private void NewMyTradesHandler(IEnumerable<MyTrade> trades)
{
foreach(var trade in trades)
{
trade.Order = GetOrderByTransaction(trade.Order.TransactionId);
}
NewMyTrades.SafeInvoke(trades);
}
и далее
private Order GetOrderByTransaction(long transactionId)
{
var order = _byTransactionOrders.TryGetValue(transactionId);
if(order == null)
throw new InvalidOperationException("Ордер с transactionId="+transactionId+" не найден");
return order;
}
Который выбрасывает исключение (потому что заявка подавалась не через эмулятор).
На событие NewMyTrades есть два подписчика. Подписчики лежат в чем то типо List<Action<IEnumerable<MyTrade>>> и при NewMyTrades.Invoke начинают вызываться в порядке в котором на событие были подписаны (ITrader.NewMyTrades += ... ) и соответственно при порядке исполнения 1),3),2) вначале вызывается обработчик стратегии а потом обработчик RealTimeEmulationTrader и вроде все хорошо. При порядке 1), 2), 3) выброшенное, необработанное исключение RealTimeEmulationTrader'ом прерывает перечисление обработчиков в List<Action<IEnumerable<MyTrade>>> и соответственно до обработчика стратегии действие не доходит и он не вызывается и получаем то, что имеем. (По крайней мере так я вижу проблему)
Как вариант, возможно есть смысл, немного подправить обработчик NewOrderHandler RealTimeEmulationTrader
private void NewOrderHandler(Order state)
{
var order = GetOrderByTransaction(state.TransactionId); // (здесь кстати происходит точно такая же ситуация, только с событием NewOrder. Со всеми вытекающими.)
using (order.BeginUpdate())
{
order.Id = state.Id;
order.LastChangeTime = state.LastChangeTime;
order.Time = state.Time;
order.Balance = state.Balance;
order.State = state.State;
}
if (order.Type == OrderTypes.Conditional)
NewStopOrdersHandler(new[] { order });
else
NewOrdersHandler(new[] { order });
}
Что бы при выбрасывании исключения
var order = GetOrderByTransaction(state.TransactionId);
оно обрабатывалось добавление нового ордера в коллекцию RealTimeEmulationTrader'а и что в свою очередь уберет проблему с выбрасыванием исключений при NewMyTrades (так как ордер уже будет в RealTimeEmulationTrader)
Comments (23)
Login or Create account, Log in or register to leave a comment
Возможно не до конца ясно выразился...
Открываем пример SampleEmulationTesting
После создание шлюза
добавляем код
После запуска появляется только табличка с текстом "1".
Использую версию 4.1.9
Это значит, я тут зря плюс поставил?
Немного, возможно, не в ту тему будет вопрос, но наткнулся на этот топик по поиску "BeginUpdate".
Как "заморозить" дальнейшую обработку стратегии до подтверждения того, что отправленная заявка выставилась, или failed. В общем подождать пока она там в пути. В примерах говорится
но это не очень красиво выглядит. Конечно не проблема как-нибудь это сделать, но интересно как это сделать наиболее оптимальным способом.
Заявка, к ней два правила WhenRegistered и WhenRegisterFailed. При срабатывании одного, удаляем другое. Также, когда сработало одно из этих правил, выполняем дальнейшую логику стратегии. Получается пока одно из правил не сработает, стратегия будет "ждать".
Меня смущает то, что пока будет ожидаться отклик о состоянии заявки, может состоятся повторный вход в цепочку и заявка шмальнётся ещё раз, или несколько. А замарозка, как мне кажется, предохраняет от этого. Я просто не вижу, где стратегия блокируется, если применено правило.
Сигнал -> Заявка на шорт выставлена? -> нет -> заявка + 2 правила + регистрация заявки + считаем что заявка выствлена СРАЗУ. да -> пропуск.
Сработало одно из правил -> Заявка зарегана? -> нет -> удаляем лишнее правило -> считаем что заявка НЕ выставлена -> дальнейшие действия. да -> удаляем лишнее правило -> подтверждение что заявка выставлена -> дальнейшие действия.
В итоге, сигналы могут приходить хоть с каждым тиком. Но пока не будет подтверждения того что заявка зарегана/незарегна, то новые сигналы будут пропускаться.
Правильно я понимаю, что без условий (if) здесь не обойтись? Правила ведь позволяют вызывать действия только при положительном ответ, а что делать при отрицательном, т.е. если ордер всё ещё не зарегистрирован.
Я сначала думал замораживать процесс через зациклинг, что-то типа этого
Замораживание (откладывание выполнения) - это уже другая логика. Решается локами или теми самыми слипами.
Мне кажется, тогда, было бы логичным сделать стандартное правило ожидания, типа:
Почему нельзя сделать так?
Попробую. Но в таком правиле тоже, думаю, был бы смысл
Trader.WhenIntervalElapsed
Проявляет себя на 4.1.11 Возможно выше написанная диагностика выполнена не достаточно ясно? Может быть, что то не понятно? Может я как то еще могу помочь?
P.S. Прошу очистить ветку от сообщений не по теме.
Прошу проверить:
Версия 4.1.12 , RealTimeEmulationTrader поверх QuikTrader: _trader.CancelOrder(order) не срабатывает, заявки не удяляються и остаются висеть в _trader.Orders со статусом Active , _trader.ReRegisterOrder тоже не удаляет заявки , но при попытке повторного удаления заявок из _trader.Orders.Where(x => x.State == OrderStates.Active) выдает ошибку что заявка не была зарегистрирована или уже удалена , при чем в _trader.Orders все также остаются висеть те же заявки с OrderStates.Active. И при попытке заслать противоположную заявку с ценой ниже выдает сообщение про кросс заявку.
Спасибо.
Что в логе пишется? События NewOrders, OrdersChanged вызываются?
Пока еще не разобрался с логами , события NewOrders, OrdersChanged у меня тоже не используются. Попробуйте у себя небольшой генератор сделок и их перерегистрацию или отмену, остаются ли у вас активные заявки в трейдере?
Так как остаються ли у вас висеть в трейдере(RealTimeEmulationTrader) активные заявки ? или только у меня проблема ?