← Zurück

Конвертация исторических файлов QScalp в формат StockSharp

Привет всем алготрейдерам!

Хочу поделиться своим решение для тестирования скальперских и ХФТ стратегий. Долгое время я использую замечательный привод Морошкина (бесплатную версию 🙂 ). И недавно решил автоматизировать несколько стратегий на базе StockSharp.

Но для этого нужны исторические данные, в частности стаканы. У StockSharp есть программа Гидра, которая по идее позволяет качать все необходимое, но ее нужно держать постоянно включенной. Для меня это не вариант, так как я постоянно занят, и интернет не всегда стабильный.

Но недавно я узнал, что QScalp сам пишет историю и бесплатно ее выкладывает через брокера IT Invest.

В итоге, я написал конвертор данных QScalp в формат StockSharp!

Просто установите программу и скачайте исторические данные формата QSH для QScalp по одной из ссылок ниже

http://www.itinvest.ru/software/spo/qscalp/history/

ftp://athistory.zerich.com/

Теперь осталось только указать в конвертере путь к скаченным файлам и к папке хранения исторических данных StockSharp, и нажать кнопку “Запустить”!

Вуаля, теперь у вас есть высококачественные исторические данные для тестирования своих стратегий!

PS Торопитесь пока бесплатно ;))

PPS Шутка))

Всем удачной торговли!

Присоединиться и редактировать код можно по https://github.com/stocksharp/Qsh2Bin

скомпилированную программу по https://github.com/StockSharp/Qsh2Bin/releases

War dieses Thema hilfreich?

Thema teilen

Kommentare (70)

Anmelden oder Konto erstellen, Melden Sie sich an oder registrieren Sie sich, um einen Kommentar zu hinterlassen

Bond
Bond

Исторические данные можно скачать только за один день? А за период времени? И какая глубина этих исторических данных?

nuan
nuan

Собственно можно залить уже установленную версию, т.к. у меня при установки вылетает ошибка... Что-то то там с манифестом.

Mikhail Sukhov
Mikhail Sukhov

nuan: Что-то то там с манифестом.

Это значит, что не в программе ошибка. Манифест - это ОС.

nuan
nuan

СВЕДЕНИЯ О ВЕРСИИ ПЛАТФОРМЫ Windows : 6.1.7601.65536 (Win32NT) Common Language Runtime : 4.0.30319.18034 System.Deployment.dll : 4.0.30319.17929 built by: FX45RTMREL clr.dll : 4.0.30319.18034 built by: FX45RTMGDR dfdll.dll : 4.0.30319.17929 built by: FX45RTMREL dfshim.dll : 4.0.31106.0 (Main.031106-0000)

ИСТОЧНИКИ URL-адрес развертывания : file:///C:/Users/Nuan/Desktop/data/publish/Qsh2Bin.application

УДОСТОВЕРЕНИЯ Удостоверение развертывания : Qsh2Bin.application, Version=1.0.0.0, Culture=neutral, PublicKeyToken=58b400c5ccdd6861, processorArchitecture=msil

СВОДКА ПРИЛОЖЕНИЯ

  • Устанавливаемое приложение.

СВОДКА ОШИБОК Ниже приводится сводка ошибок, сведения об этих ошибках перечислены далее в журнале.

  • В результате активизации C:\Users\Nuan\Desktop\data\publish\Qsh2Bin.application произошла ошибка с исключением. Определены следующие сообщения о сбоях:
    • Исключение чтения манифеста из file:///C:/Users/Nuan/Desktop/data/publish/Application%20Files/Qsh2Bin_1_0_0_0/Qsh2Bin.exe.manifest: возможно, манифест неправильный или файл не может быть открыт.
    • Манифест приложения семантически неправилен.
    • Файл значка, указанный в манифесте приложения, неправильный.

СВОДКА СБОЯ ТРАНЗАКЦИИ СОХРАНЕНИЯ КОМПОНЕНТА Не определена никакая ошибка транзакции.

ПРЕДУПРЕЖДЕНИЯ Во время этой операции предупреждения не выводились.

СОСТОЯНИЕ ВЫПОЛНЕНИЯ ОПЕРАЦИИ

  • [17.10.2013 22:51:47] : Активация C:\Users\Nuan\Desktop\data\publish\Qsh2Bin.application начата.
  • [17.10.2013 22:51:53] : Обработка манифеста развертывания успешно завершена.
  • [17.10.2013 22:51:53] : Начата установка приложения.

