← Atrás

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

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

Есть код:


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

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

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

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

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

¿Le resultó útil este tema?

Compartir tema

Comentarios (8)

Iniciar sesión o Crear cuenta, Inicie sesión o regístrese para dejar un comentario

IvanB
IvanB

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
Bond Autor

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

IvanB
IvanB

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

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

Bond
Bond Autor

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? Или и так нормально?

IvanB
IvanB

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
Bond Autor

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

Bond
Bond Autor

Попробовал. Не помогло. Тот же фарш из потоков. Прям генератор случайных чисел получился))) Поменял код. Решил оставить только одну подписку на события. И забираю коллекцию 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
IvanB

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, предварительно явно преобразовав его к типу вашего класса> }), <экземпляр класса с параметрами, объектами>)