Интеграция ArcticDB для хранения tick data в pandas

Интеграция ArcticDB для хранения tick data в pandas Анализ данных и Бэктесты
Пошаговое руководство по интеграции ArcticDB от Man Group для сверхбыстрого хранения и извлечения терабайтов тиковых данных в pandas DataFrame.
Суть: Интеграция ArcticDB позволяет хранить терабайты тиковых данных непосредственно в локальной файловой системе или S3-совместимом хранилище, обеспечивая скорость чтения и записи на уровне C++ благодаря интеграции с Apache Arrow и прямому маппингу в pandas DataFrame без накладных расходов на сериализацию.

При работе с высокочастотными историческими данными (tick data) классические реляционные СУБД и даже специализированные таймсерии-решения часто упираются в производительность дискового ввода-вывода и накладные расходы на сериализацию данных при передаче в Python. Разработанная хедж-фондом Man Group библиотека ArcticDB решает эту проблему, используя бинарный формат Apache Arrow, эффективное сжатие и оптимизированный C++ движок.

Эффективное хранение тиков критически важно для ресурсоемких задач количественного анализа. Например, когда выполняется распределенный бэктестинг RL в FinRL с Ray, миллионы симулированных сделок требуют мгновенного доступа к историческим стаканам. Также быстрый доступ к тикам необходим для построения микроструктурных фичей, когда рассчитывается кластеризация Volume Profile с DBSCAN для POC уровней, или при расчете рыночных рисков портфеля, таких как расчет VaR историческим методом для фьючерсов Binance на Python.

Исходный код

Ниже представлен готовый к продакшену скрипт, демонстрирующий инициализацию локальной базы данных ArcticDB, генерацию синтетического тикового потока объемом в миллионы строк, эффективную дозапись (append) и быстрое извлечение подмножества данных с фильтрацией на стороне C++ ядра без загрузки всего датасета в память Python.

import numpy as np
import pandas as pd
from arcticdb import Arctic, QueryBuilder

# 1. Инициализация локального хранилища ArcticDB (LMDB-бэкенд)
# Для продакшена можно использовать S3: 's3://s3.amazonaws.com:bucket_name?access=...&secret=...'
arctic = Arctic('lmdb://./arctic_tick_db')

# 2. Создание или получение библиотеки для тиковых данных
# Библиотеки в ArcticDB поддерживают версионирование из коробки
library_name = 'market_data.ticks'
if library_name not in arctic.list_libraries():
    arctic.create_library(library_name)

lib = arctic.get_library(library_name)

# 3. Генерация синтетических тиковых данных для демонстрации
def generate_mock_ticks(symbol: str, num_ticks: int, start_dt: str) -> pd.DataFrame:
    timestamps = pd.date_range(start=start_dt, periods=num_ticks, freq='ms')
    bids = 30000 + np.cumsum(np.random.normal(0, 0.1, num_ticks))
    asks = bids + np.random.uniform(0.01, 0.2, num_ticks)
    bid_sizes = np.random.randint(1, 10, num_ticks) * 100
    ask_sizes = np.random.randint(1, 10, num_ticks) * 100

    df = pd.DataFrame({
        'bid': bids,
        'ask': asks,
        'bid_size': bid_sizes,
        'ask_size': ask_sizes
    }, index=timestamps)
    df.index.name = 'index'
    return df

# Генерируем стартовый набор тиков (1 000 000 строк)
symbol = 'BTCUSDT'
df_ticks = generate_mock_ticks(symbol, 1_000_000, '2023-10-01 09:00:00')

# 4. Первичная запись данных в ArcticDB
# Данные автоматически сжимаются и разбиваются на чанки
lib.write(symbol, df_ticks, metadata={'asset_class': 'crypto', 'source': 'binance'})
print(f'Успешно записано {len(df_ticks)} тиков для {symbol}')

# 5. Дозапись новых тиков (Append)
# В отличие от обычных баз, append в ArcticDB оптимизирован для таймсерий
df_new_ticks = generate_mock_ticks(symbol, 500_000, '2023-10-01 09:16:40')
lib.append(symbol, df_new_ticks)
print(f'Дозаписано {len(df_new_ticks)} тиков для {symbol}')

# 6. Быстрое извлечение данных с фильтрацией на стороне C++ (QueryBuilder)
# Извлекаем только bid и ask для определенного временного интервала
q = QueryBuilder()
start_time = pd.Timestamp('2023-10-01 09:05:00')
end_time = pd.Timestamp('2023-10-01 09:10:00')

# Строим ленивый запрос
q = q[(q.index >= start_time) & (q.index <= end_time)]
q = q[['bid', 'ask']]

# Чтение данных с применением QueryBuilder
result = lib.read(symbol, query_builder=q)

# Получаем pandas DataFrame напрямую
df_queried = result.data
print(f'\nИзвлечено строк после фильтрации: {len(df_queried)}')
print(df_queried.head()) 
print(df_queried.tail())

Разбор параметров

  • Arctic('lmdb://./arctic_tick_db'): Инициализирует подключение к базе данных. В качестве бэкенда используется сверхбыстрая встраиваемая СУБД LMDB. Для распределенной работы в облаке этот параметр заменяется на URI S3-хранилища.
  • create_library(): Создает изолированное пространство имен (библиотеку) внутри инстанса. Каждая библиотека может иметь свои настройки версионирования, сегментации и динамического сжатия.
  • write(): Записывает DataFrame в базу. Автоматически сериализует данные в формат Arrow, сжимает их с помощью алгоритмов LZ4/ZSTD и сохраняет метаданные в заголовке чанка.
  • append(): Дописывает новые строки к существующему символу. Оптимизировано для потоковых данных, предотвращает фрагментацию диска и автоматически создает новые временные чанки.
  • QueryBuilder(): Инструмент для ленивой фильтрации данных на уровне C++ ядра ArcticDB. Позволяет избежать загрузки терабайтов данных в оперативную память Python, фильтруя строки и столбцы до этапа десериализации в pandas.

Как запустить

Для запуска данного решения выполните следующие шаги в вашем терминале:

1. Установите необходимые библиотеки с помощью пакетного менеджера pip:

pip install arcticdb pandas numpy

2. Сохраните приведенный выше Python-код в файл arctic_integration.py.

3. Запустите скрипт:

python arctic_integration.py

4. После выполнения в текущей директории появится папка arctic_tick_db, содержащая бинарные файлы базы данных LMDB. Вы увидите вывод в консоли, подтверждающий успешную запись, дозапись и мгновенную выборку отфильтрованных тиков.

Оцените статью
FinFluct