← Voltar

Проблема в RealTimeEmulationTrader

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

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

2012/02/24 10:06:10.000|Error |EmulationTrader|System.InvalidOperationException: Ордер с transactionId=101 не найден 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) 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)

Este tópico foi útil?

Compartilhar tópico

Comentários (23)

Entrar ou Criar conta, Faça login ou cadastre-se para deixar um comentário

ASorokovoy
ASorokovoy

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

Открываем пример 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
VassilSanych

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

esper
esper

VassilSanych: Это значит, я тут зря плюс поставил? На тот момент все работало😀 Сейчас баг действительно есть, будем править.

Творог
Творог

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

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

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

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

Moadip
Moadip

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

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

Творог
Творог

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

Moadip
Moadip

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

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

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

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

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

Творог
Творог

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

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

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

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

Творог
Творог

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

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

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

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

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

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

Творог
Творог

VassilSanych:

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

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

// регистрация заявки
trader.RegisterOrder(order);
> Оk. Допустим у вас есть такое правило. Ошибка регистрации заявки. Ваши действия?

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

Если ошибка регистрации, то это уже ответ failed, это уже другая история, например, денег на счёте не хватило.
esper
esper
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);
}

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

Творог
Творог

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

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


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

esper
esper

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

Trader.WhenIntervalElapsed
Творог
Творог

esper:

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

Trader.WhenIntervalElapsed


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

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

AASorokovoy
AASorokovoy Autor

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

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

esper
esper

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

longtrades
longtrades

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

Версия 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
esper

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

longtrades
longtrades

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

longtrades
longtrades

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