Как хранить историю данных фондового рынка
Что проверяют
Умеете ли вы спроектировать хранилище под временные ряды с огромным потоком записи и чтением по диапазонам, а не взять «какую-нибудь NoSQL». Следом обычно спрашивают, как построить свечи за произвольный период и что делать со сплитами акций.
Как отвечать
Сначала уточните требования: тики (каждая сделка и котировка) или только свечи OHLCV, сколько инструментов, какая глубина истории, кто читает: графики, бэктесты, отчёты. Тиков миллионы в день, минутных свечей на порядки меньше.
Дальше модель и хранилище:
- ключ: внутренний
instrument_idплюс время, а не тикер. Тикеры меняются и повторяются на разных биржах; - время: UTC с точностью до микросекунд или наносекунд, отдельно торговая сессия и часовой пояс площадки;
- цены: не
float64, а целое число в минимальных шагах цены илиDecimal, иначе поплывут суммы и сравнения; - ClickHouse:
MergeTreeсORDER BY (instrument_id, ts)и партициями по месяцу, кодекиDeltaиGorillaсжимают ряды в разы. Свечи строятся на лету черезargMin,argMax,min,maxили заранее материализованными представлениями; - TimescaleDB: если нужен PostgreSQL, гипертаблицы, сжатие старых чанков и continuous aggregates для свечей;
- холодный слой: старые тики в Parquet в объектном хранилище, в горячей базе свечи и последние месяцы тиков.
На стороне Go приём идёт через буфер (Kafka или канал с воркерами), а запись пачками: в ClickHouse через PrepareBatch из clickhouse-go, в PostgreSQL через CopyFrom из pgx. Построчные вставки такой поток не выдержат.
Сплиты и дивиденды храните отдельной таблицей корпоративных событий, а скорректированные цены считайте при чтении.
Где спотыкаются
Берут MongoDB или обычную таблицу PostgreSQL с индексом по времени и без партиционирования. Через год запросы по диапазону и удаление старых данных становятся проблемой.
Пишут в ClickHouse по одной строке на тик. Он рассчитан на пачки в тысячи строк, иначе копятся мелкие куски и растёт нагрузка на слияния.
Перезаписывают историю после сплита. Исходные цены теряются, и бэктест уже нельзя воспроизвести.