Проблема в RealTimeEmulationTrader
Atom Ответить
05.03.2013


Наблюдаю на 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)









Спасибо:




23 Ответов
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);
Спасибо:

VassilSanych

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


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

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

    // регистрация заявки
    trader.RegisterOrder(order);

Оk. Допустим у вас есть такое правило. Ошибка регистрации заявки. Ваши действия?

Спасибо:

Творог

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


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

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

    // регистрация заявки
    trader.RegisterOrder(order);

Оk. Допустим у вас есть такое правило. Ошибка регистрации заявки. Ваши действия?



Если по таймауту, например 10 сек, никакого ответа, то запускается делегат
.WaitFeedback(strategy, timeout, action)
Это будет означать что косяки либо с интернетом (переход на резервный канал), либо биржей (стоп-торги) или брокером. В общем торговлю вообще надо замораживать и по возможности крыть все позиции.

Если ошибка регистрации, то это уже ответ failed, это уже другая история, например, денег на счёте не хватило.
Спасибо:

esper

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


Код
private void Process(Candle candle)
{
	if (_order != null)
		return;

	_order = this.CreateOrder(OrderDirections.Buy, candle.ClosePrice);

	_order
		.WhenRegistered()
		.Do(() => { _order = null; })
		.Apply(this);

	_order
		.WhenRegisterFailed()
		.Do(() => { _order = null; })
		.Apply(this);

	RegisterOrder(_order);
}

Почему нельзя сделать так?
Спасибо:

Творог

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


esper Перейти

Почему нельзя сделать так?


Попробую. Но в таком правиле тоже, думаю, был бы смысл
Код

    _order
        .WaitFeedback(timeout = 10)
        .Do(() => { отправить SMS и email о том, что слишком большая задержка. попытаться перейти на резервный канал. в QUIK перейти на следующий по списку сервер, если такое вообще технически возможно  })
        .Apply(this);
Спасибо:

esper

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


Творог Перейти
Но в таком правиле тоже, думаю, был бы смысл

Код
Trader.WhenIntervalElapsed

Спасибо:

Творог

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


esper Перейти
Творог Перейти
Но в таком правиле тоже, думаю, был бы смысл

Код
Trader.WhenIntervalElapsed



Но бывают же ситуации, когда просмотровая информация поступает, а с заявками проблема.
А есть ли разница приметь к заявкам null или Dispose?
Спасибо:

esper

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


Творог Перейти
Но бывают же ситуации, когда просмотровая информация поступает, а с заявками проблема.

Так и смотрите, что таймаут истек, а информация по заявке еще не пришла.
Спасибо:

AASorokovoy

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



Проявляет себя на 4.1.11
Возможно выше написанная диагностика выполнена не достаточно ясно? Может быть, что то не понятно?
Может я как то еще могу помочь?

P.S.
Прошу очистить ветку от сообщений не по теме.
Автор топика
Спасибо:

esper

Фотография
Программист
Дата: 25.04.2013
Ответить


AASorokovoy Перейти
Проявляет себя на 4.1.11
Возможно выше написанная диагностика выполнена не достаточно ясно? Может быть, что то не понятно?
Может я как то еще могу помочь?

Диагностика отличная, спасибо. Были другие задачи, в следующей версии будет фикс.
Спасибо:

longtrades

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


Прошу проверить:

Версия 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. И при попытке заслать противоположную заявку с ценой ниже выдает сообщение про кросс заявку.

Спасибо.
Спасибо:

esper

Фотография
Программист
Дата: 11.05.2013
Ответить


Что в логе пишется? События NewOrders, OrdersChanged вызываются?
Спасибо:

longtrades

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


Пока еще не разобрался с логами , события NewOrders, OrdersChanged у меня тоже не используются. Попробуйте у себя небольшой генератор сделок и их перерегистрацию или отмену, остаются ли у вас активные заявки в трейдере?
Спасибо:

longtrades

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


Так как остаються ли у вас висеть в трейдере(RealTimeEmulationTrader) активные заявки ? или только у меня проблема ?
Спасибо:


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

loading
clippy