Состав индекса мосбиржи
Есть ли возможность вытаскивать состав индекса и доли бумаг в нем? Например imoex?
В принципе можно с помощью этого запроса к API https://iss.moex.com/iss/reference/147, но специально такая функция не реализована. При желании можно с помощью клиента получить данные:
import requests
import apimoex
import pandas as pd
api_url = 'https://iss.moex.com/iss/statistics/engines/stock/markets/index/analytics/IMOEX.json'
with requests.Session() as session:
iss = apimoex.ISSClient(session, api_url)
data = iss.get_all()
df = pd.DataFrame(data['analytics'])
print(df)
К сожалению это недостоверная информация, возможно тестовые данные.
В индексе сейчас 43 бумаги:
https://www.moex.com/ru/index/IMOEX/constituents/
Так и тут 43 - нумерация с нуля идет
indexid tradedate ticker shortnames secids weight tradingsession
0 IMOEX 2022-04-18 AFKS Система ао AFKS 0.33 3
1 IMOEX 2022-04-18 AFLT Аэрофлот AFLT 0.27 3
2 IMOEX 2022-04-18 ALRS АЛРОСА ао ALRS 1.64 3
3 IMOEX 2022-04-18 CBOM МКБ ао CBOM 0.31 3
4 IMOEX 2022-04-18 CHMF СевСт-ао CHMF 1.55 3
5 IMOEX 2022-04-18 DSKY ДетскийМир DSKY 0.33 3
6 IMOEX 2022-04-18 ENPG ЭН+ГРУП ао ENPG 0.55 3
7 IMOEX 2022-04-18 FEES ФСК ЕЭС ао FEES 0.19 3
8 IMOEX 2022-04-18 FIVE FIVE-гдр FIVE 1.09 3
9 IMOEX 2022-04-18 FIXP FIXP-гдр FIXP 0.72 3
10 IMOEX 2022-04-18 GAZP ГАЗПРОМ ао GAZP 15.98 3
11 IMOEX 2022-04-18 GLTR GLTR-гдр GLTR 0.31 3
12 IMOEX 2022-04-18 GMKN ГМКНорНик GMKN 9.01 3
13 IMOEX 2022-04-18 HHRU iHHRU-адр HHRU 0.46 3
14 IMOEX 2022-04-18 HYDR РусГидро HYDR 0.74 3
15 IMOEX 2022-04-18 IRAO ИнтерРАОао IRAO 0.73 3
16 IMOEX 2022-04-18 LKOH ЛУКОЙЛ LKOH 13.06 3
17 IMOEX 2022-04-18 MAGN ММК MAGN 0.76 3
18 IMOEX 2022-04-18 MGNT Магнит ао MGNT 2.36 3
19 IMOEX 2022-04-18 MOEX МосБиржа MOEX 1.12 3
20 IMOEX 2022-04-18 MTSS МТС-ао MTSS 1.48 3
21 IMOEX 2022-04-18 NLMK НЛМК ао NLMK 1.61 3
22 IMOEX 2022-04-18 NVTK Новатэк ао NVTK 5.77 3
23 IMOEX 2022-04-18 OZON OZON-адр OZON 0.46 3
24 IMOEX 2022-04-18 PHOR ФосАгро ао PHOR 1.95 3
25 IMOEX 2022-04-18 PIKK ПИК ао PIKK 0.69 3
26 IMOEX 2022-04-18 PLZL Полюс PLZL 3.38 3
27 IMOEX 2022-04-18 POGR Petropavl POGR 0.19 3
28 IMOEX 2022-04-18 POLY Polymetal POLY 2.48 3
29 IMOEX 2022-04-18 ROSN Роснефть ROSN 3.87 3
30 IMOEX 2022-04-18 RTKM Ростел -ао RTKM 0.49 3
31 IMOEX 2022-04-18 RUAL РУСАЛ ао RUAL 1.44 3
32 IMOEX 2022-04-18 SBER Сбербанк SBER 8.89 3
33 IMOEX 2022-04-18 SBERP Сбербанк-п SBERP 0.89 3
34 IMOEX 2022-04-18 SNGS Сургнфгз SNGS 1.84 3
35 IMOEX 2022-04-18 SNGSP Сургнфгз-п SNGSP 1.60 3
36 IMOEX 2022-04-18 TATN Татнфт 3ао TATN 2.12 3
37 IMOEX 2022-04-18 TATNP Татнфт 3ап TATNP 0.41 3
38 IMOEX 2022-04-18 TCSG TCS-гдр TCSG 2.72 3
39 IMOEX 2022-04-18 TRNFP Транснф ап TRNFP 0.54 3
40 IMOEX 2022-04-18 VKCO VK-гдр VKCO 0.44 3
41 IMOEX 2022-04-18 VTBR ВТБ ао VTBR 0.77 3
42 IMOEX 2022-04-18 YNDX Yandex clA YNDX 4.45 3
Странно, я дёрнул https://iss.moex.com/iss/statistics/engines/stock/markets/index/analytics/IMOEX.json
Там гораздо меньше строк:
{ "analytics": { "metadata": { "indexid": {"type": "string", "bytes": 36, "max_size": 0}, "tradedate": {"type": "date", "bytes": 10, "max_size": 0}, "ticker": {"type": "string", "bytes": 36, "max_size": 0}, "shortnames": {"type": "string", "bytes": 189, "max_size": 0}, "secids": {"type": "string", "bytes": 36, "max_size": 0}, "weight": {"type": "double"}, "tradingsession": {"type": "int32"} }, "columns": ["indexid", "tradedate", "ticker", "shortnames", "secids", "weight", "tradingsession"], "data": [ ["IMOEX", "2022-04-18", "AFKS", "Система ао", "AFKS", 0.33, 3], ["IMOEX", "2022-04-18", "AFLT", "Аэрофлот", "AFLT", 0.27, 3], ["IMOEX", "2022-04-18", "ALRS", "АЛРОСА ао", "ALRS", 1.64, 3], ["IMOEX", "2022-04-18", "CBOM", "МКБ ао", "CBOM", 0.31, 3], ["IMOEX", "2022-04-18", "CHMF", "СевСт-ао", "CHMF", 1.55, 3], ["IMOEX", "2022-04-18", "DSKY", "ДетскийМир", "DSKY", 0.33, 3], ["IMOEX", "2022-04-18", "ENPG", "ЭН+ГРУП ао", "ENPG", 0.55, 3], ["IMOEX", "2022-04-18", "FEES", "ФСК ЕЭС ао", "FEES", 0.19, 3], ["IMOEX", "2022-04-18", "FIVE", "FIVE-гдр", "FIVE", 1.09, 3], ["IMOEX", "2022-04-18", "FIXP", "FIXP-гдр", "FIXP", 0.72, 3], ["IMOEX", "2022-04-18", "GAZP", "ГАЗПРОМ ао", "GAZP", 15.98, 3], ["IMOEX", "2022-04-18", "GLTR", "GLTR-гдр", "GLTR", 0.31, 3], ["IMOEX", "2022-04-18", "GMKN", "ГМКНорНик", "GMKN", 9.01, 3], ["IMOEX", "2022-04-18", "HHRU", "iHHRU-адр", "HHRU", 0.46, 3], ["IMOEX", "2022-04-18", "HYDR", "РусГидро", "HYDR", 0.74, 3], ["IMOEX", "2022-04-18", "IRAO", "ИнтерРАОао", "IRAO", 0.73, 3], ["IMOEX", "2022-04-18", "LKOH", "ЛУКОЙЛ", "LKOH", 13.06, 3], ["IMOEX", "2022-04-18", "MAGN", "ММК", "MAGN", 0.76, 3], ["IMOEX", "2022-04-18", "MGNT", "Магнит ао", "MGNT", 2.36, 3], ["IMOEX", "2022-04-18", "MOEX", "МосБиржа", "MOEX", 1.12, 3] ] }, "analytics.cursor": { "metadata": { "INDEX": {"type": "int64"}, "TOTAL": {"type": "int64"}, "PAGESIZE": {"type": "int64"},
Данный запрос имеет страничную выдачу - размер страницы 20. Нужно дополнительно запрашивать следующие страницы. Вызов
iss = apimoex.ISSClient(session, api_url)
data = iss.get_all()
автоматически определяет наличие и выкачивает все страницы. Если сделать вызов
iss = apimoex.ISSClient(session, api_url)
data = iss.get()
То будет получена только первая страница, как у вас.
Спасибо, вы очень помогли
Предлагаю упаковать в функцию, в файл requests.py. Вариант:
def get_index_tickers(
session: requests.Session,
index: str,
date: Optional[str] = None,
columns: Optional[Tuple[str, ...]] = (
"ticker",
"from",
"till",
"tradingsession",
),
market: str = "index",
engine: str = "stock",
):
"""Получить информацию по составу указанного индекса за указанную дату.
Описание запроса - https://iss.moex.com/iss/reference/148
:param session:
Сессия интернет соединения.
:param index:
Название индекса. Например, IMOEX. Список: https://iss.moex.com/iss/statistics/engines/stock/markets/index/analytics
:param date:
Дата вида ГГГГ-ММ-ДД. Если указано, то будут показаны только активные инструменты, по которым тогда рассчитывалось значение индекса. Если в указанный день не было торгов, то вернёт пустой список! При отсутствии данные будут загружены с начала истории.
:param columns:
Кортеж столбцов, которые нужно загрузить - по умолчанию режим торгов, дата торгов, цена закрытия и объем в
штуках и стоимости. Если пустой или None, то загружаются все столбцы.
:param market:
Рынок - по умолчанию индексы.
:param engine:
Движок - по умолчанию акции.
:return:
Список словарей, которые напрямую конвертируется в pandas.DataFrame.
"""
url = (
f"https://iss.moex.com/iss/statistics/engines/{engine}/markets/{market}/"
f"analytics/{index}/tickers.json"
)
table = "tickers"
query = _make_query(date=date, table=table, columns=columns)
return _get_short_data(session, url, table, query)
Ещё добавить в тот же файл:
__all__ = [
...
"get_index_tickers",
]
def _make_query(
...
date: Optional[str] = None,
...
) :
...
:param date:
Точная дата (используется при получении тикеров в индексе).
...
if date:
query["date"] = date
А это в автотесты:
def test_get_index_tickers(session):
data = requests.get_market_history(session, index='IMOEX', date='2023-03-03')
assert len(data) == 40
assert data[15]['ticker'] == 'MAGN'
assert data[25]['till'] == '2023-03-03'
assert data[35]['tradingsession'] == 3
Без проблем - делайте PR