Справочник REST API FinaQuotes

REST API FinaQuotes дополняет WebSocket-фид котировок обычными HTTPS-запросами. Через него доступны история свечей OHLC на девяти таймфреймах, каталог инструментов, которые отдаёт фид, сводка по классам активов и логотипы инструментов. API рассчитан на брокеров, торговые платформы и финансовые сайты, которые уже подключены к фиду и строят графики, списки символов и справочники.

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

Базовый URL и формат

  • Базовый URL: https://feed.finaquotes.com/api/v1/ (только HTTPS).
  • Все эндпоинты - запросы GET с query-параметрами.
  • Ответы в JSON. Время - миллисекунды от начала эпохи Unix, всегда UTC.
  • Версия входит в путь. Со временем в ответах могут появляться новые поля, поэтому разбирайте ответ по именам и пропускайте незнакомые поля.
ЭндпоинтНазначениеТокен
/api/v1/instrumentsКаталог инструментовнужен
/api/v1/categoriesКлассы активов и их размернужен
/api/v1/candlesИстория цен OHLCнужен
/api/v1/logos/...Логотипы инструментовне нужен
/api/v1/healthДоступность сервисане нужен

Аутентификация

Эндпоинты каталога и истории аутентифицируются одним заголовком:

заголовок
x-history-token: YOUR_HISTORY_TOKEN

Токен персональный. Его выдаёт оператор вместе с учётными данными фида, и он привязан к той же клиентской учётной записи, что и доступ к WebSocket. Если доступ отозван, истёк или ротирован, REST-токен тоже перестаёт работать.

Запрос без валидного токена получает 404 с пустым телом. Так задумано: API не подтверждает, что защищённый эндпоинт существует. Если 404 приходит на любой запрос, сначала проверьте имя заголовка и значение токена.

Держите токен на сервере Обращайтесь к API со своего бэкенда и отдавайте страницам уже готовые данные. Не встраивайте токен в браузерный код или мобильное приложение, где его может прочитать пользователь.

GET /api/v1/instruments

Возвращает каталог активных инструментов, которые отдаёт фид. Он совпадает с ответом Symbols WebSocket-фида один в один: те же символы и та же точность цены. Цен в ответе нет.

ПараметрТипОписание
categorystring, необязательныйФильтр по классу активов: crypto, stocks, forex, metals, commodities, indices или bonds. Неизвестное значение возвращает 400. Без параметра приходит весь каталог.

Ответ - объект с полем count (число элементов в instruments) и массивом instruments, отсортированным по категории, затем по символу. Акция и валютная пара выглядят так:

json
{
  "symbol": "AAPL",
  "name": "Apple Inc.",
  "category": "stocks",
  "currency": "USD",
  "digits": 2,
  "session": "nasdaq",
  "logo": {
    "icon": "https://feed.finaquotes.com/api/v1/logos/icon/AAPL.webp?v=b7b8407f",
    "full": "https://feed.finaquotes.com/api/v1/logos/logo/AAPL.svg?v=5165a409"
  }
}
{
  "symbol": "AUDCAD",
  "name": "Australian Dollar / Canadian Dollar",
  "category": "forex",
  "currency": "CAD",
  "digits": 5,
  "session": "forex_24_5",
  "logo": null
}
ПолеТипЗначение
symbolstringТикер в том виде, в каком его использует фид. Тикеры с точкой передаются без неё: BRK.B → BRKB.
namestringЧитаемое название инструмента.
categorystringКласс активов, одно из значений выше.
currencystringВалюта котировки.
digitsintЧисло знаков после запятой в цене - совпадает с Precision в фиде.
sessionstringТип торговой сессии, например 24_7, nasdaq, forex_24_5.
logoobject | nullАбсолютные ссылки icon и full или null, если логотипа нет. Каждая из ссылок внутри объекта тоже может быть null. См. Логотипы.

GET /api/v1/categories

Список классов активов с числом активных инструментов в каждом. Порядок фиксированный, класс без активных инструментов тоже присутствует - с нулём, поэтому ответ можно выводить как статичное меню.

структура
{
  "count": 7,
  "categories": [
    { "category": "crypto", "count": <int> },
    { "category": "stocks", "count": <int> },
    ...
  ]
}

Верхнеуровневый count - число классов активов. Количество инструментов в классе растёт вместе со списком, не зашивайте его в код.

GET /api/v1/candles

История цен OHLCV по одному инструменту. Свечи строятся из минутных баров, старшие таймфреймы агрегируются из них. Все бары выровнены по UTC. Свечи акций есть только в часы торгов биржи листинга, с учётом перехода на летнее время; премаркет и постмаркет акций США добавляются параметром session=extended (см. ниже). В архиве - годы дневной истории и месяцы внутридневной.

ПараметрТипОписание
symbolstring, обязательныйСимвол фида из каталога, например AAPL, EURUSD, BRKB.
tfstringТаймфрейм: 1m, 5m, 15m, 30m, 1H, 4H, 1D, 1W или 1MN. Регистр важен.
fromint, необязательныйНачало диапазона, миллисекунды от эпохи Unix (UTC).
toint, необязательныйКонец диапазона, миллисекунды от эпохи Unix (UTC).
limitint, необязательныйЧисло баров. По умолчанию 1000, максимум 5000.
sessionstring, необязательныйregular (по умолчанию) - только основная торговая сессия. extended - вместе с премаркетом и постмаркетом акций США; нужны включённые для аккаунта расширенные часы.
json
{
  "symbol": "AAPL",
  "tf": "1H",
  "candles": [
    { "ts": 1782928800000, "open": 293.725, "high": 295.53, "low": 292.7, "close": 294.72, "volume": 4190956, "trades": 43640 },
    { "ts": 1782932400000, "open": 294.73, "high": 295.55, "low": 293.7501, "close": 294.25, "volume": 5363332, "trades": 59130 }
  ]
}
ПолеТипЗначение
tsintВремя открытия бара, UTC, миллисекунды.
open, high, low, closenumberЦены OHLC бара.
volumenumberОбъём торгов за бар.
tradesintЧисло сделок за бар.

