Нефть глазами аналитика данных
Любите ли вы работать с данными, как люблю это делать я? Страдаете ли вы также от несовершенства инструментов для анализа данных? И вот, буквально в первых строках, я понимаю, что мне надо быть очень аккуратным, дабы не задеть чувства, к примеру, фанатов Excel или Notepad++. Попытаюсь исправить ситуацию: Эксель великолепен! Лучшая low-code система! Notepad++ бесподобен…, но попробуйте поработать этими инструментами с данными размером с один миллион строк… эх, не удержался. Ну и раз статья обещает быть провокационной, добавлю еще огоньку: я хочу продемонстрировать, как обрабатывать и анализировать данные по всем обезличенным сделкам по нефти. Взглядом аналитика покажу, как крупный капитал управляет рынком. И да, я хочу, чтобы такая возможность была доступна не только корпорациям с их ресурсами, а обычному пользователю с ноутбуком. Текст статьи не является инвестиционной рекомендацией, все совпадения случайны.
Краткое вступление.
Написание статьи как и сбор данных осуществлялись в первой половине января 2024 года. Поэтому предметом анализа выступали обезличенные сделки по расчетному фьючерсу на нефть (BRG4) в период начиная с начала вечерней сессии 12.01.2024 заканчивая финалом дневной сессии от 17.01.2024.
Содержание
1) Способ получения и подготовки данных
2) Хранение и загрузка данных
3) Анализ данных
Способ получения данных.
Опишу, как сделать это бесплатно, но у вас должен быть активный торговый терминал Quik. Да, есть сервис московской биржи, который очень скупо делится данными. Да, мне понравилась задумка tinkoff отдавать все через API-шечку (обожаю Swagger). Но повторюсь, для обычного пользователя это сложновато. Открываем терминал Quik, желательно ближе к концу дневной сессии (18–45 МСК). Время выбрано не случайно, т.к. через терминал у вас есть возможность получить данные всего за один день (если быть точнее за вечернюю сессию предыдущего дня и за дневную сессию текущего).
Выбираем меню → Создать окно → Таблица обезличенных сделок
В открывшемся окне выставляем параметры как показано на рисунке
В открывшейся таблице обезличенных сделок щелкаем правой кнопкой мыши и выбираем «Копировать все» как показано на рисунке
Далее, начинается первое испытание силы вашей любви к Notepad++ :) Вставьте содержимое буфера обмена в Notepad++. Скажу честно, я не справился, слукавил и воспользовался VSCode. Тем не менее, после вставки в текстовый файл данные выглядят примерно вот так:
Далее в текстовом файле необходимо выполнить серию замен, чтобы немного снизить размер файла и подготовить полноценный csv файл. Я обычно подменяю:
- Все запятые на точки
- Все табы на запятые
- слово «Купля» на символ 'B'
- слово «Продажа» на символ 'S'
- ну и т.д.
Должно все получится вот примерно в таком виде:
Здесь стоит заметить, что как список инструментов, так и набор колонок могут быть любыми.
Хранение и загрузка данных
На самом деле, здесь уже вопрос предпочтений и удобства. Данные можно хранить в виде 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), ну и посмотрим что у нас получилось.
Здесь, для понимания, опишу значения в колонках
- ID_DTTM — дата и время сделки
- OPERATION — «B»: покупка, «S»: продажа
- PRICE — цена сделки
- QUANTITY — количество (лотов)
- OI — открытый интерес
Немного статистики
Обратите внимание на минимальные и максимальные значения столбца Quantity, нам это потребуется в дальнейшем.
Теперь перейдем к моей любимой процедуре — рисованию графиков. Начнем с простого: посмотрим динамику изменения цены за выбранный период.
Отлично, но пока скромно. Любой торговый терминал так может. А теперь давайте нарисуем то, чего не могут терминалы (или не хотят). Например, меня очень давно интересовала корреляция между покупками/продажами и открытым интересом. Пусть у нас будет новый столбец в датафрейме, назовем его дельтой. Суть дельты — накапливаемая с начала выборки разница между покупкой и продажей. Например, если у нас с начала периода продали 18 лотов, потом купили 1, а потом снова продали 5, то дельта = -18 + 5 — 1 = — 22 лота.
А теперь посмотрим на примере графика
А вот уже интересные выводы:
- Несмотря на то, что за 16 января цена нефти почти не изменилась (если сравнивать начало дня и конец дня) — тем не менее все участники рынка по итогам дня выкупили около 7500 лотов. Интересно, почему так случилось, правда?
- С открытым интересом — можно, конечно, и точно посчитать, но явно видна обратная корреляция между дельтой и интересом. Т.е. когда рынок покупает, открытый интерес падает ну и наоборот.
Теперь давайте разделим нашу дельту на составные части. Ведь в нашей выборке обезличенных сделок присутствуют сделки от всех участников рынка, независимо от размера. Вот мы их и разделим по размеру сделки. Помните, я просил вас запомнить минимальное и максимальное значение количества лотов в сделке? Оно в данном случае от 1 лота до 500. Давайте возьмем сделки размером более 100 лотов и посчитаем по ним дельту отдельно. Является ли данный признак подходящим для определения крупной сделки? Думаю, что да. Покупатель/продавец под 1 лот фьючерса BRG4 должен иметь обеспечение на сумму около 14 тыс. руб. Следовательно под 100 лотов речь идет уже о обеспечении в 1.4 млн руб. Еще раз, 1.4 млн руб. — это только обеспечение по всего одной сделке. Так что думаю вполне.
Вот что получилось.
Оранжевая кривая — мелкие сделки, красная — крупные. И тут мы с вами оказываемся на тонком льду интерпретации результатов. Воображаемые «сторонники заговора маркетмейкеров против спекулянтов» могут сказать «ну все очевидно, когда цена начала падать, поддержали рынок, а дальше гнали толпу наверх». Ну, а если опираться на цифры, то мы видим, что посредством крупных сделок к концу дня выкуплено около 2500 лотов, а вот посредством мелких — 5000 лотов.
Но лично мне хотелось бы получить четкий признак локальных экстремумов. Если говорить упрощенно, я хотел бы в ситуации, когда цена упала — понимать, что «это дно и дальше будем расти», или в ситуации, когда цена растет — понимать, «это вершина, скоро начнем падать». И, буду честен, мне пока не удалось этого достичь. Но, ведь и цель статьи была в другом, верно?
Послесловие.
Ссылка на git c csv файлами выгрузки и файлом jupyter notebook: https://github.com/BazDen/BR_trades/
В статье я старался продемонстрировать возможность для обычного пользователя заниматься анализом большого объема данных. Да, таким же способом можно анализировать не только инструменты срочного рынка, а, к примеру, сделки по акциям. Можно ли построить успешную стратегию на основе данного анализа? Уверен, что да. И даже протестировать. Но, думаю это материал уже для следующей статьи и следующей бессонной ночи.