Проблема в RealTimeEmulationTrader
Atom
05.03.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) с примерно следующим конструктором.

Код

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).
Сделки приедут.

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

Цитата:

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 и обрабатываются в методе.

Код

		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)









Спасибо:


1 2 3  >
ASorokovoy

Фотография
Дата: 18.03.2013
Ответить


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

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

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

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


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

Код

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


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

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

Спасибо:

VassilSanych

Фотография
Дата: 18.03.2013
Ответить


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

esper

Фотография
Дата: 18.03.2013
Ответить


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

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

Творог

Фотография
Дата: 19.03.2013
Ответить


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

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

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


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

Moadip

Фотография
Дата: 19.03.2013
Ответить


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

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

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

Творог

Фотография
Дата: 19.03.2013
Ответить


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

Moadip

Фотография
Дата: 19.03.2013
Ответить


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

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

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

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

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

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

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

Творог

Фотография
Дата: 19.03.2013
Ответить


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

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

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

Спасибо:

VassilSanych

Фотография
Дата: 19.03.2013
Ответить


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

Творог

Фотография
Дата: 20.03.2013
Ответить


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

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

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

Добавить файлы через драг-н-дроп, , или вставить из буфера обмена.

loading
clippy