Mikhail Sukhov Поправил утилиту, чтобы поддерживала новый формат.
Утилитой кто-то пользуется? Или ОЛ уже интересен только единицам?
Здравствуйте. Я пользуюсь утилитой. Огромное за нее спасибо - очень полезная вещь. Но я обнаружил, что утилита неправильно собирает стакан.
Как я это обнаружил. Я добавил в утилиту функцию подсчета суммарного объема стакана по бидам и аскам (глубина стакана 50) и сохранения суммарного объема, а также лучшей цены в файл.
Т.е. я добавил после строки 509 метода ConvertFile файла MainWindow.xaml.cs следующий код (под спойлером):
Код
var bestBidQuote = builder.Depth.GetBestBid();
decimal BestBidPrice = (bestBidQuote == null) ? 0 : bestBidQuote.Price;
decimal BidVolume = 0;
var quotes = builder.Depth.Bids.Take(orderBookMaxDepth).ToArray();
foreach (var item in quotes)
{
BidVolume += item.Volume;
}
var bestAskQuote = builder.Depth.GetBestAsk();
decimal BestAskPrice = (bestAskQuote == null) ? 0 : bestAskQuote.Price;
decimal AskVolume = 0;
var quotes = builder.Depth.Asks.Take(orderBookMaxDepth).ToArray();
foreach (var item in quotes)
{
AskVolume += item.Volume;
}
... сохраняем BestBidPrice, BidVolume, BestAskPrice, AskVolume в файл ...
Далее я протестировал утилиту на исторических данных фьючерса на индекс РТС (RTS-3.19), скаченных с сайта цериха и сравнил полученные объемы стакана с объемами, которые выводит QScalp на этих же исторических данных.
Результаты отличались: объемы, рассчитанные утилитой на порядок превышали объемы QScalp. Я пришел к выводу, что проблема в коде в строках 438 - 441 метода ConvertFile файла MainWindow.xaml.cs:
Код
else if (ol.Flags.Contains(OrdLogFlags.Moved))
{
status |= 0x100000;
}
По совету пользователя vk37 от 26.01.2016 я установил OrderState = Done для заявок с флагом Moved:
Код
else if (ol.Flags.Contains(OrdLogFlags.Moved))
{
status |= 0x100000;
msg.OrderState = OrderStates.Done;
}
И утилита стала считать объемы стакана правильно. Скажите пожалуйста, насколько мое решение верно?
Пользователь vk37 в своем сообщении от 26.01.2016 вообще советует устанавливать OrderState = Done для всех заявок из ордерлога, кроме добавляемых заявок (с флагом Add). Скажите пожалуйста, насколько его совет правильный?
Но это еще не все. Когда я стал сравнивать лучшие цены и суммарные объемы стакана после вечернего клиринга с данными, выводимыми QScalp, то обнаружил, что они отличаются: объемы рассчитанные утилитой в разы превышали объемы QScalp.
Я пришел к выводу, что утилита при сборке стакана некорректно обрабатывает вечерний клиринг, фактически не очищая стакан. Вот пример результата работы утилиты в вечерний клиринг:
1) Перед вечерним клирингом (время 18:44:59.926) суммарный объем по бидам = 2186, по аскам = 1889.
2) При обработке всех последующих заявок из ордерлога в период вечернего клиринга получаем пустой стакан (список котировок по бидам и аскам, а также лучшие цены пустые).
3) Начало вечерней сессии (время 19:0:0.347). Поступила заявка, в результате которой получаем лучшую цену по аскам, а суммарный объем по аскам = 2612, что фактически составляет суммарный объем до клиринга плюс объем заявок, поступивших в период вечернего клиринга.
4) Аналогично с бидами: время 19:0:0.505, поступает заявка, в результате которой получаем лучшую цену по бидам, а суммарный объем по бидам = 2536, что фактически составляет суммарный объем до клиринга плюс объем заявок, поступивших в период вечернего клиринга.
Я решил очищать стакан в вечерний клиринг просто создавая новый экземпляр builder:
Код
builder = new PlazaOrderLogMarketDepthBuilder(securityId);
Теперь результаты утилиты и QScalp совпадают.
Скажите пожалуйста, насколько мое решение верно и каким еще образом можно очищать стакан (мой метод мне кажется слишком грубым).