Блог им. SergeyTunkin

moexalgo для Algopack мосбиржи – #1 Справочная информация о всех инструментах рынка

moexalgo для Algopack мосбиржи – #1 Справочная информация о всех инструментах рынка


Что такое Алгопак я уже писал, как и то, как можно сделать для библиотеки на Python moexalgo документацию из докстрингов – ведь пока никакого хорошего пособия с “разжеванными” примерами от Мосбиржи не существует.

На данный момент я поставил задачу – вытащить исторические данные по российским акциям и в дальнейшем их регулярно обновлять. Это позволит мне при изучении Backtrader использовать данные Мосбиржи для компонента DataFeeds, а также разрабатывать и тестировать на исторических данных собственные торговые стратегии.

Приступим. Отправная точка – раздел moexalgo на Гитхабе.  Файл samples/quick_start.ipynb начинается с примера:
moexalgo для Algopack мосбиржи – #1 Справочная информация о всех инструментах рынка

Сразу же встает вопрос: что такое stocks?

 

На самом деле это алиас. Механизм алиасов в коде библиотеки на Python позволяет создавать псевдонимы для модулей или их функций, классов и переменных. Это полезно, когда нужно сократить длинные имена или импортировать функции или классы из модуля с более удобными именами. В библиотеке moexalgo в модуле market.py определены алиасы:

_ALIASES= {
‘index’: (‘index’, ‘SNDX’),
‘shares’: (‘shares’, ‘TQBR’),
‘stocks’: (‘shares’, ‘TQBR’),
‘EQ’: (‘shares’, ‘TQBR’),
}

Это означает, что объекты Market(“stocks”) и Market(“shares/TQBR”) эквивалентны и создают объект для работы с данными по акциям в режиме основных торгов TQBR. Первый вариант с использование “stocks” по замыслу разработчиков является более удобным и коротким способом написания кода.

Выражение Market(‘shares/TQBR’) создает объект класса Market из библиотеки moexalgo, который представляет раздел рынка акций Московской биржи (TQBR).

TQBR позволяет осуществлять сделки с акциями. 


BOARDID на Московской бирже – это уникальный цифровой идентификатор торговой площадки или режима торгов, в рамках которого проходят торги различными финансовыми инструментами.

Каждой торговой площадке на Мосбирже присваивается свой BOARDID:

  • BOARDID=TQBR – основная площадка для акций и облигаций (Торгово-Quotation Board)
  • BOARDID=TQTF – площадка для биржевых ETF и паев ПИФов
  • BOARDID=EQBR – площадка для торговли акциями малой капитализации
  • BOARDID=FQBR – площадка для корпоративных и муниципальных облигаций и т.д.

Зная BOARDID конкретной ценной бумаги, можно однозначно определить на какой площадке и в рамках какого режима она обращается. Этот идентификатор широко используется в отчетности и API Московской биржи.

Вернемся к нашему коду Market(“shares/TQBR”).

Market – это класс в moexalgo, представляющий раздел биржевого рынка. При создании экземпляра класса Market нужно указать название раздела и режим торгов. В нашем случае shares – название раздела акций и TQBR – режим основных торгов акциями на Московской бирже.

А например другой вариант Market(“index/SNDX”) создаст объект класса Market для работы с индексами фондового рынка Московской биржи. Здесь index – раздел фондовых индексов, SNDX – режим основных торгов индексами Мосбиржи.

Мы же сосредоточимся на акциях.

Далее мы уже можем получить справочную информацию о всех инструментах рынка.

from moexalgo import Market

stocks = Market("shares/TQBR")
all_stocks = stocks.tickers()  # Вызоваем метод tickers() на экземпляре класса Market
print(type(all_stocks)) 
# <class 'pandas.core.frame.DataFrame'> или <class 'list'> в зависимости от того, где вызвали метод (в интерактивной среде или нет) 

Здесь мы создаём объект stocks, который будет представлять раздел акций Московской биржи в режиме основных торгов TQBR. И далее вызываем метод stocks.tickers(), который возвращает информацию по всем инструментам (тикерам акций) с их метаданными в этом разделе рынка. Результат сохраняем в переменной all_stocks. Можем вывести на печать тип и увидим, что это будет список словарей с данными по каждой акции.

Тут есть одно важное замечание(!): метод tickers возвращает нам тип данных в зависимости от того, где выполняется код программы. Если программа выполняется в интерактивной среде (например, в Jupyter Notebook), то функция tickers возвращает результат в виде pandas DataFrame, потому что в интерактивных средах удобно работать с DataFrame. Если код выполняется не в интерактивной среде, то функция tickers возвращает результат в виде итератора объектов данных (в данном случае TradeStat), потому что вне интерактивных сред это видимо более эффективный формат.

Так как в конечном итоге нам нужен код для обычной программы, и мне все же хочется оперировать с данными именно через pandas, то давайте полученную информацию в виде списка list отправим в Dataframe pandas. 

(Замечу, что Pandas для знакомства и начала работы с ним очень простой. Главное понять, что DataFrame в pandas  – это по сути плоская таблица данных, практически как Excell. Все остальное можно узнавать и изучать по мере необходимости.)