СВЕДЕНИЯ ОБ ОШИБКЕ Во время выполнения этой операции обнаружены следующие ошибки.

  • [17.10.2013 22:51:53] System.Deployment.Application.InvalidDeploymentException (ManifestParse)
    • Исключение чтения манифеста из file:///C:/Users/Nuan/Desktop/data/publish/Application%20Files/Qsh2Bin_1_0_0_0/Qsh2Bin.exe.manifest: возможно, манифест неправильный или файл не может быть открыт.
    • Источник: System.Deployment
    • Запись изменений стека: в System.Deployment.Application.ManifestReader.FromDocument(String localPath, ManifestType manifestType, Uri sourceUri) в System.Deployment.Application.DownloadManager.DownloadApplicationManifest(AssemblyManifest deploymentManifest, String targetDir, Uri deploymentUri, IDownloadNotification notification, DownloadOptions options, Uri& appSourceUri, String& appManifestPath) в System.Deployment.Application.DownloadManager.DownloadApplicationManifest(AssemblyManifest deploymentManifest, String targetDir, Uri deploymentUri, Uri& appSourceUri, String& appManifestPath) в System.Deployment.Application.ApplicationActivator.DownloadApplication(SubscriptionState subState, ActivationDescription actDesc, Int64 transactionId, TempDirectory& downloadTemp) в System.Deployment.Application.ApplicationActivator.InstallApplication(SubscriptionState& subState, ActivationDescription actDesc) в System.Deployment.Application.ApplicationActivator.PerformDeploymentActivation(Uri activationUri, Boolean isShortcut, String textualSubId, String deploymentProviderUrlFromExtension, BrowserSettings browserSettings, String& errorPageUrl) в System.Deployment.Application.ApplicationActivator.ActivateDeploymentWorker(Object state) --- Внутреннее исключение --- System.Deployment.Application.InvalidDeploymentException (ManifestSemanticValidation)
    • Манифест приложения семантически неправилен.
    • Источник: System.Deployment
    • Запись изменений стека: в System.Deployment.Application.Manifest.AssemblyManifest.ValidateSemanticsForApplicationRole() в System.Deployment.Application.Manifest.AssemblyManifest.ValidateSemantics(ManifestType manifestType) в System.Deployment.Application.ManifestReader.FromDocument(String localPath, ManifestType manifestType, Uri sourceUri) --- Внутреннее исключение --- System.Deployment.Application.InvalidDeploymentException (InvalidManifest)
    • Файл значка, указанный в манифесте приложения, неправильный.
    • Источник: System.Deployment
    • Запись изменений стека: в System.Deployment.Application.Manifest.AssemblyManifest.ValidateSemanticsForApplicationRole()

СВЕДЕНИЯ О ТРАНЗАКЦИИ СОХРАНЕНИЯ КОМПОНЕНТА Нет доступных сведений о транзакции.

Mikhail Sukhov
Mikhail Sukhov

Типа мне разбираться?😂 Гуглите.

nuan
nuan

дык я и прошу проинсталенную уже ) чтобы и мне не разбираться с установкой )

longtrades
longtrades

Скажите, пожалуйста, какая версия стокшарпа сможет открыть эти архивные файлы ?

А то у меня вобще какая то проблема с доставанием инфы из базы данных: Версия 4.1.19.1 пишу трейды в базу :


                        trader.NewTrades += trades => this.GuiAsync(() =>
                        {
                            var secgroup = trades.GroupBy(x => x.Security);
                            foreach (var sec in secgroup)
                            {
                                if (sec.Key.MinStepSize != 0)
                                {
                                    var tradestorage = storage.GetTradeStorage(sec.Key);
                                    tradestorage.AppendOnlyNew = true;
                                    tradestorage.Save(sec);
                                }
                            }

                        });

Потом пробую дастать трейды из той же базы в той же программе :


            var startTime = new DateTime(2013, 11, 18);
            var stopTime = new DateTime(2013, 11, 20);

            // создаем тестовый инструмент, на котором будет производится тестирование
            var security = new Security
            {
                Id = "RIZ3@FORTS", // по идентификатору инструмента будет искаться папка с историческими маркет данными
                Code = "RIZ3",
                Name = "RTS-12.13",
                MinStepSize = 10,
                MinStepPrice = 6.5m,
                MinPrice = 10,
                MaxPrice = 1000000,
                ExchangeBoard = ExchangeBoard.Forts,
            };

            security.LastTrade = new Trade { Price = 143000 };

            // тестовый портфель
            var portfolio = new Portfolio
            {
                Name = "test account",
                BeginValue = 1000000,
            };

            // создаем шлюз для эмуляции
            // инициализируем настройки (инструмент в истории обновляется раз в секунду)
            var Trader = new EmulationTrader(
                new[] { security },
                new[] { portfolio })
            {
                MarketTimeChangedInterval = TimeSpan.FromMilliseconds(10),
                StorageRegistry = storage,

                // использовать стаканы
                UseMarketDepth = true,

                // использовать свечки
               // UseCandlesTimeFrame = emulationInfo.UseCandleTimeFrame,
            };

            // проверка что стаканы соответствуют сделкам. Улучшает реалистичность тестирования.
            Trader.MarketEmulator.Settings.SyncDepthToTrades = true;

            // сведение сделки в эмуляторе если цена коснулась нашей лимитной заявки. 
            // Если выключено - требуется "прохождение цены сквозь уровень"
            // (более "суровый" режим тестирования.)
            Trader.MarketEmulator.Settings.FillOnTouch = false;

            security.Trader = Trader;

            Trader.RegisterMarketDepth(security);

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

            Trader.Start(startTime, stopTime);

Но почему то в трейдере нет ни одного трейда , они вобще должны там быть или они будут появлятся в процессе тестирования ?

