Нужна помощь (очередь событий)
Atom
12.11.2013
Bond


Нужна помощь!

Есть код:


//Событие изменения PnL
strategy.PnLChanged += () =>
  {
     x = x + 1;
  };

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

Подскажите как сделать очередь выполнения событий или еще лучше сделать их параллельное вычисление.

Вот нашел пример в интернете: http://usings.ru/2009/06/22/eventpool/

Заранее спасибо.


Теги:


Спасибо:


IvanB

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


Bond: Нужна помощь!

Есть код:

//Событие изменения PnL strategy.PnLChanged += () => { x = x + 1; };

> 
> Когда запускаешь несколько стратегий второе приходящее событие обрывает выполнение действия в скобках и начинает свое, в итоге получается белиберда.
> 
> Подскажите как сделать очередь выполнения событий или еще лучше сделать их параллельное вычисление.
> 
> Вот нашел пример в интернете:
> <http://usings.ru/2009/06/22/eventpool/>
> 
> Заранее спасибо.

В теле обработчика события напишите так:
```csharp

System.Threading.ThreadPool.QueueUserWorkItem((s) => { 
     x = x + 1;
});

это, грубо говоря, через многопоточность.

Либо попробовать через блокировку:

lock()
{

}

http://msdn.microsoft.com/ru-ru/library/c5kehkcz.aspx

Спасибо:

Bond

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


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

Спасибо:

IvanB

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


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

Можно на код взглянуть, где этот кусок используется?

Спасибо:

Bond

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



while (countVariation != CountAllReadyStrategy - 1)
            {
                while (CountAtOnceTrader != CountReadyStrategy - 1)
                {
                    //Перебираем параметры стратегий в циклах
                    for (int i = end_i; i < lenghtArrayFirstParametr; i++)
                    {
                        if (CountAddTrader == CountAtOnceTrader) break;                       

                        for (int j = end_j; j < lenghtArraySecondParametr; j++)
                        {
                            //Создаем шлюз для эмуляции
                            var trader = new EmulationTrader(new[] {security}, new[] {portfolio}, storageRegistry)
                                {
                                    StorageRegistry = storageRegistry,
                                    UseCandlesTimeFrame = timeFrame,
                                };

                            //Соединяемся с трейдером и запускаем экспорт, чтобы инициализировать переданными инструментами и портфелями необходимые свойства EmulationTrader
                            trader.Connect();
                            trader.StartExport();

                            //Создаем менеджера свечек
                            var candleManager = new CandleManager(trader);
                            candleManager.Start(series);

                            //Создаем торговую стратегию
                            var strategy = new SmaStrategy(series, new SimpleMovingAverage {Length = arrayFirstParametr[i]}, new SimpleMovingAverage {Length = arraySecondParametr[j]})
                                {
                                    Volume = 1,
                                    Security = security,
                                    Portfolio = portfolio,
                                    Trader = trader,
                                };

                            //Событие изменения стратегии
                            trader.StateChanged += (oldState, newState) =>
                            {
                                if (trader.State == EmulationStates.Started)
                                {
                                    //Запускаем стратегию когда эмулятор запустился
                                    strategy.Start();
                                }

                                //Если стратегия остановлена
                                if (trader.State == EmulationStates.Stopped)
                                {
                                    //Console.WriteLine("Стратегия #{3} ({1}, {2}) Time: {0}.", DateTime.Now - afterDateTime, strategy.LongSma.Length, strategy.ShortSma.Length, CountAllReadyStrategy);

                                    Console.WriteLine("Стратегия #{3} ({1}, {2}) Time: {0}.", DateTime.Now - afterDateTime, strategy.LongSma.Length, strategy.ShortSma.Length, CountAllReadyStrategy);
                                    Console.WriteLine("Max знач. прибыли: {0}; Росла {1}% времени", arrayMaxPnL[strategy.LongSma.Length, strategy.ShortSma.Length], arrayPnLUpPer[strategy.LongSma.Length, strategy.ShortSma.Length]);
                                    Console.WriteLine("Min знач. прибыли: {0}; Падала {1}% времени", arrayMinPnL[strategy.LongSma.Length, strategy.ShortSma.Length], 100 - arrayPnLUpPer[strategy.LongSma.Length, strategy.ShortSma.Length]);
                                    Console.WriteLine("Последнее значение: {0}.", arrayPnLAfter[strategy.LongSma.Length, strategy.ShortSma.Length]);
                                    
                                    afterDateTime = DateTime.Now;

                                    CountReadyStrategy = CountReadyStrategy + 1;
                                    CountAllReadyStrategy = CountAllReadyStrategy + 1;

                                    trader.Stop();
                                    trader.Dispose();
                                    trader = null;
                                    strategy.Stop();
                                    strategy.Dispose();
                                    strategy = null;
                                    candleManager.Dispose();
                                    candleManager = null;

                                    if (CountAllReadyStrategy == countVariation + 1) Console.WriteLine("Тестирование закончено за {0}!", (DateTime.Now - startEmulationTime).ToString().Remove(11));
                                }
                            };

                            //System.Threading.ThreadPool.QueueUserWorkItem()
                            
                            //Событие изменения PnL
                            strategy.PnLChanged += () =>
                            {
                                //arrayPnLCollect[strategy.LongSma.Length, strategy.ShortSma.Length].Add(new Tuple<DateTime, double>(strategy.GetMarketTime(), (double)strategy.PnL));


                                int _i = strategy.LongSma.Length;
                                int _j = strategy.ShortSma.Length;

                                if ((double)strategy.PnL > arrayMaxPnL[_i, _j]) arrayMaxPnL[_i, _j] = (double)strategy.PnL;
                                if ((double)strategy.PnL < arrayMinPnL[_i, _j]) arrayMinPnL[_i, _j] = (double)strategy.PnL;

                                if (arrayPnLAfter[_i, _j] < (double)strategy.PnL) arrayPnLUp[_i, _j] = arrayPnLUp[_i, _j] + 1;
                                else arrayPnLDown[_i, _j] = arrayPnLDown[_i, _j] + 1;

                                arrayPnLAfter[_i, _j] = (double)strategy.PnL;

                                arrayPnLUpPer[_i, _j] = (arrayPnLUp[_i, _j] * 100 / (arrayPnLUp[_i, _j] + arrayPnLDown[_i, _j]));

                            };                                                      

                            //Запускаем трейдера
                            trader.Start(startTime, stopTime);

                            CountAddTrader = CountAddTrader + 1;

                            if (j == lenghtArraySecondParametr - 1) end_j = 0;
                           
                            if (CountAddTrader == CountAtOnceTrader)
                            {
                                end_j = j + 1;
                                end_i = i;
                                break;
                            }
                        }

                        if (end_j == lenghtArraySecondParametr)
                        {
                            end_i = i + 1;
                            end_j = 0;
                        }

                    }
                }

                CountReadyStrategy = 1;
                CountAddTrader = 0;

                Console.WriteLine("-----------------------------------------------");
            }

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

П.С. Использую циклы по условию для ожилания завершения стратегии и потом только запускаю новую партию стратегий. Есть ли другие более производительные варианты реализации кроме как While? Или и так нормально?

Спасибо:

Bond

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


Могу всю программу на почту сбросить.

Спасибо:

IvanB

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


Bond:


while (countVariation != CountAllReadyStrategy - 1)
            {
                while (CountAtOnceTrader != CountReadyStrategy - 1)
                {
                    //Перебираем параметры стратегий в циклах
                    for (int i = end_i; i < lenghtArrayFirstParametr; i++)
                    {
                        if (CountAddTrader == CountAtOnceTrader) break;                       

                        for (int j = end_j; j < lenghtArraySecondParametr; j++)
                        {
                            //Создаем шлюз для эмуляции
                            var trader = new EmulationTrader(new[] {security}, new[] {portfolio}, storageRegistry)
                                {
                                    StorageRegistry = storageRegistry,
                                    UseCandlesTimeFrame = timeFrame,
                                };

                            //Соединяемся с трейдером и запускаем экспорт, чтобы инициализировать переданными инструментами и портфелями необходимые свойства EmulationTrader
                            trader.Connect();
                            trader.StartExport();

                            //Создаем менеджера свечек
                            var candleManager = new CandleManager(trader);
                            candleManager.Start(series);

                            //Создаем торговую стратегию
                            var strategy = new SmaStrategy(series, new SimpleMovingAverage {Length = arrayFirstParametr[i]}, new SimpleMovingAverage {Length = arraySecondParametr[j]})
                                {
                                    Volume = 1,
                                    Security = security,
                                    Portfolio = portfolio,
                                    Trader = trader,
                                };

                            //Событие изменения стратегии
                            trader.StateChanged += (oldState, newState) =>
                            {
                                if (trader.State == EmulationStates.Started)
                                {
                                    //Запускаем стратегию когда эмулятор запустился
                                    strategy.Start();
                                }

                                //Если стратегия остановлена
                                if (trader.State == EmulationStates.Stopped)
                                {
                                    //Console.WriteLine("Стратегия #{3} ({1}, {2}) Time: {0}.", DateTime.Now - afterDateTime, strategy.LongSma.Length, strategy.ShortSma.Length, CountAllReadyStrategy);

                                    Console.WriteLine("Стратегия #{3} ({1}, {2}) Time: {0}.", DateTime.Now - afterDateTime, strategy.LongSma.Length, strategy.ShortSma.Length, CountAllReadyStrategy);
                                    Console.WriteLine("Max знач. прибыли: {0}; Росла {1}% времени", arrayMaxPnL[strategy.LongSma.Length, strategy.ShortSma.Length], arrayPnLUpPer[strategy.LongSma.Length, strategy.ShortSma.Length]);
                                    Console.WriteLine("Min знач. прибыли: {0}; Падала {1}% времени", arrayMinPnL[strategy.LongSma.Length, strategy.ShortSma.Length], 100 - arrayPnLUpPer[strategy.LongSma.Length, strategy.ShortSma.Length]);
                                    Console.WriteLine("Последнее значение: {0}.", arrayPnLAfter[strategy.LongSma.Length, strategy.ShortSma.Length]);
                                    
                                    afterDateTime = DateTime.Now;

                                    CountReadyStrategy = CountReadyStrategy + 1;
                                    CountAllReadyStrategy = CountAllReadyStrategy + 1;

                                    trader.Stop();
                                    trader.Dispose();
                                    trader = null;
                                    strategy.Stop();
                                    strategy.Dispose();
                                    strategy = null;
                                    candleManager.Dispose();
                                    candleManager = null;

                                    if (CountAllReadyStrategy == countVariation + 1) Console.WriteLine("Тестирование закончено за {0}!", (DateTime.Now - startEmulationTime).ToString().Remove(11));
                                }
                            };

                            //System.Threading.ThreadPool.QueueUserWorkItem()
                            
                            //Событие изменения PnL
                            strategy.PnLChanged += () =>
                            {
                                //arrayPnLCollect[strategy.LongSma.Length, strategy.ShortSma.Length].Add(new Tuple<DateTime, double>(strategy.GetMarketTime(), (double)strategy.PnL));


                                int _i = strategy.LongSma.Length;
                                int _j = strategy.ShortSma.Length;

                                if ((double)strategy.PnL > arrayMaxPnL[_i, _j]) arrayMaxPnL[_i, _j] = (double)strategy.PnL;
                                if ((double)strategy.PnL < arrayMinPnL[_i, _j]) arrayMinPnL[_i, _j] = (double)strategy.PnL;

                                if (arrayPnLAfter[_i, _j] < (double)strategy.PnL) arrayPnLUp[_i, _j] = arrayPnLUp[_i, _j] + 1;
                                else arrayPnLDown[_i, _j] = arrayPnLDown[_i, _j] + 1;

                                arrayPnLAfter[_i, _j] = (double)strategy.PnL;

                                arrayPnLUpPer[_i, _j] = (arrayPnLUp[_i, _j] * 100 / (arrayPnLUp[_i, _j] + arrayPnLDown[_i, _j]));

                            };                                                      

                            //Запускаем трейдера
                            trader.Start(startTime, stopTime);

                            CountAddTrader = CountAddTrader + 1;

                            if (j == lenghtArraySecondParametr - 1) end_j = 0;
                           
                            if (CountAddTrader == CountAtOnceTrader)
                            {
                                end_j = j + 1;
                                end_i = i;
                                break;
                            }
                        }

                        if (end_j == lenghtArraySecondParametr)
                        {
                            end_i = i + 1;
                            end_j = 0;
                        }

                    }
                }

                CountReadyStrategy = 1;
                CountAddTrader = 0;

                Console.WriteLine("-----------------------------------------------");
            }

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

П.С. Использую циклы по условию для ожилания завершения стратегии и потом только запускаю новую партию стратегий. Есть ли другие более производительные варианты реализации кроме как While? Или и так нормально? С циклом все в порядке. По поводу подсчета прибыли-убытка. Нужно вынести код вычисления в отдельный метод, примерно так:


private void PnLCalc(MyStrategy strategy)
        {
            int _i = strategy.LongSma.Length;
            int _j = strategy.ShortSma.Length;

            if ((double)strategy.PnL > arrayMaxPnL[_i, _j]) arrayMaxPnL[_i, _j] = (double)strategy.PnL;
            if ((double)strategy.PnL < arrayMinPnL[_i, _j]) arrayMinPnL[_i, _j] = (double)strategy.PnL;

            if (arrayPnLAfter[_i, _j] < (double)strategy.PnL) arrayPnLUp[_i, _j] = arrayPnLUp[_i, _j] + 1;
            else arrayPnLDown[_i, _j] = arrayPnLDown[_i, _j] + 1;

            arrayPnLAfter[_i, _j] = (double)strategy.PnL;

            arrayPnLUpPer[_i, _j] = (arrayPnLUp[_i, _j] * 100 / (arrayPnLUp[_i, _j] + arrayPnLDown[_i, _j]));
        }

И далее его используем так:


//Событие изменения PnL
                            strategy.PnLChanged += () =>
                            {
                                System.Threading.ThreadPool.QueueUserWorkItem((s) =>
                                 {
                                     PnLCalc((MyStrategy)s);
                                          }, strategy);
                            }

Спасибо:

Bond

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


Попробовал. Не помогло. Тот же фарш из потоков. Прям генератор случайных чисел получился))) Поменял код. Решил оставить только одну подписку на события. И забираю коллекцию trader.MyTrades. Потом буду ее потрошить.


//Событие изменения стратегии
                            trader.StateChanged += (oldState, newState) =>
                            {
                                if (trader.State == EmulationStates.Started)
                                {
                                    //Запускаем стратегию когда эмулятор запустился
                                    strategy.Start();
                                }

                                //Если стратегия остановлена
                                if (trader.State == EmulationStates.Stopped)
                                {
                                    double count = 0;

                                    arrayMyTrades[strategy.LongSma.Length, strategy.ShortSma.Length] = trader.MyTrades;

                                    foreach (var myTrade in arrayMyTrades[strategy.LongSma.Length, strategy.ShortSma.Length])
                                    {
                                        count = count + 1;
                                    }

                                    Console.WriteLine("Стратегия #{3} ({1}, {2}). Время: {0} \nКоличество сделок: {4}.", DateTime.Now - afterDateTime, strategy.LongSma.Length, strategy.ShortSma.Length, CountAllReadyStrategy, count);
                                    
                                    afterDateTime = DateTime.Now;

                                    CountReadyStrategy = CountReadyStrategy + 1;
                                    CountAllReadyStrategy = CountAllReadyStrategy + 1;

                                    trader.Stop();
                                    trader.Dispose();
                                    trader = null;
                                    strategy.Stop();
                                    strategy.Dispose();
                                    strategy = null;
                                    candleManager.Dispose();
                                    candleManager = null;

                                    if (CountAllReadyStrategy == countVariation + 1) Console.WriteLine("Тестирование закончено за {0}!", (DateTime.Now - startEmulationTime).ToString().Remove(11));
                                }
                            };

Попробовал с этой подпиской. Вообще вылетает.


trader.StateChanged += (oldState, newState) =>
                            {
                                System.Threading.ThreadPool.QueueUserWorkItem((s =>
                                {
                                    PnLCalc((EmulationTrader)s, strategy, arrayMyTrades, CountReadyStrategy, CountAllReadyStrategy, countVariation);
                                }), trader);
                            };


private static void PnLCalc(EmulationTrader trader, SmaStrategy strategy, IEnumerable<MyTrade>[,] arrayMyTrades, int CountReadyStrategy, int CountAllReadyStrategy, int countVariation)
        {
            double count = 0;

            arrayMyTrades[strategy.LongSma.Length, strategy.ShortSma.Length] = trader.MyTrades;

            foreach (var myTrade in arrayMyTrades[strategy.LongSma.Length, strategy.ShortSma.Length])
            {
                count = count + 1;
            }

            Console.WriteLine("Стратегия # ({1}, {2}). Время: {0} \nКоличество сделок: {3}.", DateTime.Now /*- afterDateTime*/, strategy.LongSma.Length, strategy.ShortSma.Length/*, CountAllReadyStrategy*/, count);

            //afterDateTime = DateTime.Now;

            CountReadyStrategy = CountReadyStrategy + 1;
            CountAllReadyStrategy = CountAllReadyStrategy + 1;

            trader.Stop();
            trader.Dispose();
            trader = null;
            strategy.Stop();
            strategy.Dispose();
            strategy = null;
            //candleManager.Dispose();
            //candleManager = null;

            if (CountAllReadyStrategy == countVariation + 1) Console.WriteLine("Тестирование закончено за {0}!", (DateTime.Now /*- startEmulationTime*/).ToString().Remove(11));

        }

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

П.С. Вылетает ошибка, что IEnumerable<MyTrade> нельзя сериализовать. "Тип "Ecng.ComponentModel.NotifiableObject" в сборке "Ecng.ComponentModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" не помечен как сериализуемый." Конвертировать в другую коллекцию? Или можно проще решить?

Спасибо:

IvanB

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


Bond: Попробовал. Не помогло. Тот же фарш из потоков. Прям генератор случайных чисел получился))) Поменял код. Решил оставить только одну подписку на события. И забираю коллекцию trader.MyTrades. Потом буду ее потрошить.


//Событие изменения стратегии
                            trader.StateChanged += (oldState, newState) =>
                            {
                                if (trader.State == EmulationStates.Started)
                                {
                                    //Запускаем стратегию когда эмулятор запустился
                                    strategy.Start();
                                }

                                //Если стратегия остановлена
                                if (trader.State == EmulationStates.Stopped)
                                {
                                    double count = 0;

                                    arrayMyTrades[strategy.LongSma.Length, strategy.ShortSma.Length] = trader.MyTrades;

                                    foreach (var myTrade in arrayMyTrades[strategy.LongSma.Length, strategy.ShortSma.Length])
                                    {
                                        count = count + 1;
                                    }

                                    Console.WriteLine("Стратегия #{3} ({1}, {2}). Время: {0} \nКоличество сделок: {4}.", DateTime.Now - afterDateTime, strategy.LongSma.Length, strategy.ShortSma.Length, CountAllReadyStrategy, count);
                                    
                                    afterDateTime = DateTime.Now;

                                    CountReadyStrategy = CountReadyStrategy + 1;
                                    CountAllReadyStrategy = CountAllReadyStrategy + 1;

                                    trader.Stop();
                                    trader.Dispose();
                                    trader = null;
                                    strategy.Stop();
                                    strategy.Dispose();
                                    strategy = null;
                                    candleManager.Dispose();
                                    candleManager = null;

                                    if (CountAllReadyStrategy == countVariation + 1) Console.WriteLine("Тестирование закончено за {0}!", (DateTime.Now - startEmulationTime).ToString().Remove(11));
                                }
                            };

Попробовал с этой подпиской. Вообще вылетает.


trader.StateChanged += (oldState, newState) =>
                            {
                                System.Threading.ThreadPool.QueueUserWorkItem((s =>
                                {
                                    PnLCalc((EmulationTrader)s, strategy, arrayMyTrades, CountReadyStrategy, CountAllReadyStrategy, countVariation);
                                }), trader);
                            };


private static void PnLCalc(EmulationTrader trader, SmaStrategy strategy, IEnumerable<MyTrade>[,] arrayMyTrades, int CountReadyStrategy, int CountAllReadyStrategy, int countVariation)
        {
            double count = 0;

            arrayMyTrades[strategy.LongSma.Length, strategy.ShortSma.Length] = trader.MyTrades;

            foreach (var myTrade in arrayMyTrades[strategy.LongSma.Length, strategy.ShortSma.Length])
            {
                count = count + 1;
            }

            Console.WriteLine("Стратегия # ({1}, {2}). Время: {0} \nКоличество сделок: {3}.", DateTime.Now /*- afterDateTime*/, strategy.LongSma.Length, strategy.ShortSma.Length/*, CountAllReadyStrategy*/, count);

            //afterDateTime = DateTime.Now;

            CountReadyStrategy = CountReadyStrategy + 1;
            CountAllReadyStrategy = CountAllReadyStrategy + 1;

            trader.Stop();
            trader.Dispose();
            trader = null;
            strategy.Stop();
            strategy.Dispose();
            strategy = null;
            //candleManager.Dispose();
            //candleManager = null;

            if (CountAllReadyStrategy == countVariation + 1) Console.WriteLine("Тестирование закончено за {0}!", (DateTime.Now /*- startEmulationTime*/).ToString().Remove(11));

        }

С событиями заметил, что может только дойти до фигурной скобки и даже не зайти в блок операторов и сразу смениться на новое пришедшее событие. Даже не знаю, как подойти. Может реализовать очередь событий из того примера в интернете, который я указал в первом сообщении ветки? Тот вариант что я рекомендовал, он должен работать, он работает в многопоточном режиме, т.е. не гарантируется, что порядок обработки вызываемых обработчиков будет соответствовать порядку вызовов. Вот Вы и думаете что получается ерунда. Если хотите работать с многопоточностью, то соответственно, может понадобиться и переделывать логику, которая была реализована как линейная. П.С. Вылетает ошибка, что IEnumerable<MyTrade> нельзя сериализовать. "Тип "Ecng.ComponentModel.NotifiableObject" в сборке "Ecng.ComponentModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" не помечен как сериализуемый." Конвертировать в другую коллекцию? Или можно проще решить? То, что Вы передаете в PnLCalc, я рекомендую объединить в один экземпляр, некоторого класса (нужно создать класс) и этот экземпляр передавать в пул: System.Threading.ThreadPool.QueueUserWorkItem((s => ), <экземпляр класса с параметрами, объектами>) и этот экземпляр Вы можете использовать внутри пула, т.е. он передается в тело в виде аргумента: System.Threading.ThreadPool.QueueUserWorkItem((s => { <используем s, предварительно явно преобразовав его к типу вашего класса> }), <экземпляр класса с параметрами, объектами>)

Спасибо:


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

loading
clippy