Неверный tf или отсутствующий symbol возвращают 400, неизвестный символ - 404. Если период не помещается в один ответ, разбейте его на последовательные окна через from и to. Текущий, ещё не закрытый бар обновляется в реальном времени через WebSocket-фид, поэтому график обычно один раз грузит историю по REST, а дальше следует за фидом.

Расширенные часы (акции США)

С session=extended ответ для 1m, 5m, 15m, 30m, 1H и 4H содержит бары основной сессии вместе с барами премаркета (04:00-09:30) и постмаркета (16:00-20:00 по нью-йоркскому времени) акций США. Для остальных инструментов результат тот же, что с regular.

  • Для 1D, 1W и 1MN параметр ни на что не влияет: дневные и более старшие бары всегда строятся по основной сессии.
  • Если для аккаунта не включены расширенные часы, session=extended возвращает 403. Чтобы их включить, напишите в поддержку через вашего менеджера.
  • Любое значение, кроме regular и extended, возвращает 400.
запрос
curl -H "x-history-token: YOUR_HISTORY_TOKEN" \
  "https://feed.finaquotes.com/api/v1/candles?symbol=AAPL&tf=5m&session=extended&limit=500"
Нужен параметр, которого здесь нет, или более глубокая история по конкретному инструменту? Это не входит в публичный API - напишите команде FinaQuotes через вашего менеджера.

GET /api/v1/logos/{icon|logo}/{SYMBOL}.{ext}

Логотипы инструментов - статические файлы. Это публичные бренд-ассеты, поэтому токен не нужен, а файлы можно грузить прямо в браузере. Берите ссылки из поля logo каталога, а не собирайте их вручную.

  • icon - квадратная растровая иконка для списков инструментов.
  • logo - широкий логотип, чаще SVG, для карточки инструмента.
  • SYMBOL - символ каталога (BRKB, а не BRK.B).
  • ?v=... - версия по содержимому. Ссылка с версией кэшируется на год как неизменяемая; при обновлении логотипа каталог вернёт новый v.

Логотипы есть у акций. У остальных классов активов в каталоге logo: null. Нет файла - 404.

GET /api/v1/health

Публичная проверка доступности для вашего мониторинга. Токен не нужен. Возвращает 200, когда сервис здоров ("status": "ok"), и 503 при деградации ("status": "degraded").

json
{
  "status": "ok",
  "uptimeSec": 3600,
  "components": { ... }
}

Ориентируйтесь на HTTP-статус и поле status. Содержимое components - диагностическое и может меняться.

Лимиты

REST-запросы ограничиваются по IP-адресу клиента. По умолчанию - 120 запросов в минуту, на части эндпоинтов лимит выше. У логотипов свой, заметно больший лимит на всплески, чтобы список мог подгрузить сразу много иконок. Запрос сверх лимита получает 429.

  • Кэшируйте каталог и категории у себя и обновляйте раз в несколько минут, а не на каждый просмотр страницы.
  • Грузите историю один раз при открытии графика, дальше следуйте за обновлениями WebSocket-фида.
  • На 429 подождите и повторите с экспоненциальной задержкой, а не сразу.

Оплаты за запрос нет. В WebSocket-фиде нет и тарификации за сообщение.

Коды ответов

КодКогда
200Успех.
400Неверные параметры: неизвестная category, неверный tf или session, нет symbol.
403session=extended в /candles, когда для аккаунта не включены расширенные часы.
404Нет или неверный x-history-token (пустое тело), неизвестный символ в /candles или несуществующий файл логотипа.
429Превышен лимит - подождите и повторите позже.
503/health сообщает о деградации сервиса.

Примеры

curl

shell
# Форекс-часть каталога
curl -H "x-history-token: YOUR_HISTORY_TOKEN" \
  "https://feed.finaquotes.com/api/v1/instruments?category=forex"

# Последние 500 дневных свечей EURUSD
curl -H "x-history-token: YOUR_HISTORY_TOKEN" \
  "https://feed.finaquotes.com/api/v1/candles?symbol=EURUSD&tf=1D&limit=500"

# Проверка доступности, без токена
curl -i "https://feed.finaquotes.com/api/v1/health"

Python

Только стандартная библиотека. Токен читается из переменной окружения, чтобы не попадать в код.

history.py
import json
import os
import time
import urllib.error
import urllib.parse
import urllib.request

BASE = "https://feed.finaquotes.com/api/v1"
TOKEN = os.environ["FINAQUOTES_HISTORY_TOKEN"]


def get(path, **params):
    url = BASE + path + "?" + urllib.parse.urlencode(params)
    req = urllib.request.Request(url, headers={"x-history-token": TOKEN})
    for attempt in range(5):
        try:
            with urllib.request.urlopen(req, timeout=15) as resp:
                return json.load(resp)
        except urllib.error.HTTPError as e:
            if e.code == 429:
                time.sleep(2 ** attempt)
                continue
            raise
    raise RuntimeError("rate limited: " + url)


catalog = get("/instruments", category="stocks")
print(catalog["count"], "stocks in the catalog")

week_ms = 7 * 24 * 3600 * 1000
now_ms = int(time.time() * 1000)
bars = get("/candles", symbol="AAPL", tf="1H", **{"from": now_ms - week_ms, "to": now_ms})
for bar in bars["candles"][-3:]:
    print(bar["ts"], bar["open"], bar["high"], bar["low"], bar["close"])

См. также