longtrades
longtrades

Проверил версию 4.1.14.1, тоже самое Трейдов нет , Может я что-то не так делаю ?

Trader.RegisterTrades(security); тоже не помогает :(

Mikhail Sukhov
Mikhail Sukhov

longtrades: Проверил версию 4.1.14.1, тоже самое Трейдов нет , Может я что-то не так делаю ?

А что вы вообще делаете?

longtrades
longtrades

Постоянно пишу все новые треды в базу , потом хочу тестировать на этой истории .

risty
risty

вставил в исходники текущую версию API с поддержкой четверной версии qsh файлов (http://www.qscalp.ru/download) http://dropmefiles.com/XqiuN

Mikhail Sukhov
Mikhail Sukhov

risty: вставил в исходники текущую версию API с поддержкой четверной версии qsh файлов (http://www.qscalp.ru/download) http://dropmefiles.com/XqiuN

Залили бы сразу в репозитарий. Потеряется же.

risty
risty

Михаил Сухов:

risty: вставил в исходники текущую версию API с поддержкой четверной версии qsh файлов (http://www.qscalp.ru/download) http://dropmefiles.com/XqiuN

Залили бы сразу в репозитарий. Потеряется же.

не умею )

LiCiSin
LiCiSin

risty:

Михаил Сухов:

risty: вставил в исходники текущую версию API с поддержкой четверной версии qsh файлов (http://www.qscalp.ru/download) http://dropmefiles.com/XqiuN

Залили бы сразу в репозитарий. Потеряется же.

не умею ) ну вот уже потерялись-время ханения вышло.... давай исходники -а я залью.

XMbIPb
XMbIPb

Сейчас история только клиентам ITinvest доступна или вообще прикрыли лавочку?

Mikhail Sukhov
Mikhail Sukhov

У айти абонентка за быть их клиентом?

Церих тоже скоро лавочку прикроет

risty
risty

http://dropmefiles.com/P5alg - перезалил. До гитхаба все никак не добраться (

nikitao
nikitao

А можно перезалить, а то файл уже удален? Спасибо

Mikhail Sukhov
Mikhail Sukhov

Обновил сырцы. Качается так же с Гита. ОЛ от Цериха конвертирует.

M1k3
M1k3

Mikhail Sukhov: Обновил сырцы. Качается так же с Гита. ОЛ от Цериха конвертирует. А можно это все запустить без actipro за 650$? А то что-то не получается. Да и вообще не понятно, аналогов actipro нет для stocksharp в виде telerik или чего-то другого, чтобы не платить так сильно за разработку 1-го приложения, которое может в итоге и не понадобиться? Некоторых отпугивает...

Mikhail Sukhov
Mikhail Sukhov

M1k3: Некоторых отпугивает...

Финансовые рынки - не место для трусов.

Pantov
Pantov

Подскажите, что за ошибка: Имя параметра: item в StockSharp.Algo.OrderLogHelper.GetOrderLogCancelReason(ExecutionMessage item) в f:\develop\StockSharp_436\Algo\OrderLogHelper.cs:строка 128 в StockSharp.Algo.OrderLogMarketDepthBuilder.Update(ExecutionMessage item) в f:\develop\StockSharp_436\Algo\OrderLogMarketDepthBuilder.cs:строка 167 в StockSharp.Algo.Connector.ProcessOrderLogMessage(Security security, ExecutionMessage message) в f:\develop\StockSharp_436\Algo\Connector_ProcessMessage.cs:строка 1047 2015/06/04 19:00:00.126|Error |HistoryEmulationConnector|System.ArgumentException: Строка лога заявок не содержит информацию о причине отмены заявки. Имя параметра: item

В ОЛ сформированного данной программой.

Mikhail Sukhov
Mikhail Sukhov

Pantov: Подскажите, что за ошибка: Имя параметра: item в StockSharp.Algo.OrderLogHelper.GetOrderLogCancelReason(ExecutionMessage item) в f:\develop\StockSharp_436\Algo\OrderLogHelper.cs:строка 128

https://github.com/StockSharp/StockSharp

Mikhail Sukhov
Mikhail Sukhov

Придется переконвертировать ОЛ, если кто уже сделал. Забыл заполнить одно из важных полей https://github.com/AntonySS/Qsh2Bin/commit/ae2470db4092ab93ad69305430058bc473786831

Может быть кто-то выложил сконвертированные файлы, чтобы не заниматься одним и тем же?

vkaliteevsky
vkaliteevsky

Пожалуйста, выложите скомпилированную версию программы!

Mikhail Sukhov
Mikhail Sukhov

vkaliteevsky: Пожалуйста, выложите скомпилированную версию программы!

Выложил

M1k3
M1k3

Mikhail Sukhov:

vkaliteevsky: Пожалуйста, выложите скомпилированную версию программы!

Выложил

А можно попросить у вас прямую ссылку на *.exe?

ionn
ionn

Не работает конвертация, скачал историю с цериха. ордерлог видит в qsh, сохраняет пачками по 1000 записей, но в папке с инструментом в результате только файл orderlog.bin размером 7 килобайт.

Mikhail Sukhov
Mikhail Sukhov

Запустил, проверил, работает.

ionn
ionn

я качал с гитхаба скомпилированную прогу, и сам компилировал из исходников - результат одинаков.

сюда передается массив сообщений: registry.GetOrderLogMessageStorage(security).Save(secData.Item4);

но в файл orderlog.bin ничего не записывается и что там в Save() происходит мне не ведомо... запускал на разных машинах...

Куда смотреть? Где копать?

Mikhail Sukhov
Mikhail Sukhov

ionn: и что там в Save() происходит мне не ведомо...

Куда смотреть? Где копать?

https://github.com/StockSharp/StockSharp/

ionn
ionn

выяснил что в ExecutionMessage не проставляется transactionId, он всегда равен 0. поэтому ничего не сохраняется, если убрать AppendOnlyNew или проставить свой transactionId то всё сохраняется - но по этой истории тестирование все равно не работает, свечки не формируются

хотя qscalp проигрывает скаченные файлы нормально.

Mikhail Sukhov
Mikhail Sukhov

Доработал чуть утилиту. Добавил файл настроек и файл с ранее обработанными файлами (это если экспорт перезапускается, чтобы не конвертировать все заново).

Добавил поддежку CSV формата. У Ку Скальпа есть своя утилита, но она у меня почему-то падает. Плюс она без графического интерфейса, а значит нужно писать скрипт (опять же делать индекс-файл с обработанными файлами).

Ну что, может сейчас уже кто-то решится сделать мини сервер истории с паблик доступом? Может скинутся, и купить Amazon S3? Там есть веб интерфейс и настройка прав доступа (в том числе и публичное использование). За 100GB придется заплатить 36 долларов в год. Этого размера вполне хватит для ОЛ истории.

Я готов оплатить место сам, но администрировать не берусь. Если кто-то все настроит, то давайте туда зальем данные (пока доступ не отрубили).

Pantov
Pantov

Как их истории торгов от ИК «ЦЕРИХ» с помощью Qsh2Bin получить: quotes.bin trades.bin security.bin, а не orderlog.bin?

Спасибо.

Mikhail Sukhov
Mikhail Sukhov

Pantov: Как их истории торгов от ИК «ЦЕРИХ» с помощью Qsh2Bin получить: quotes.bin trades.bin security.bin, а не orderlog.bin?

Спасибо.

Через Гидру.

Pantov
Pantov

Mikhail Sukhov:

Pantov: Как их истории торгов от ИК «ЦЕРИХ» с помощью Qsh2Bin получить: quotes.bin trades.bin security.bin, а не orderlog.bin?

Спасибо.

Через Гидру.

Спасибо. все сделал, но даже в Гидре есть только BIDы и в ОЛ и в конвертированных стаканах. Какие надо учесть ньюансы, что не так?

Mikhail Sukhov
Mikhail Sukhov

Pantov: все сделал, но даже в Гидре есть только BIDы и в ОЛ и в конвертированных стаканах. Какие надо учесть ньюансы, что не так?

https://github.com/StockSharp/Qsh2Bin/commit/8a314f967e918658219d6e44e4d5133b7e9e076f

Хочу к чему ОЛ при таком ДолларРубле...

Pantov
Pantov

Mikhail Sukhov:

Pantov: все сделал, но даже в Гидре есть только BIDы и в ОЛ и в конвертированных стаканах. Какие надо учесть ньюансы, что не так?

https://github.com/StockSharp/Qsh2Bin/commit/8a314f967e918658219d6e44e4d5133b7e9e076f

Хочу к чему ОЛ при таком ДолларРубле...

Все заработало, получил, что хотел, спасибо Михаил. Готов оплатить помощь, скажите куда.

Mikhail Sukhov
Mikhail Sukhov

Pantov: Все заработало, получил, что хотел, спасибо Михаил. Готов оплатить помощь, скажите куда.

Лучше выложите сконвертированное куда-то, чтобы не делать одно и то же всем.

Mikhail Sukhov
Mikhail Sukhov

https://github.com/StockSharp/Qsh2Bin/releases/tag/1.0.4

Фильтр по инструменту. Фикс экспорта в csv.

vk37
vk37

У меня получился несколько иной алгоритм конвертации. Возможно, кому-то окажется полезным:

if (ol.Flags.HasFlag(OrdLogFlags.Add))                           
{
    // Action 1 - заявка добавлена
    msg.OrderState = StockSharpOrderState.Active;
    msg.Action = 1;
}
else if (ol.Flags.HasFlag(OrdLogFlags.Fill))
{
    // Action 2 - заявка сведена в сделку
    msg.OrderState = StockSharpOrderState.Done;
    msg.Action = 2;
}
else
{
    // Action 0 - заявка удалена
    msg.OrderState = StockSharpOrderState.Done;
    msg.Action = 0;
}

if (ol.Flags.HasFlag(OrdLogFlags.NonZeroReplAct))
    msg.ReplAct = -1;

if (ol.Flags.HasFlag(OrdLogFlags.SessIdChanged))
    msg.SessId = -1;

var status = 0;

if (ol.Flags.HasFlag(OrdLogFlags.Canceled))
    status |= 0x200000;

if (ol.Flags.HasFlag(OrdLogFlags.CanceledGroup))
    status |= 0x400000;

if (ol.Flags.HasFlag(OrdLogFlags.Moved))
    status |= 0x100000;

if (ol.Flags.HasFlag(OrdLogFlags.Buy))
    msg.Side = Side.Buy;
else if (ol.Flags.HasFlag(OrdLogFlags.Sell))
    msg.Side = Side.Sell;
else
    throw new ArgumentException("Не задано направление заявки");

if (ol.Flags.HasFlag(OrdLogFlags.Quote))
{
    // котировочная
    msg.TimeInForce = StockSharpTimeInForce.PutInQueue;
    status |= 0x01;
}

if (ol.Flags.HasFlag(OrdLogFlags.Counter))
{
    // встречная
    msg.TimeInForce = StockSharpTimeInForce.CancelBalance;
    status |= 0x02;
}

if (ol.Flags.HasFlag(OrdLogFlags.FillOrKill))
{
    // fill-or-kill
    msg.TimeInForce = StockSharpTimeInForce.MatchOrCancel;
    status |= 0x80000;
}

if (ol.Flags.HasFlag(OrdLogFlags.NonSystem))
    status |= 0x04;

if (ol.Flags.HasFlag(OrdLogFlags.EndOfTransaction))
    status |= 0x1000;

if (ol.Flags.HasFlag(OrdLogFlags.CrossTrade))
    status |= 0x20000000;

msg.Status = status;

По 3 дням стакан построить не получилось: предполагаю что запись данных была выполнена с ошибками. Даты и время ошибок: 13.10.2014 Пн 19:00:55.878 11.06.2015 Чт 18:56:21.672 18.09.2015 Пт 18:51:07.919

sharafievrr
sharafievrr

После конвертации в из qsh в bin подкладываю данные в директорию где хранятся данные для гидры. Но при попытке получить тики по этому инструменту гидра говорит что данных нет. Что надо сделать чтобы гидра увидела файлы с сконвертированной историей?

Lexuz77
Lexuz77

sharafievrr: После конвертации в из qsh в bin подкладываю данные в директорию где хранятся данные для гидры. Но при попытке получить тики по этому инструменту гидра говорит что данных нет. Что надо сделать чтобы гидра увидела файлы с сконвертированной историей? Присоединяюсь к вопросу - ни гидра, ни дизайнер бетка эти данные (bin) не видит :(

Mikhail Sukhov
Mikhail Sukhov

Новая версия 1.0.5:

  1. Многопоточная обработка. Лучше запускать, если инструменты разбиты по разным файлам, как это сделано у Цериха.
  2. Преобрезование Order log в стаканы. Глубика по-умолчанию 5, правится в настройках в конфиг-файле.
  3. Фильтр инструментов по маске, перечисление через запятую. Например, SBER,RTS-*,BR будет означать поиск инструментов с названием SBER, вме инструменты, начинающиеся с RTS- и все инструменты, содержащие в названии BR (SBER, BRENT и т.д.).

Скачать

Напишите пожелание по утилите. Интересен ли вам сервис от Цериха, нужны ли в работе такие данные. Кто знает что стало с аналогичным сервисом от IT Invest?

JaguarFX
JaguarFX
JaguarFX

Программа очень и очень нужная для тестирования hft-стратегий на предмет того не являются ли они тестовыми граалыми, у которых чудо-доходность обусловлена исключительно несовершенством тестера (а-ля такого Мой hft-грааль). А так же подобные данные позволяют "исследовать" микроструктуру рынка на предмет реальных возможностей для заработка на фреймах ниже М1. Основное пожелание - интегрировать в следующую версию S#.Data данный сайт Цериха как доп. источник для скачивания данных с конвертацией "на лету" в формат bin с формированием OL или стаканов по выбору пользователя.

Mikhail Sukhov
Mikhail Sukhov

Лебедев Сергей: Основное пожелание - интегрировать в следующую версию S#.Data данный сайт Цериха как доп. источник для скачивания данных с конвертацией "на лету" в формат bin с формированием OL или стаканов по выбору пользователя.

Сайт поддерживает неофициально. Вполне вероятно, что у Цериха не хватает ресурсов, и он может быть закрыт в любое время. Тратить ресурсы на такую задачу нам не сильно охота. Да и что там автоматизировать? Закачку c FTP? Это делается любым download manager-ом на 1-2-3.

Константин
Константин

Конвертор не работает с файлами типа:

Название.AuxInfo.qsh Ошибка: Qsh2Bin 12.02.2018 19:27:26 Error "System.AggregateException: Произошла одна или несколько ошибок. ---> System.ArgumentOutOfRangeException: Время в формате UTC, представленное при применении смещения, должно находиться в диапазоне от 0 до 10 000 лет. Имя параметра: offset в System.DateTimeOffset.ValidateDate(DateTime dateTime, TimeSpan offset) в System.DateTimeOffset..ctor(DateTime dateTime, TimeSpan offset) в Ecng.Common.TimeHelper.ApplyTimeZone(DateTime dt, TimeZoneInfo zone) в StockSharp.Qsh2StockSharp.MainWindow.<>c__DisplayClass16_1.<ConvertFile>b__9(Int32 key, AuxInfo info) в QScalp.History.Reader.V4.AuxInfoStream.Read(Boolean push) в QScalp.History.Reader.V4.QshReaderImpl.Read(Boolean push) в StockSharp.Qsh2StockSharp.MainWindow.ConvertFile(String fileName, IStorageRegistry registry, StorageFormats format, ExchangeBoard board, String securityLike, Dictionary2 orderLog2OrderBookBuilders, Int32 orderBookMaxDepth) в StockSharp.Qsh2StockSharp.MainWindow.<>c__DisplayClass14_0.<ConvertDirectory>b__0(String f) в MoreLinq.MoreEnumerable.ForEach(IEnumerable1 source, Action1 action) в StockSharp.Qsh2StockSharp.MainWindow.ConvertDirectory(String path, IStorageRegistry registry, StorageFormats format, ExchangeBoard board, String securityLike, Boolean multithread, Dictionary2 orderLog2OrderBookBuilders, Int32 orderBookMaxDepth) в StockSharp.Qsh2StockSharp.MainWindow.<>c__DisplayClass13_0.<Convert_OnClick>b__0() в System.Threading.Tasks.Task.Execute() --- Конец трассировки внутреннего стека исключений --- ---> (Внутреннее исключение #0) System.ArgumentOutOfRangeException: Время в формате UTC, представленное при применении смещения, должно находиться в диапазоне от 0 до 10 000 лет. Имя параметра: offset в System.DateTimeOffset.ValidateDate(DateTime dateTime, TimeSpan offset) в System.DateTimeOffset..ctor(DateTime dateTime, TimeSpan offset) в Ecng.Common.TimeHelper.ApplyTimeZone(DateTime dt, TimeZoneInfo zone) в StockSharp.Qsh2StockSharp.MainWindow.<>c__DisplayClass16_1.<ConvertFile>b__9(Int32 key, AuxInfo info) в QScalp.History.Reader.V4.AuxInfoStream.Read(Boolean push) в QScalp.History.Reader.V4.QshReaderImpl.Read(Boolean push) в StockSharp.Qsh2StockSharp.MainWindow.ConvertFile(String fileName, IStorageRegistry registry, StorageFormats format, ExchangeBoard board, String securityLike, Dictionary2 orderLog2OrderBookBuilders, Int32 orderBookMaxDepth) в StockSharp.Qsh2StockSharp.MainWindow.<>c__DisplayClass14_0.<ConvertDirectory>b__0(String f) в MoreLinq.MoreEnumerable.ForEach(IEnumerable1 source, Action1 action) в StockSharp.Qsh2StockSharp.MainWindow.ConvertDirectory(String path, IStorageRegistry registry, StorageFormats format, ExchangeBoard board, String securityLike, Boolean multithread, Dictionary2 orderLog2OrderBookBuilders, Int32 orderBookMaxDepth) в StockSharp.Qsh2StockSharp.MainWindow.<>c__DisplayClass13_0.<Convert_OnClick>b__0() в System.Threading.Tasks.Task.Execute()<--- "

Mikhail Sukhov
Mikhail Sukhov

Поправил утилиту, чтобы поддерживала новый формат.

Утилитой кто-то пользуется? Или ОЛ уже интересен только единицам?

Дмитрий_ nik
torontoxx
torontoxx

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 совпадают.

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

Константин
Константин

Я юзаю сею утиль

torontoxx
torontoxx

Хотя нет, утилита все еще неудовлетворительно собирает стакан. Стал на истории сравнивать лучшие цены, рассчитанные утилитой с лучшими ценами, выводимыми QScalp и обнаружил, что разница между ними большая. Для фьючерса на индекс РТС за 25 февраля, например разница составляет 2-3 шага цены (20-30 пунктов)

torontoxx
torontoxx

Все-таки интересно, почему лучшие цены в стакане, собранным утилитой (PlazaOrderLogMarketDepthBuilder) отличаются от лучших цен QScalp. Неужели один из двух дает неверный результат? Или я что-то не понимаю...

Дмитрий_
Дмитрий_

Добрый день.

Подскажите пожалуйста.

Имею данные (c ftp://athistory.zerich.com/). GAZP.2019-01-30.Deals.qsh GAZP.2019-01-30.Quotes.qsh LKOH.2019-01-30.Deals.qsh LKOH.2019-01-30.Quotes.qsh

Снимок.PNG Пробовал ставить и MICEX площадку и бинарные данные.

Стаканы грузятся корректно, но сделки не совсем.

Для Газпрома цену нужно разделить на 100 и тогда ок. Снимок.PNG

Для Лукойла цену нужно разделить на 2 и тогда ок. Снимок.PNG

Почему так получается?

torontoxx
torontoxx

Дмитрий Антипов: Добрый день.

Подскажите пожалуйста.

Почему так получается?

Может надо цену умножать на шаг (priceStep) по аналогии с заявками из ордерлога?

Дмитрий_
Дмитрий_

torontoxx:

Дмитрий Антипов: Добрый день.

Подскажите пожалуйста.

Почему так получается?

Может надо цену умножать на шаг (priceStep) по аналогии с заявками из ордерлога?

Подскажите пожалуйста, на какой строке проекта находится данная "аналогия с заявками из ордерлога"?

Отследил чтение. Нужно в этом методе что-то менять? Снимок.PNG

torontoxx
torontoxx

Дмитрий Антипов:

torontoxx:

Дмитрий Антипов: Добрый день.

Подскажите пожалуйста.

Почему так получается?

Может надо цену умножать на шаг (priceStep) по аналогии с заявками из ордерлога?

Подскажите пожалуйста, на какой строке проекта находится данная "аналогия с заявками из ордерлога"?

Отследил чтение. Нужно в этом методе что-то менять? Снимок.PNG

Попробуйте поменять строку №380 в файле MainWindow.xaml.cs:

Старая строка: TradePrice = deal.Price, Исправленная срока: TradePrice = deal.Price * priceStep,

Viacheslav
Viacheslav

Коллеги, правильно ли я понимаю, что файлы сделок и стаканов на athistory.zerich.com и http://qsh.qscalp.ru/scalping.pro - это данные по Московской бирже?

torontoxx
torontoxx

Viacheslav: Коллеги, правильно ли я понимаю, что файлы сделок и стаканов на athistory.zerich.com и http://qsh.qscalp.ru/scalping.pro - это данные по Московской бирже?

Надо полагать, да

Sun_Storm
Sun_Storm

Добрый день. Пробую сейчас сконвертировать данные через этот конвертер. Данные беру отсюда: http://erinrv.qscalp.ru, за апрель Возникли следующие ошибки: При загрузке данных стаканов по акциям Сбербанка возникала ошибка и данные не грузились. Проблему я решил, порывшись в исходниках. там в исходном файле в начале торгов есть строки с ценой и объемом 0 и типом Unknown. Когда тип Unknown, программа сразу выдает исключение:


switch (q.Type)
{
	case QuoteType.Unknown:
	case QuoteType.Free:
	case QuoteType.Spread:
		throw new ArgumentException(q.Type.ToString());

Написал пока так для себя, не знаю, как в С# принято такое обрабатывать, когда у нас только 2 значения side:


switch (q.Type)
{
	case QuoteType.Free:
	case QuoteType.Spread:
		throw new ArgumentException(q.Type.ToString());
	case QuoteType.Unknown:
		\\throw new ArgumentException(q.Type.ToString());
		side = 0;
		break;

Второй ошибкой является то, что для всех стаканов (файл quotes) время проставляется одно и то же для каждой строчки на весь файл. Эта ошибка проявляется и для акций и для фьючерсов. Пока не могу её побороть. сохранение в файл делается средствами StockSharp.Algo.Storages, все исходники там, как я понимаю. По отладке не могу понять, какие параметры должны быть у pair, чтобы в строке registry.GetQuoteMessageStorage(pair.Key, format: format).Save(pair.Value.Item1); запись происходила как надо. Пробовал менять LocalTime и ServerTime для каждого набора, всё равно сохраняет неправильно (со временем 35517549, например)

Sun_Storm
Sun_Storm

Опытным путем разобрался с проблемой времени! Если у вас в папке, из которой вы конвертируете, лежат сразу 3 файла на день из архива http://erinrv.qscalp.ru (Deals, Quotes И AuxInfo), то конвертация будет некорректной! Я скачивал сразу все 3 файла, и из одной папки конвертировал, поэтому была ошибка. Если в папке лежат 2 файла на день - Deals, Quotes, то всё конвертируется нормально (если не считать ошибки по акциям, описанной мной выше)

UPD: В общем это я поспешил, что разобрался, всё равно время некорректно ставится. Ошибка плавающая... Я в потоках этих не разбираюсь... Однако, если прописать вместо ServerTime = currentDate.ApplyTimeZone(TimeHelper.Moscow), ServerTime = qr.CurrentDateTime.ApplyTimeZone(TimeHelper.Moscow), то вроде будет работать и время сменяться. Только в файлах начало дня при таком раскладе будет 4 часа.

traveller
traveller

Тип Unknown для quotes действительно надо фильтровать, в файле MainWindow.xaml.cs я добавил Where var quotes2 = quotes**.Where(q => q.Type != QuoteType.Unknown)**.Select(... что позволяет сразу выкинуть этот тип из рассмотрения.

И цена бывает иногда нулевая, тоже можно фильтровать при желании.

Для правки времени согласен с постом выше, можно использовать ServerTime = qr.CurrentDateTime.ApplyTimeZone(TimeHelper.Moscow) и тогда присвоение currentDate выше можно удалить, оно нигде не используется.

MichaelShpin
MichaelShpin

Писал подобную утилиту для TSLab и тоже заметил проблему рассинхронизации стакана и сделок. Как я понял эту проблему:

  • Есть лаг между событием на бирже и записью в локальный фаил. Он может достигать существенное количество секунд.
  • Записанный отдельно стакан в Quotes.qsh не имеет того самого реального (биржевого события), а только время локальной записи.
  • Сделка же летит сразу со временем, и можно увидеть этот лаг между временем записи и времен в самой сделке.
    При генерации из ордер лога всё хорошо, так как в логе есть все записи, а вот с акциями придётся наворачивать.

Как поступил я.

Если акция я просто создаю сразу 2 QshReader для Deals.qsh и Quotes.qsh. И начинаю их читать опираясь на внутреннее время записи QshReader CurrentDateTime, и стакан синхронизирую относительно времени сделки.



if (readers.Count > 1)
				{
					while (true)
					{
						if (readers.All(qr => qr.CurrentDateTime == DateTime.MaxValue))
							break;

						QshReader rd = readers.OrderBy(qr => qr.CurrentDateTime).First();
						rd.Read(true);
					}

					foreach (QshReader r in readers)
						r.Dispose();
				}
				else 
				{
					QshReader qr = readers[0];

					while (qr.CurrentDateTime != DateTime.MaxValue)
						qr.Read(true);

					qr.Dispose();
				}

Есть засада, что стаканы до первой сделки придётся проигнорировать, но в моей задаче была цель узнать лучший Бид/Аск в момент сделки и я её так решил.

Надеюсь помог.

Думаю скоро погружусь в эту задачу и для StokSharp

GIP
GIP

Позвольте глупый вопрос... При импорте данных QSH по инструменту RIZ2019 за 20.11.19 первая строка: 064624425;+03:00;637098399844250000;38091733454;143780;1;Buy;Done;PutInQueue;;;; 64624425 это время в миллисекундах с начала дня, получается 18 часов? Или это 06:46? Первая сделка должна проходить в 10:00 мск.

samosh
samosh

Здравствуйте, у меня Qsh2bin не видит файлы QSH

Di
Di

Я не трейдер, меня попросили сконвертировать данные в csv или txt, нашел вашу утилиту, но она выдает ошибку при конвертации. qsh.7z исходные файлы и то что получается SBER@FORTS.7z

Что делаю не так?

Mikhail Sukhov
Mikhail Sukhov

Обновил утилиту. Перевел на 17ую версию, заобно пофиксил ошибки. Бинарники так же по ссылке https://github.com/StockSharp/Qsh2Bin/releases

Важный момент при анализе записей. QSH не имеет признака временной зоны у времени. Поэтому понять в какой временной зоне записаны данные невозможно. С большей вероятностью она может быть или Московская или UTC. Точно могу сказать, что Церих и Айти в разных временных зонах пишут данные.

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

Как решить это проблему. Конечно же, надо писать всё в UTC. Но данные и формат уже легаси, поэтому в утилите две выпадающих списка. Один для установка временной зоны локальной отметки, другой для биржевой.

После конвертации может Гидрой или через S#.Storage API просмотреть полученные данные на предмет времени. Если начало торгов что-то вроде 7 часов утра - значит временная зона была в UTC.

Пишите о своём опыте использования. Ошибки старайтесь сами исправить, исходники на Гите. Папку с рефами не заливал, чтобы не захламлять дистрибутив. Думаю, кто умеет код пистать, эту проблему порешает.

Данные по качестве средней паршивости и для пипсовых алгоритмов совершенно бесполезные из-за недостоверной отметки времени и пропуска ряда цен внутри спреда (я про стакан). Но объемы более менее совпадают по итогу. Сервис уже достоин медали, что столь долго существует, и его ещё кто-то поддерживает.

nik
zoh
zoh

Mikhail Sukhov: Обновил утилиту. Перевел на 17ую версию, заобно пофиксил ошибки. Бинарники так же по ссылке https://github.com/StockSharp/Qsh2Bin/releases

Важный момент при анализе записей. QSH не имеет признака временной зоны у времени. Поэтому понять в какой временной зоне записаны данные невозможно. С большей вероятностью она может быть или Московская или UTC. Точно могу сказать, что Церих и Айти в разных временных зонах пишут данные.

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

Как решить это проблему. Конечно же, надо писать всё в UTC. Но данные и формат уже легаси, поэтому в утилите две выпадающих списка. Один для установка временной зоны локальной отметки, другой для биржевой.

После конвертации может Гидрой или через S#.Storage API просмотреть полученные данные на предмет времени. Если начало торгов что-то вроде 7 часов утра - значит временная зона была в UTC.

Пишите о своём опыте использования. Ошибки старайтесь сами исправить, исходники на Гите. Папку с рефами не заливал, чтобы не захламлять дистрибутив. Думаю, кто умеет код пистать, эту проблему порешает.

Данные по качестве средней паршивости и для пипсовых алгоритмов совершенно бесполезные из-за недостоверной отметки времени и пропуска ряда цен внутри спреда (я про стакан). Но объемы более менее совпадают по итогу. Сервис уже достоин медали, что столь долго существует, и его ещё кто-то поддерживает.

А АйТи ещё продолжает шарить записи с qscalp ?