Проблема в RealTimeEmulationTrader

Проблема в RealTimeEmulationTrader
Atom
3/5/2013
AASorokovoy


Наблюдаю на 4.1.8

Проявляет себя как не вызывание события NewMyTrades у объекта EmulationTrader as ITrader (существует и такой по мимо RealTimeEmulationTrader).

Схема такая: ( прошу не задавать вопросы зачем это нужно :) )

1) создаем объект EmulationTrader, нацеленный на некоторую базу гидры.
2) создаем объект new RealTimeEmulationTrader<ITrader> (EmulationTrader as ITrader)
3) Создаем стратегию new MyStrategy(EmulationTrader as ITrader) с примерно следующим конструктором.

Code

MyStrategy(ITrader iDataSource)
{
iDataSource.NewMyTrades += (obj) => { MessageBox.Show("Приехали сделки"); };
}

запускаем и наблюдаем, что сделки то не приезжают.

Дальше веселее. Если поменять пункт 2 и 3 по порядку то есть сделать так:
1) создаем объект EmulationTrader, нацеленный на некоторую базу гидры.
3) Создаем стратегию new MyStrategy(EmulationTrader as ITrader)
2) создаем объект new RealTimeEmulationTrader<ITrader> (EmulationTrader as ITrader).
Сделки приедут.

В логах можно обнаружить следующее.

Quote:

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.RealTimeEmulationTrader`1.#=qW_NOGPO8hUy5l8I2xNZCL$oRPjjivnoDpJ2KizA3TPo=(IEnumerable`1 #=qA0Q6xXtG5Oyta7t6dDl7yg==)
at System.Action`1.Invoke(T obj)
at Ecng.Common.DelegateHelper.SafeInvoke[T](Action`1 handler, T arg)
at Ecng.ComponentModel.EventsContainer`1.Raise(IEnumerable`1 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.RealTimeEmulationTrader`1.#=qoYen7SIGXXIHC5yDoBmtakvI8ajVk$YMRTG2hIXiflw=(Int64 #=qO9iU2Mv29dcXgUc$4EMffw==)
at StockSharp.Algo.Testing.RealTimeEmulationTrader`1.#=qW_NOGPO8hUy5l8I2xNZCL$oRPjjivnoDpJ2KizA3TPo=(IEnumerable`1 #=qA0Q6xXtG5Oyta7t6dDl7yg==)
at System.Action`1.Invoke(T obj)
at Ecng.Common.DelegateHelper.SafeInvoke[T](Action`1 handler, T arg)
at Ecng.ComponentModel.EventsContainer`1.Raise(IEnumerable`1 items)


Что наводит нас на мысли о том, что мы отправляем заявки через EmulationTrader он их обрабатывает и генерирует MyTrade которые выдает ее через событие NewMyTrades. Данные MyTrades перехватываются RealTimeEmulationTrader и обрабатываются в методе.

Code

		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

Code

		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 });
		}


Что бы при выбрасывании исключения
Code

var order = GetOrderByTransaction(state.TransactionId); 


оно обрабатывалось добавление нового ордера в коллекцию RealTimeEmulationTrader'а и что в свою очередь уберет проблему с выбрасыванием исключений при NewMyTrades (так как ордер уже будет в RealTimeEmulationTrader)









Thanks:


1 2 3  >
ASorokovoy

Avatar
Date: 3/18/2013
Reply


Возможно не до конца ясно выразился...

Открываем пример SampleEmulationTesting

После создание шлюза
Code

			// создаем шлюз для эмуляции
			_trader = new EmulationTrader(
				new[] { security },
				new[] { portfolio })
			{
				MarketTimeChangedInterval = timeFrame
			};


добавляем код

Code

            _trader.NewMyTrades += (obj) => { MessageBox.Show("1"); };
            RealTimeEmulationTrader<ITrader> _em = new RealTimeEmulationTrader<ITrader>(_trader);
            _trader.NewMyTrades += (obj) => { MessageBox.Show("2"); };


После запуска появляется только табличка с текстом "1".

Использую версию 4.1.9

Thanks:

VassilSanych

Avatar
Date: 3/18/2013
Reply


Это значит, я тут зря плюс поставил?
Thanks:

esper

Avatar
Date: 3/18/2013
Reply


