Поиск по материалам

ISS MOEX API: как получать свечи, стакан и сделки без авторизации

·

ISS MOEX API — публичный REST-интерфейс Московской биржи: можно бесплатно и без регистрации получать спецификации инструментов, исторические свечи, текущие котировки, стакан и ленту сделок. Подходит для бэктестинга, аналитики и pet-проектов, где не нужна реальная торговля. Разбираем структуру URL, ключевые endpoint, парсинг ответа в pandas, ограничения и где это решение заканчивается.

Что такое ISS MOEX API

ISS — Information Statistical Server — это публичный REST API Московской биржи, доступный по адресу https://iss.moex.com/iss/. Он отдаёт данные обо всём, что торгуется на MOEX: акции, облигации, фьючерсы, опционы, валюты, индексы, ETF, БПИФ. Авторизация не требуется для большинства endpoint — данные публичны.

Что можно получать:

  • Спецификации инструментов: тикер, ISIN, лот, шаг цены, режим торгов, экспирация для деривативов.
  • Исторические свечи (1 минута, 10 минут, час, день, неделя, месяц, квартал).
  • Текущие котировки (с задержкой 15 минут — это реальное ограничение, а не баг).
  • Стакан (биды/аски) — упрощённый, без полной глубины.
  • Лента сделок (тиковые трейды) с задержкой.
  • Корпоративные действия: дивиденды, сплиты, размещения.
  • Индексы (IMOEX, RTSI, отраслевые) — состав и веса бумаг.

Что нельзя:

  • Торговать. ISS — read-only.
  • Получать данные real-time без задержки. Для этого — Plaza-2 или брокерский API (Tinkoff, БКС).
  • Стримить через WebSocket. ISS — чистый REST с polling-моделью.

Для бэктестинга, обзорной аналитики, дашбордов и пет-проектов ISS — оптимальный выбор: бесплатно, не требует регистрации, не блокирует по IP при разумных нагрузках.

Структура URL

Базовая модель URL: iss/<engine>/<market>/<resource>. Engine — это рынок, market — секция этого рынка.

https://iss.moex.com/iss/engines/stock/markets/shares/securities/SBER.json

Разбор:

  • engines/stock — фондовый рынок.
  • markets/shares — акции.
  • securities/SBER — конкретная бумага по тикеру.
  • .json — формат ответа (доступны также .xml, .csv, .html).

Engines, доступные на MOEX:

  • stock — акции, облигации, ETF, БПИФ, ПИФы.
  • futures — фьючерсы и опционы (FORTS).
  • currency — валютный рынок.
  • commodity — товарный рынок (металлы).
  • agro — АГРО-площадка.
  • interventions — валютные интервенции.

Markets внутри stock: shares (акции), bonds (облигации), index (индексы), eq_bob (T-Bond OFZ), etf_bob, foreignshares и др.

Markets внутри futures: forts (срочный рынок), fortsoptions (опционы).

Полный список — https://iss.moex.com/iss/engines/<engine>/markets.json.

Ответ ISS: формат

Ответ ISS — не плоский массив объектов, а табличная структура:

{
  "securities": {
    "metadata": { ... },
    "columns": ["SECID", "BOARDID", "SHORTNAME", "PREVPRICE", "LOTSIZE", ...],
    "data": [
      ["SBER", "TQBR", "Сбербанк", 280.50, 10, ...],
      ...
    ]
  }
}

Это проектная особенность ISS: данные оптимизированы под минимальный размер ответа, поэтому каждая «таблица» отдельно содержит схему (columns) и данные (data). При парсинге надо собирать словари.

Хелпер на Python:

import requests

def iss_get(url, params=None):
    r = requests.get(url, params=params, timeout=15)
    r.raise_for_status()
    raw = r.json()
    out = {}
    for table_name, table in raw.items():
        if isinstance(table, dict) and "columns" in table and "data" in table:
            out[table_name] = [dict(zip(table["columns"], row))
                               for row in table["data"]]
        else:
            out[table_name] = table
    return out

data = iss_get("https://iss.moex.com/iss/engines/stock/markets/shares/securities/SBER.json")
print(data["securities"][:3])

Получение списка инструментов

# Все акции на MOEX в режиме T+1 (TQBR)
url = "https://iss.moex.com/iss/engines/stock/markets/shares/securities.json"
data = iss_get(url)
shares = [s for s in data["securities"] if s["BOARDID"] == "TQBR"]
print(f"акций в TQBR: {len(shares)}")
print(shares[0])

Ответ содержит ~280 акций с тикером, наименованием, лотом, текущей котировкой. Для конкретной бумаги — добавить тикер в URL: securities/SBER.json.

Для фьючерсов:

url = "https://iss.moex.com/iss/engines/futures/markets/forts/securities.json"
data = iss_get(url)
si_futures = [s for s in data["securities"] if s["SECID"].startswith("Si")]

Получение исторических свечей

Свечи живут на отдельном endpoint candles:

GET https://iss.moex.com/iss/engines/stock/markets/shares/securities/SBER/candles.json
    ?from=2026-01-01&till=2026-05-01&interval=60

Где interval — длительность свечи в минутах:

  • 1 — 1 минута
  • 10 — 10 минут
  • 60 — час
  • 24 — день
  • 7 — неделя
  • 31 — месяц
  • 4 — квартал

Полный пример загрузки в pandas:

import pandas as pd
import requests

