Нефть глазами аналитика данных

jbnijbz7oqssqvk0xvizl5rtxik.png

    Любите ли вы работать с данными, как люблю это делать я? Страдаете ли вы также от несовершенства инструментов для анализа данных? И вот, буквально в первых строках, я понимаю, что мне надо быть очень аккуратным, дабы не задеть чувства, к примеру, фанатов Excel или Notepad++. Попытаюсь исправить ситуацию: Эксель великолепен! Лучшая low-code система! Notepad++ бесподобен…, но попробуйте поработать этими инструментами с данными размером с один миллион строк… эх, не удержался. Ну и раз статья обещает быть провокационной, добавлю еще огоньку: я хочу продемонстрировать, как обрабатывать и анализировать данные по всем обезличенным сделкам по нефти. Взглядом аналитика покажу, как крупный капитал управляет рынком. И да, я хочу, чтобы такая возможность была доступна не только корпорациям с их ресурсами, а обычному пользователю с ноутбуком. Текст статьи не является инвестиционной рекомендацией, все совпадения случайны.

Краткое вступление.


    Написание статьи как и сбор данных осуществлялись в первой половине января 2024 года. Поэтому предметом анализа выступали обезличенные сделки по расчетному фьючерсу на нефть (BRG4) в период начиная с начала вечерней сессии 12.01.2024 заканчивая финалом дневной сессии от 17.01.2024.

Содержание


1) Способ получения и подготовки данных
2) Хранение и загрузка данных
3) Анализ данных

Способ получения данных.


    Опишу, как сделать это бесплатно, но у вас должен быть активный торговый терминал Quik. Да, есть сервис московской биржи, который очень скупо делится данными. Да, мне понравилась задумка tinkoff отдавать все через API-шечку (обожаю Swagger). Но повторюсь, для обычного пользователя это сложновато. Открываем терминал Quik, желательно ближе к концу дневной сессии (18–45 МСК). Время выбрано не случайно, т.к. через терминал у вас есть возможность получить данные всего за один день (если быть точнее за вечернюю сессию предыдущего дня и за дневную сессию текущего).

    Выбираем меню → Создать окно → Таблица обезличенных сделок
    В открывшемся окне выставляем параметры как показано на рисунке
kchs4qc3r6uzcn98k5z2_ofh-uw.png

    В открывшейся таблице обезличенных сделок щелкаем правой кнопкой мыши и выбираем «Копировать все» как показано на рисунке
ljztsebjef6xi2tp9fkpfq9-gm8.png

    Далее, начинается первое испытание силы вашей любви к Notepad++ :) Вставьте содержимое буфера обмена в Notepad++. Скажу честно, я не справился, слукавил и воспользовался VSCode. Тем не менее, после вставки в текстовый файл данные выглядят примерно вот так:
m7cnrzfx3q0vrxf3mfcqtfvey4k.png

    Далее в текстовом файле необходимо выполнить серию замен, чтобы немного снизить размер файла и подготовить полноценный csv файл. Я обычно подменяю:

  • Все запятые на точки
  • Все табы на запятые
  • слово «Купля» на символ 'B'
  • слово «Продажа» на символ 'S'
  • ну и т.д.


    Должно все получится вот примерно в таком виде:
bzmofr5manpqmsjip46xajhfqas.png
    Здесь стоит заметить, что как список инструментов, так и набор колонок могут быть любыми.

Хранение и загрузка данных


    На самом деле, здесь уже вопрос предпочтений и удобства. Данные можно хранить в виде csv файлов. Мой путь — более сложный, но все же опишу его. Я лично предпочитаю использовать СУБД, любимый Clickhouse от yandex. При таком подходе у получаю гибкость, например, я могу дать такой SQL-запрос:

 SELECT ID_DTTM, OPERATION, PRICE, QUANTITY, OI FROM moex.br_trades bt where bt.ID_DTTM>toDateTime('2024-01-16 08:50:00') and bt.ID_DTTM


… и получу сразу набор данных в период с 08:50 16.01.24 по 00:00 17.01.24 отсортированный по дате и времени. В случае с хранением данных в формате csv — о такой гибкости можно и не мечтать.
    Как установить Clickhouse лучше спросить у Яндекса :) В официальной документации описан сложный путь, однако я встречал статьи, где все описывается значительно проще.
    Как загрузить данные из csv в clickhouse. Я использую DBeaver и простенький Python-скрипт, например, вот такой:

Простой скрипт
INSERT_SQL = "INSERT INTO moex.br_trades (ID_DTTM, TRADENO, SECID, PRICE, QUANTITY, OPERATION, OI) VALUES "
with open("./br_in_16-17.csv") as file:
	content = file.readlines()

sql = INSERT_SQL
for line in content:
	trade = line.split(",")
	tradeno = trade[1]
	id_dttm = trade[2] + " " + trade[3]
	secid = trade[4]
	price = trade[5]
	quantity = trade[6]
	operation = trade[7]
	oi = trade[8]

	sql = (
		INSERT_SQL
		+ "(toDateTime('"
		+ id_dttm
		+ "'),'"
		+ tradeno
		+ "','"
		+ secid
		+ "',"
		+ price
		+ ","
		+ quantity
		+ ",'"
		+ operation
		+ "',"
		+ oi
		+ ");"
	)

	print(sql)

    Примерно в этом месте должны появится «душнилы», которые скажут, что в аналитические СУБД данные надо грузить батчами (batch), а не построчно. На практике же DBeaver умирает примерно перед запуском батча размером от 100 тыс. строк и выше. А построчно медленно, но выполняет.