немного изменим код:

import pandas as pd
from moexalgo import Market

stocks = Market("shares/TQBR")
all_stocks = pd.DataFrame(stocks.tickers())
print(all_stocks)

и получаем таблицу Dataframe, включающую 248 акций

Вот как она выглядит, если программу запустить как обычный скрипт:
moexalgo для Algopack мосбиржи – #1 Справочная информация о всех инструментах рынка

27 колонок со следующими названиями [‘SECID’, ‘BOARDID’, ‘SHORTNAME’, ‘PREVPRICE’, ‘LOTSIZE’, ‘FACEVALUE’, ‘STATUS’, ‘BOARDNAME’, ‘DECIMALS’, ‘SECNAME’, ‘REMARKS’, ‘MARKETCODE’, ‘INSTRID’, ‘SECTORID’, ‘MINSTEP’, ‘PREVWAPRICE’, ‘FACEUNIT’, ‘PREVDATE’, ‘ISSUESIZE’, ‘ISIN’, ‘LATNAME’, ‘REGNUMBER’, ‘PREVLEGALCLOSEPRICE’, ‘CURRENCYID’, ‘SECTYPE’, ‘LISTLEVEL’, ‘SETTLEDATE’]

 

и вот так выглядит таблица, если программу запустить в интерактивной среде в Jupyter Notebook:
moexalgo для Algopack мосбиржи – #1 Справочная информация о всех инструментах рынка

только 9 колонок со следующими названиями [‘ticker’, ‘shortname’, ‘lotsize’, ‘decimals’, ‘minstep’, ‘issuesize’, ‘isin’, ‘regnumber’, ‘listlevel’]

Таблица с акциями в сохраненном pdf файле.

Вы заметили, что получаемые dataframe немного отличаются (!) друг от друга. Обращайте внимание на названия колонок.  Например символьное обозначение акции в первом варианте трактуется как SECID, а во втором как ticker. Это очень важно при написании программы. И если вы пишите программу модулями в Jupyter Notebook и обращаетесь в ней к названиям колонок, то скорее всего этот код в скрипте при запуске в обычном режиме выдаст ошибку.

SECID – уникальный идентификатор инструмента, присваивается биржей. Тикер – буквенно-цифровой код, также идентифицирующий инструмент. SECID всегда уникален для каждого финансового инструмента на бирже. Тикер уникален только в рамках одного рынка. Тикер является “внешним” идентификатором – он используется для отображения в торговых системах. А SECID больше предназначен для внутреннего использования.

Пройдемся по заголовкам полученного Dataframe: 

  1. ticker – торговый код (тикер) инструмента, его уникальный идентификатор. Например, SBER.
  2. shortname – краткое название инструмента, может содержать аббревиатуру эмитента. К примеру, Сбербанк.
  3. lotsize – минимальный объем одной заявки на покупку/продажу в лотах.
  4. decimals – количество знаков после запятой при отображении цены инструмента.
  5. minstep – минимальный шаг изменения цены при торговле данным инструментом.
  6. issuesize – объем выпуска данного инструмента согласно проспекту эмиссии.
  7. isin – международный идентификационный код ценной бумаги (ISIN).
  8. regnumber – регистрационный номер выпуска ценной бумаги в ЦБ РФ.
  9. listlevel – уровень листинга инструмента, соответствует котировальному списку на Мосбирже.

Остановимся на последнем параметре. На Московской бирже параметр listlevel обозначает уровень листинга, то есть котировальный список, в который включены ценные бумаги (акции, облигации).

Выделяют 3 уровня листинга:

  1. Первый уровень (listlevel=1) – самые ликвидные и надежные ценные бумаги крупнейших и инвестиционно-привлекательных эмитентов. Для включения есть жесткие требования.
  2. Второй уровень (listlevel=2) – бумаги компаний поменьше по капитализации и ликвидности. Требования мягче.
  3. Третий уровень (listlevel=3) – как правило, акции компаний малой капитализации и более высокого риска. Требования слабее.

Чем выше уровень листинга, тем выше требования к эмитенту и качество его ценных бумаг с точки зрения надежности, информационной прозрачности и ликвидности. Все голубые фишки относятся к первому уровню листинга.

Ну и ниже приведен код программы, которая создает списки акций с сортировкой по листингам.

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

moexalgo для Algopack мосбиржи – #1 Справочная информация о всех инструментах рынка
Листинг программы

Давайте детально разберем код, чтобы любой начинающий с нуля “питонист”, собственно говоря как и я,  мог в нем разобраться.

Мы имеем all_stocks – это dataframe с информацией по всем акциям.

Выражение listlevels = sorted(all_stocks[“LISTLEVEL”].unique())

Здесь метод .unique() используется для возврата уникальных значений в колонке “LISTLEVEL” нашего датафрейма all_stocks. В результате будет создан массив (listlevels) из уникальных значений в колонке listlevel. И сразу же методом sort() отсортируем значения в массиве listlevels. Получим [1, 2, 3].

with open(“stock_listing.txt”, “w”, encoding=”utf-8″) as file:

в этом коде используется оператора with в сочетании с функцией open(). Оператор with используется для автоматического управления ресурсами, такими как файлы или соединения с базами данных. Он гарантирует, что после выполнения блока кода ресурсы будут корректно закрыты или освобождены.

В этом коде функция open() используется для открытия файла с именем “stock_listing.txt” в режиме записи (“w”). Оператор with используется для гарантии правильного закрытия файла после того, как он больше не нужен. Если файла stock_listing.txt нет, то он будет создан, если есть – перезаписан. Благодаря with, нам не нужно вызывать метод file.close(), так как он автоматически будет выполнен после выхода из блока кода.

print(f”Всего в Алгопаке доступны данные по {all_stocks.shape[0]} акциям Мосбиржи”, file=file)

print выводит сообщение в терминал, а print с параметром file – записывается в файл. В фигурных скобках выполняется выражение {all_stocks.shape[0]}, в котором применен атрибут shape у объекта all_stocks, чтобы узнать количество строк в нем. Атрибут shape возвращает кортеж с двумя элементами: количество строк и количество столбцов в датафрейме, соответственно элемент [0] содержит количество строк. Фактически мы узнали сколько строк в нашем DataFrame с информацией по акциям, т.е. узнали количество акций.

Далее запускаем цикл for level in listlevels: , т.е. выполняется итерация по элементам переменной listlevels. На каждой итерации значение level будет содержать очередной элемент из listlevels, т.е. на каждой итерации в переменную level будет попадать очередное значение из listlevels, которая содержит уникальные уровни листинга.

В цикле происходит следующее:

stocks_level = all_stocks[all_stocks[“LISTLEVEL”] == level]
Здесь происходит фильтрация данных. Мы берем весь датафрейм all_stocks и отбираем из него только те строки, в которых значение в столбце LISTLEVEL равно текущему значению переменной level, например 1,2 или 3. В результате в stocks_level будут записаны данные только по тем акциям, которые имеют текущее значение LISTLEVEL.

print(f”Для {level} уровня листинга отобрано {stocks_level.shape[0]} акций:”)

Выводим сообщение в терминал (в файл с параметром file) о том, какое количество акций отобрано для каждого уровня листинга.

list_tickers = stocks_level[“SECID”].tolist()
Здесь из отфильтрованных данных по акциям stocks_level (датафрейм) извлекаем столбец с тикерами акций (‘SECID’) и преобразуем его в список с помощью tolist().

.tolist() – это метод, который используется для преобразования массива в список (list).Таким образом в list_tickers попадают тикеры всех акций с текущим уровнем листинга.

Аналогично создаем список list_shortnames с перечнем SHORTNAME всех акций текущего уровня листинга.

Далее выводим список тикеров и названий акций из двух списков. Для этого используем функцию zip для объединения двух списков list_tickers и list_shortnames в один итератор, который возвращает кортежи из элементов с одинаковыми индексами. В каждом кортеже будут содержаться элементы из соответствующих позиций исходных итерируемых объектов (списков). Это удобно, когда нужно проходить по нескольким спискам одновременно и выполнять операции с элементами из одной и той же позиции в каждом списке.

Выводим с помощью цикла for в терминал и файл список из пар элементов (ticker и shortname) из созданного функцией zip кортежа.

На каждой итерации цикла мы будем получать данные для очередного уникального LISTLEVEL.


Собственно говоря выше детально описан весь код. Надеюсь, что в нем все понятно)) Результат работы программы будет выведен в терминал и продублирован в текстовый файл, можете посмотреть сохраненную копию stock_listing.txt .

Теперь я буду писать вторую часть кода для непосредственного скачивания исторических данных с выбором:
— какой-либо конкретной акции,
— либо всех акций заданного уровня листинга,
— или вообще всех 248 акций
— за определенный период
— с заданным таймфреймом.

И это тема для следующей публикации. Продолжение следует..

Чтобы быть в курсе Telegram-канал Алготрейдинг на Python

Видео по теме:

| ★8

Читайте на SMART-LAB:
Фото
Снижение военной премии в нефти: что это меняет для доллара и G10
Во второй половине понедельника – начале вторники рынки активно пересматривают премию за худший сценарий на энергетическом рынке, что цепочкой...
Фото
12 марта Группа Ренессанс страхование опубликует МСФО за 2025 год
Напоминаем, что 12 марта 2026 года RENI опубликует МСФО Группы за 2025 год, а также проведет День инвестора, чтобы рассказать о ситуации на...
Фото
📈 Новый выпуск облигаций МГКЛ уже торгуется на рынке
Биржевые облигации ПАО «МГКЛ» серии 001PS-02 начали торговаться на вторичном рынке после размещения. 💼 Выпуск доступен для неквалифицированных...
Фото
Гендиректор Инарктики продал свои акции компании. Что это может значить?
Вечером в пятницу (6 марта ) вышел сущфакт о том, что Соснов Илья Геннадьевич, гендиректор Инарктики, продал свои акции компании. В нашем...

теги блога Beekeeper-algo

....все тэги



UPDONW
Новый дизайн