Когда еще только начал заниматься алготрейдингом, возник вопрос удобного доступа к историческим данным котировкам. Дело в том, что csv файлы могут содержать пропуски данных, а мне необходимо было получать котировки за конкретные дни года. Поэтому мне было не удобно грузить csv файл в общий массив и затем искать в нем отрезки данных. Второй проблемой было то, что минутный график (не говоря уже о тиковом) занимает много места, когда речь идет о более 20 шт. валютных пар. Конечно это уже не такая проблема, как первая, так как сейчас большая память на SSD или HHD не проблема. Но с другой стороны, хранить все >20 валютных пар уже в памяти компьютера тоже не лучший вариант, лучше было бы грузить данные по кускам.
Поэтому я решил убить всех зайцев тем, чтобы написать специальную библиотеку для удобного хранения и использования котировок.
- Так как мой интерес был именно минутный график, было решено хранить фиксированное количество минут для каждого дня (даже если есть пропуски цен). В одном дне 1440 минут, следовательно каждый дневной фрагмент исторических данных содержит 1440 баров.
- Каждый дневной фрагмент было решено обозвать «подфайлом» и хранить все подфайлы в одном файле. Дело в том, что множество файлов тормозят систему, поэтому записывать каждый фрагмент как отдельный файл — не лучшее решение. В то же время сильно усложнять хранение фрагментов не хотелось, да и не было смысла. Обычная операция для «хранилища» котировок — добавление новых данных или чтение старых, при этом перезапись или добавление нового подфайла в глубоком слое исторических данных может потребоваться редко. Поэтому оптимальное решение будет записывать дневные фрагменты исторических данных по порядку в один общий файл и хранить ссылки на подфайлы в конце файла.
- Чтобы уменьшить количество памяти под котировки было решено переводить цену в переменную типа uint32_t путем умножения на 100000. Обычно котировки имеют пять знаков после запятой, поэтому данного коэффициента должно хватить для всех валютных пар. Но важно иметь ввиду ограничение максимального значения цены сверху (максимальная котировка в данном случае 42949,67295 и возможно когда нибудь этот потолок может быть пробит тем же BTCUSD).
- Также, чтобы уменьшить количество памяти, каждый подфайл не содержит меток времени для баров. Метку времени каждого бара легко получить через прибавление смещения к началу дня конкретного подфайла. Так как для подфайлов важен именно момент начала дня, то было решено хранить номер дня с начала unix-времени.
- Если бар отсутствует, то его все его цены open, high, low, close равны 0.
- Чтобы дополнительно уменьшить память, было решено сжимать подфайлы при помощи библиотеки zstd и специально подготовленного словаря. Данный вариант с zstd также позволяет ускорить декомпрессию и увеличить степень сжатия.
- Хранилище котировок позволяет получить бар по метке времени. Это очень удобно для тестирования. Также можно получить список последний N дней начиная с некоторого момента, что удобно для алгоритмов оптимизаций. Каждый подфайл загружается по мере необходимости, поэтому память ЭВМ содержит в себе лишь небольшой участок исторических данных.
Позже я подумал, что инструмент получится конечно неплохой, но многим программам мой формат котировок не знаком и не нужен. Поэтому решил добавить небольшую консольную программу, которая может конвертировать формат обратно в csv файл.
Ссылка на репозиторий:
https://github.com/NewYaroslav/xquotes_history
В качестве примера сжатия котировок — исторические данные Финама из метатрейдера 4 с максимальной глубиной истории:
https://github.com/NewYaroslav/finam_history_quotes
Оригинальные CSV файлы от Финама занимают
10.9 Гб, после сжатия —
930 Мб, поэтому их можно загрузить на гитхаб с лимитом в
1 Гб.