def get_candles(secid, market="shares", engine="stock",
                from_date="2026-01-01", till_date=None, interval=60):
    if till_date is None:
        till_date = pd.Timestamp.now().strftime("%Y-%m-%d")

    url = (f"https://iss.moex.com/iss/engines/{engine}"
           f"/markets/{market}/securities/{secid}/candles.json")
    candles = []
    start = 0
    while True:
        r = requests.get(url, params={
            "from": from_date,
            "till": till_date,
            "interval": interval,
            "start": start,
        }, timeout=15)
        r.raise_for_status()
        page = r.json()["candles"]
        cols = page["columns"]
        rows = page["data"]
        if not rows:
            break
        candles.extend([dict(zip(cols, row)) for row in rows])
        start += len(rows)
        if len(rows) < 500:  # ISS отдаёт страницами по 500
            break

    df = pd.DataFrame(candles)
    df["begin"] = pd.to_datetime(df["begin"])
    df["end"] = pd.to_datetime(df["end"])
    return df.set_index("begin")[["open", "close", "high", "low", "value", "volume"]]

df = get_candles("SBER", interval=60, from_date="2026-04-01")
print(df.tail())

Важный момент: ISS возвращает данные страницами по 500 свечей. Чтобы получить всю историю, нужно пагинировать через параметр start. Без пагинации вы получите только первые 500 свечей и решите, что данных мало.

Время свечей в ISS — московское (UTC+3), без явного указания TZ в формате. Если бэктест на UTC — нужно конвертировать.

Стакан и сделки

Стакан (только лучшие 20 уровней):

url = "https://iss.moex.com/iss/engines/stock/markets/shares/boards/TQBR/securities/SBER/orderbook.json"
data = iss_get(url)
ob = data["orderbook"]
bids = sorted([b for b in ob if b["BUYSELL"] == "B"],
              key=lambda x: -x["PRICE"])
asks = sorted([b for b in ob if b["BUYSELL"] == "S"],
              key=lambda x: x["PRICE"])
print(f"bid {bids[0]['PRICE']} x {bids[0]['QUANTITY']}")
print(f"ask {asks[0]['PRICE']} x {asks[0]['QUANTITY']}")

Лента сделок (последние 100):

url = "https://iss.moex.com/iss/engines/stock/markets/shares/boards/TQBR/securities/SBER/trades.json"
data = iss_get(url)
trades = data["trades"]
print(f"трейдов в окне: {len(trades)}")
print(trades[-1])

Все эти данные — с задержкой 15 минут относительно реального времени биржи. Для боевого алготрейдинга не подходит, для аналитики и индикаторов на закрытых барах — нормально.

Корпоративные действия и дивиденды

# Дивиденды по бумаге
url = "https://iss.moex.com/iss/securities/SBER/dividends.json"
data = iss_get(url)
divs = data["dividends"]
for d in divs[-5:]:
    print(f"{d['registryclosedate']}: {d['value']} ₽ ({d['currencyid']})")

Этот endpoint — главный источник для любого «календаря дивидендов». Не нужно ходить на Smart-lab или disclosure — данные у биржи в первоисточнике.

Состав индексов

# Состав индекса IMOEX
url = "https://iss.moex.com/iss/statistics/engines/stock/markets/index/analytics/IMOEX.json"
data = iss_get(url)
weights = data["analytics"]
for s in sorted(weights, key=lambda x: -x["weight"])[:10]:
    print(f"{s['ticker']}: {s['weight']:.2f}%")

Аналогично — RTSI, MOEXBC (голубые фишки), MOEXBMI (бенчмарк), отраслевые индексы.

Подводные камни

  • Пагинация. Каждая «большая» выборка отдаётся страницами по 500–1000 строк. Параметр start для смещения. Без пагинации — обрезанный ответ.
  • Поля meta vs data. Иногда нужная информация лежит не в data, а в metadata или дополнительной таблице. Структура candles отличается от securities, и каждое API имеет свои поля.
  • Тайм-зона. ISS возвращает время в московском часовом поясе как «naive datetime» — без указания TZ. Для конверсии в UTC: pd.to_datetime(df['begin']) - pd.Timedelta(hours=3).
  • Праздники и выходные. ISS не выдаёт «нулевых свечей» в нерабочие часы — пропуски в индексе нужно обрабатывать в коде самостоятельно.
  • Переименования бумаг. При смене тикера старый тикер в ISS какое-то время остаётся доступным, потом исчезает. Историю надо подгружать с актуальным тикером.
  • Rate limiting. Биржа официально не публикует лимиты, но при потоке > 10 запросов/секунду с одного IP начинаются 429. Делайте time.sleep(0.1–0.2) между запросами в массовом сборе.
  • Неполные данные за свежие сессии. Свечи за «сегодня» могут содержать только закрытые бары. Активный 5-минутный бар в текущий момент в ответе не появится — для real-time нужен другой источник.

Альтернативы для real-time

ISS — для исторических данных и аналитики. Для боевого алготрейдинга:

  • Tinkoff Invest API (gRPC stream) — real-time свечи без задержки, при наличии счёта.
  • Plaza-2 — прямой биржевой канал для срочного рынка, требует соглашения.
  • TQS / SmartCom (Финам, Алор) — брокерские API, реалтайм есть только при наличии счёта.
  • WebSocket-обёртки третьих сторон — ALOR Open API, Тинькофф WebSocket — но всё через брокерский счёт.

Что запомнить

  • ISS MOEX API — публичный REST биржи, без авторизации, идеально для бэктеста и аналитики.
  • Базовая модель URL: iss/engines/<engine>/markets/<market>/securities/<secid>/<resource>.json.
  • Свечи — на endpoint candles, параметр interval в минутах, пагинация по 500.
  • Котировки и стакан — с задержкой 15 минут. Для боевой торговли использовать брокерский API.
  • Готовый код парсинга — около 30 строк Python с requests и pandas.
  • Дивиденды и состав индексов — там же, в первоисточнике.
MOEX ISS API REST Python pandas данные