VassilSanych
Это значит, я тут зря плюс поставил?

На тот момент все работало[biggrin] Сейчас баг действительно есть, будем править.
Thanks:

Творог

Avatar
Date: 3/19/2013
Reply


Немного, возможно, не в ту тему будет вопрос, но наткнулся на этот топик по поиску "BeginUpdate".

Как "заморозить" дальнейшую обработку стратегии до подтверждения того, что отправленная заявка выставилась, или failed. В общем подождать пока она там в пути. В примерах говорится

Code
// ждем 1 секунду
    Thread.Sleep(1000);


но это не очень красиво выглядит. Конечно не проблема как-нибудь это сделать, но интересно как это сделать наиболее оптимальным способом.
Thanks:

Moadip

Avatar
Date: 3/19/2013
Reply


Quote:
Как "заморозить" дальнейшую обработку стратегии до подтверждения того, что отправленная заявка выставилась, или failed.

Замораживать надо не работу стратегии. Все должно быть на уровне логики работы стратегии. Т.е. пока не выполнилось одно условие, дальше стратегия не выполняется.

Заявка, к ней два правила WhenRegistered и WhenRegisterFailed.
При срабатывании одного, удаляем другое. Также, когда сработало одно из этих правил, выполняем дальнейшую логику стратегии.
Получается пока одно из правил не сработает, стратегия будет "ждать".
Thanks:

Творог

Avatar
Date: 3/19/2013
Reply


Меня смущает то, что пока будет ожидаться отклик о состоянии заявки, может состоятся повторный вход в цепочку и заявка шмальнётся ещё раз, или несколько. А замарозка, как мне кажется, предохраняет от этого. Я просто не вижу, где стратегия блокируется, если применено правило.
Thanks:

Moadip

Avatar
Date: 3/19/2013
Reply


Quote:
Я просто не вижу, где стратегия блокируется, если применено правило.

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

Quote:
Меня смущает то, что пока будет ожидаться отклик о состоянии заявки, может состоятся повторный вход в цепочку и заявка шмальнётся ещё раз, или несколько. А замарозка, как мне кажется, предохраняет от этого.

Еще раз повторюсь. Замораживать поток в котором выполняется стратегия это плохой вариант. Все должно быть построено на уровне логики.
И чтобы не "шмальнуть" еще одну заявку, это надо учитывать в логике.
Простой пример. Допустим надо выставить заявку на шорт, причем сигналы приходят постоянно.

Сигнал ->
Заявка на шорт выставлена? ->
нет -> заявка + 2 правила + регистрация заявки + считаем что заявка выствлена СРАЗУ.
да -> пропуск.

Сработало одно из правил ->
Заявка зарегана? ->
нет -> удаляем лишнее правило -> считаем что заявка НЕ выставлена -> дальнейшие действия.
да -> удаляем лишнее правило -> подтверждение что заявка выставлена -> дальнейшие действия.

В итоге, сигналы могут приходить хоть с каждым тиком. Но пока не будет подтверждения того что заявка зарегана/незарегна, то новые сигналы будут пропускаться.
Thanks:

Творог

Avatar
Date: 3/19/2013
Reply


Правильно я понимаю, что без условий (if) здесь не обойтись? Правила ведь позволяют вызывать действия только при положительном ответ, а что делать при отрицательном, т.е. если ордер всё ещё не зарегистрирован.

Я сначала думал замораживать процесс через зациклинг, что-то типа этого

Code
while(order.Status == None)
{
   order.BeginUpdate(); // не знаю что делает этот метод, наверное обновляет члены.
}

Thanks:

VassilSanych

Avatar
Date: 3/19/2013
Reply


Замораживание (откладывание выполнения) - это уже другая логика.
Решается локами или теми самыми слипами.
Thanks:

Творог

Avatar
Date: 3/20/2013
Reply


Мне кажется, тогда, было бы логичным сделать стандартное правило ожидания, типа:

Code
    order
        .WaitFeedback(strategy, timeout) //запрещает проводить любые действия с заявками по стратегии
        .WhenRegistered()
        .Do(() => trader.AddInfoLog("Заявка успешно зарегестрирована"))
        .Once()
        .Apply(this);

    // регистрация заявки
    trader.RegisterOrder(order);
Thanks:
1 2 3  >

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

loading
clippy