IvanB
|
Date: 11/12/2013
Bond Нужна помощь! Есть код: Code
//Событие изменения PnL
strategy.PnLChanged += () =>
{
x = x + 1;
};
Когда запускаешь несколько стратегий второе приходящее событие обрывает выполнение действия в скобках и начинает свое, в итоге получается белиберда. Подскажите как сделать очередь выполнения событий или еще лучше сделать их параллельное вычисление. Вот нашел пример в интернете: http://usings.ru/2009/06/22/eventpool/Заранее спасибо. В теле обработчика события напишите так: Code
System.Threading.ThreadPool.QueueUserWorkItem((s) => {
x = x + 1;
});
это, грубо говоря, через многопоточность. Либо попробовать через блокировку: http://msdn.microsoft.co...ru/library/c5kehkcz.aspx
|
|
Thanks:
|
|
|
|
|
Bond
|
Date: 11/12/2013
Lock не работает. Перебрал все возможные варианты. Может потому что метод только один и он статичный? В общем не пошло, а первый вариант пока запустить не получается.
|
|
Thanks:
|
|
|
|
|
IvanB
|
Date: 11/12/2013
Bond Lock не работает. Перебрал все возможные варианты. Может потому что метод только один и он статичный? В общем не пошло, а первый вариант пока запустить не получается. Можно на код взглянуть, где этот кусок используется?
|
|
Thanks:
|
|
|
|
|
Bond
|
Date: 11/12/2013
|
|
|
|
Code
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? Или и так нормально?
|
|
Thanks:
|
|
|
|
|
Bond
|
Date: 11/12/2013
Могу всю программу на почту сбросить.
|
|
Thanks:
|
|
|
|
|
IvanB
|
Date: 11/12/2013
|
|
|
|
Bond Code
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? Или и так нормально? С циклом все в порядке. По поводу подсчета прибыли-убытка. Нужно вынести код вычисления в отдельный метод, примерно так: Code
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]));
}
И далее его используем так: Code
//Событие изменения PnL
strategy.PnLChanged += () =>
{
System.Threading.ThreadPool.QueueUserWorkItem((s) =>
{
PnLCalc((MyStrategy)s);
}, strategy);
}
|
|
Thanks:
|
|
|
|
|
Bond
|
Date: 11/12/2013
|
|
|
|
Попробовал. Не помогло. Тот же фарш из потоков. Прям генератор случайных чисел получился))) Поменял код. Решил оставить только одну подписку на события. И забираю коллекцию trader.MyTrades. Потом буду ее потрошить. Code
//Событие изменения стратегии
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));
}
};
Попробовал с этой подпиской. Вообще вылетает. Code
trader.StateChanged += (oldState, newState) =>
{
System.Threading.ThreadPool.QueueUserWorkItem((s =>
{
PnLCalc((EmulationTrader)s, strategy, arrayMyTrades, CountReadyStrategy, CountAllReadyStrategy, countVariation);
}), trader);
};
Code
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" не помечен как сериализуемый." Конвертировать в другую коллекцию? Или можно проще решить?
|
|
Thanks:
|
|
|
|
|
IvanB
|
Date: 11/13/2013
|
|
|
|
Bond Попробовал. Не помогло. Тот же фарш из потоков. Прям генератор случайных чисел получился))) Поменял код. Решил оставить только одну подписку на события. И забираю коллекцию trader.MyTrades. Потом буду ее потрошить. Code
//Событие изменения стратегии
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));
}
};
Попробовал с этой подпиской. Вообще вылетает. Code
trader.StateChanged += (oldState, newState) =>
{
System.Threading.ThreadPool.QueueUserWorkItem((s =>
{
PnLCalc((EmulationTrader)s, strategy, arrayMyTrades, CountReadyStrategy, CountAllReadyStrategy, countVariation);
}), trader);
};
Code
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));
}
С событиями заметил, что может только дойти до фигурной скобки и даже не зайти в блок операторов и сразу смениться на новое пришедшее событие. Даже не знаю, как подойти. Может реализовать очередь событий из того примера в интернете, который я указал в первом сообщении ветки? Тот вариант что я рекомендовал, он должен работать, он работает в многопоточном режиме, т.е. не гарантируется, что порядок обработки вызываемых обработчиков будет соответствовать порядку вызовов. Вот Вы и думаете что получается ерунда. Если хотите работать с многопоточностью, то соответственно, может понадобиться и переделывать логику, которая была реализована как линейная. Quote: П.С. Вылетает ошибка, что 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, предварительно явно преобразовав его к типу вашего класса> }), <экземпляр класса с параметрами, объектами>)
|
|
Thanks:
|
|
|
|