Анализ данных


    Здесь также тропинка к результату проходила через болото разочарования. Я было ринулся рисовать графики в Apache Superset, но тот сразу «покинул чат», замерев навечно при отрисовке скромного датасета размером в 300 тыс. строк. Да, понимаю, дело всего в одном воркере и скверной манере данной BI-системы оборачивать исходный SQL-датасета в свой. Как итог — здравствуй, Jupyter Notebook.

    Установку рекомендую через Anaconda

    Первым делом импортируем нужные пакеты, и в датафрейм df загрузим данные (или из csv файла, или из clickhouse), ну и посмотрим что у нас получилось.

6mmwdhkw_gnshpecc4g79dnqyre.png

    Здесь, для понимания, опишу значения в колонках

  • ID_DTTM — дата и время сделки
  • OPERATION — «B»: покупка, «S»: продажа
  • PRICE — цена сделки
  • QUANTITY — количество (лотов)
  • OI — открытый интерес

    Немного статистики
jsiulxf2t14fvnxlttbeekzp07g.png

    Обратите внимание на минимальные и максимальные значения столбца Quantity, нам это потребуется в дальнейшем.
    Теперь перейдем к моей любимой процедуре — рисованию графиков. Начнем с простого: посмотрим динамику изменения цены за выбранный период.
ucxfukvdzbnte7_aju8ral5vtky.png

    Отлично, но пока скромно. Любой торговый терминал так может. А теперь давайте нарисуем то, чего не могут терминалы (или не хотят). Например, меня очень давно интересовала корреляция между покупками/продажами и открытым интересом. Пусть у нас будет новый столбец в датафрейме, назовем его дельтой. Суть дельты — накапливаемая с начала выборки разница между покупкой и продажей. Например, если у нас с начала периода продали 18 лотов, потом купили 1, а потом снова продали 5, то дельта = -18 + 5 — 1 = — 22 лота.
    А теперь посмотрим на примере графика
cii_9g6z7w_sl3bmy1oainptf4m.png

    А вот уже интересные выводы:

  1. Несмотря на то, что за 16 января цена нефти почти не изменилась (если сравнивать начало дня и конец дня) — тем не менее все участники рынка по итогам дня выкупили около 7500 лотов. Интересно, почему так случилось, правда?
  2. С открытым интересом — можно, конечно, и точно посчитать, но явно видна обратная корреляция между дельтой и интересом. Т.е. когда рынок покупает, открытый интерес падает ну и наоборот.


    Теперь давайте разделим нашу дельту на составные части. Ведь в нашей выборке обезличенных сделок присутствуют сделки от всех участников рынка, независимо от размера. Вот мы их и разделим по размеру сделки. Помните, я просил вас запомнить минимальное и максимальное значение количества лотов в сделке? Оно в данном случае от 1 лота до 500. Давайте возьмем сделки размером более 100 лотов и посчитаем по ним дельту отдельно. Является ли данный признак подходящим для определения крупной сделки? Думаю, что да. Покупатель/продавец под 1 лот фьючерса BRG4 должен иметь обеспечение на сумму около 14 тыс. руб. Следовательно под 100 лотов речь идет уже о обеспечении в 1.4 млн руб. Еще раз, 1.4 млн руб. — это только обеспечение по всего одной сделке. Так что думаю вполне.
    Вот что получилось.
imddmirf7t8tehbvx0l8h9rojwm.png

    Оранжевая кривая — мелкие сделки, красная — крупные. И тут мы с вами оказываемся на тонком льду интерпретации результатов. Воображаемые «сторонники заговора маркетмейкеров против спекулянтов» могут сказать «ну все очевидно, когда цена начала падать, поддержали рынок, а дальше гнали толпу наверх». Ну, а если опираться на цифры, то мы видим, что посредством крупных сделок к концу дня выкуплено около 2500 лотов, а вот посредством мелких — 5000 лотов.

    Но лично мне хотелось бы получить четкий признак локальных экстремумов. Если говорить упрощенно, я хотел бы в ситуации, когда цена упала — понимать, что «это дно и дальше будем расти», или в ситуации, когда цена растет — понимать, «это вершина, скоро начнем падать». И, буду честен, мне пока не удалось этого достичь. Но, ведь и цель статьи была в другом, верно?

Послесловие.


    Ссылка на git c csv файлами выгрузки и файлом jupyter notebook: https://github.com/BazDen/BR_trades/
    В статье я старался продемонстрировать возможность для обычного пользователя заниматься анализом большого объема данных. Да, таким же способом можно анализировать не только инструменты срочного рынка, а, к примеру, сделки по акциям. Можно ли построить успешную стратегию на основе данного анализа? Уверен, что да. И даже протестировать. Но, думаю это материал уже для следующей статьи и следующей бессонной ночи.

© Habrahabr.ru