ErmiData API — Документация
REST API и WebSocket для получения ML-скоров по инструментам. Основной идентификатор — ISIN. Публичные таргеты: 7 alias, обновляются ежедневно.
Интерактивный Swagger UI (OpenAPI) открывается в отдельном окне: там можно выполнять запросы прямо из браузера с вашим API-ключом (кнопка Authorize).
Быстрый старт
1. Получите API-ключ
- Зарегистрируйтесь на ERMIAS Platform
- Перейдите в личный кабинет → Подписка
- Активируйте тариф (Trial / Lite / Standard / Pro)
- Скопируйте API-ключ из личного кабинета
2. Сделайте запрос
import requests
API_KEY = "your_api_key_here"
headers = {"X-API-Key": API_KEY}
# Получить сегодняшние таргеты по всем инструментам
response = requests.get(
"https://api.app-trading.ru/v1/targets/today",
headers=headers
)
payload = response.json()
# envelope: {"success": true, "data": {...}, "meta": {...}}
if not payload["success"]:
raise RuntimeError(payload["error"]["message"])
data = payload["data"]
print(f"Снимок от {data['generated_at']} до {data['valid_until']}")
print(f"Инструментов: {data['count']}")
first = data["targets"][0]
print(f"{first['ticker']} ({first['isin']}):")
for alias, score in first["probabilities"].items():
print(f" {alias}: {score:.4f}")
3. Формат ответа
Пример — реальный ответ GET /v1/targets/today. В probabilities каждого объекта
попадают только alias, выбранные для вашего тарифа (значения 0.0–1.0); остальные ключи
отсутствуют и не заполняются null.
{
"success": true,
"data": {
"date": "2026-09-08",
"generated_at": "2026-09-08T11:05:56+03:00",
"valid_until": "2026-09-08T18:50:00+03:00",
"count": 77,
"targets": [
{
"isin": "RU0009029540",
"ticker": "SBER",
"name": "SBER",
"sector": "financial",
"probabilities": {
"base_vector": 0.5202,
"lower_progression": 0.3821
}
}
]
},
"meta": {
"generated_at": "2026-09-08T22:22:57+03:00",
"request_id": "938fb707-97e6-4f50-959b-776f453d0d30",
"disclaimer": "Информация предоставляется только для аналитических целей..."
}
}
Формат ответа и ошибки
Единый envelope
Все JSON-ответы имеют одну форму. Успех: success=true, данные — в блоке data.
Ошибка: success=false, объект error с кодом, сообщением и контекстом.
Блок meta всегда присутствует: generated_at, request_id
(совпадает с заголовком x-request-id) и disclaimer.
{
"success": false,
"error": {
"code": 401,
"message": "Missing X-API-Key header",
"details": null,
"limit": null,
"reset_at": null
},
"meta": {
"generated_at": "2026-09-08T22:19:42+03:00",
"request_id": "455ebbfc-93ec-4f5f-81a3-348aed752eb1",
"disclaimer": "Информация предоставляется только для аналитических целей..."
}
}
При превышении дневной квоты (429) в полях error.limit и error.reset_at
приходят размер квоты и время её сброса. CSV-endpoints при ошибке возвращают тот же JSON, а не пустой файл.
Rate-limit заголовки
| Заголовок | Описание |
|---|---|
x-ratelimit-limit |
Дневная квота запросов тарифа (500 / 500 / 2 000 / 10 000) |
x-ratelimit-remaining |
Осталось запросов в текущем московском дне |
x-ratelimit-reset |
Время сброса счётчика, ISO 8601 со смещением Europe/Moscow |
x-request-id |
Уникальный идентификатор запроса; совпадает с meta.request_id |
REST API Endpoints
Публичные (без ключа)
Тарифный каталог. Возвращает список доступных планов и их параметров.
Каталог всех семи публичных alias с маркетинговыми названиями и описаниями.
С X-API-Key
Статус ключа и текущего снимка: состояние рынка, время генерации ML-скоров и срок их действия,
количество активных инструментов, индикатор торгового дня. Остаток квоты виден в заголовках
x-ratelimit-*.
{
"success": true,
"data": {
"status": "closed",
"date": "2026-09-08",
"targets_generated_at": "2026-09-08T11:05:56+03:00",
"targets_valid_until": "2026-09-08T18:50:00+03:00",
"instruments_count": 93,
"is_trading_day": true
},
"meta": { /* ... */ }
}
Каталог активных инструментов MOEX — одинаковый для всех тарифов. Поля объекта:
id, isin, ticker, name, sector,
class_code, flag_work, flag_work_inday, wave.
FIGI и внутренние колонки не публикуются.
{
"success": true,
"data": {
"count": 93,
"instruments": [
{
"id": 65,
"isin": "RU000A0DQZE3",
"ticker": "AFKS",
"name": "AFKS",
"sector": "financial",
"class_code": "TQBR",
"flag_work": 1,
"flag_work_inday": 0,
"wave": 2
}
]
}
}
Полностью сегодняшний снимок ML-скоров. data.targets — массив объектов по всем активным
инструментам, в probabilities каждого — только alias, выбранные для вашего тарифа.
data.count равен длине массива. Формат ответа — в разделе «Быстрый старт».
Таргеты одного инструмента. В отличие от общего снимка, объект лежит в
data.target: {isin, ticker, name, sector, probabilities} + метаданные
снимка date, generated_at, valid_until.
Неизвестный или неактивный ISIN — 404 Instrument not found.
| Параметр | Тип | Описание |
|---|---|---|
isin |
path | ISIN инструмента из каталога /v1/instruments (обязательно) |
История снимков по инструменту. Строки data.history[]:
{date, generated_at, valid_until, probabilities}. Глубина считается в уникальных
торговых датах; запрос глубже лимита тарифа — 403.
| Параметр | Тип | Описание |
|---|---|---|
isin |
path | ISIN инструмента (обязательно) |
days |
int | Сколько последних торговых дней вернуть (по умолчанию — максимум тарифа; у Pro без параметра — с 2022-01-01) |
Текущий выбор alias: план, лимит, разрешённый набор, описание выбранных таргетов и состояние смены.
{
"success": true,
"data": {
"plan": "lite",
"target_limit": 2,
"count": 2,
"allowed_aliases": ["base_vector", "lower_progression"],
"targets": [
{
"api_alias": "base_vector",
"marketing_name": "Базовый вектор",
"description": "Оценка основного направления ценового смещения...",
"sort_order": 1
}
],
"selection": {
"can_change": true,
"changed_at": "2026-08-06T01:00:52+03:00",
"next_change_at": "2026-08-13T01:00:52+03:00"
}
}
}
Смена набора таргетов (только Lite/Standard). Первое изменение — сразу после выдачи ключа,
следующие — не чаще одного раза в 7 календарных суток; попытка раньше cooldown возвращает
409. Trial и Pro всегда имеют полный набор и получают 403.
| Поле | Тип | Описание |
|---|---|---|
target_aliases |
string[] | Ровно столько уникальных alias, сколько разрешено тарифу (Lite — 2, Standard — 5). Неизвестный, неактивный или повторяющийся alias — 422 |
Content-Type: application/json
{"target_aliases": ["base_vector", "sequence_stability"]}
CSV-выгрузка вероятностей за период — только Pro. Даты раньше 2022-01-01 или неправильный
порядок дат — 422. Файл содержит только инструменты, чья волна входит в
CSV_ALLOWED_WAVES (по умолчанию 1–5), со всеми семью alias.
| Параметр | Тип | Описание |
|---|---|---|
from |
date | Начало периода, YYYY-MM-DD (обязательно) |
to |
date | Окончание периода, YYYY-MM-DD (обязательно) |
Одноразовый маркетинговый CSV для любого тарифа (требуется X-API-Key): все семь alias,
начиная с 2022-01-01, с лагом 30 торговых дней от последней доступной даты, только инструменты с
волнами из CSV_ALLOWED_WAVES. Повторное скачивание того же ключом —
409 Marketing CSV has already been downloaded.
Публичные таргеты
API публикует только 7 alias из внутреннего каталога. Точность, ранки и агрегированный score не публикуются. Тариф определяет количество доступных alias:
| Тариф | Количество alias | Начальный набор |
|---|---|---|
| Trial | 7 (все) | Все 7 alias |
| Lite | 2 на выбор | base_vector, daily_impulse |
| Standard | 5 на выбор | base_vector, daily_impulse, upper_reference, lower_reference, sequence_stability |
| Pro | 7 (все) | Все 7 alias |
Lite и Standard могут изменить выбор сразу после выдачи ключа, затем не чаще одного раза за 7 суток.
WebSocket
Push-уведомление о готовности нового снимка ML-скоров. Доступно в тарифах Standard и Pro:
соединение Trial/Lite закрывается сразу после handshake кодом 1008.
Ключ передаётся заголовком X-API-Key. После подключения сервер сначала шлёт
connected с текущим набором allowed_target_aliases; при появлении нового снимка —
targets_ready, после чего значения нужно запросить через
GET /v1/targets/today именно по этому набору alias. Сессию поддерживает heartbeat.
Неверный, неактивный или просроченный ключ, а также некорректный JSON от клиента — закрытие
кодом 1008. Внутренние имена таргетов по каналу не раскрываются.
Протокол сообщений
| Сообщение | Назначение |
|---|---|
connected |
Первое сообщение после подключения. Поле allowed_target_aliases совпадает с текущим выбором плана и используется для проверки REST-данных |
targets_ready |
Сформирован новый дневной снимок ML-скоров — выполните GET /v1/targets/today |
heartbeat |
Регулярный keep-alive пакет; в бизнес-логике игнорируется |
{"type": "connected", "allowed_target_aliases": ["base_vector", "daily_impulse", "upper_reference", "lower_reference", "sequence_stability"]}
Пример подключения (Python)
import json
import websocket
API_KEY = "your_api_key_here"
def on_message(ws, raw):
message = json.loads(raw)
event = message.get("type")
if event == "connected":
print(f"[WS] Разрешённые alias: {message['allowed_target_aliases']}")
elif event == "targets_ready":
print("[WS] Новый снимок готов — запрашиваем GET /v1/targets/today")
elif event == "heartbeat":
pass # keep-alive
def on_close(ws, status_code, reason):
if status_code == 1008:
print(f"[WS] Соединение закрыто кодом 1008: {reason}")
ws = websocket.WebSocketApp(
"wss://api.app-trading.ru/v1/stream",
on_message=on_message,
on_close=on_close,
header=[f"X-API-Key: {API_KEY}"]
)
ws.run_forever()
Примеры интеграции
Python — Получение ML-скоров
import requests
API_KEY = "your_api_key"
headers = {"X-API-Key": API_KEY}
# Список инструментов
response = requests.get("https://api.app-trading.ru/v1/instruments", headers=headers)
instruments = response.json()["data"]["instruments"]
print(f"Инструментов: {len(instruments)}")
# Таргеты одного инструмента: объект лежит в data.target
response = requests.get(
"https://api.app-trading.ru/v1/targets/today/RU0009029540",
headers=headers
)
target = response.json()["data"]["target"]
print(f"{target['ticker']} ({target['sector']}):")
for alias, score in target["probabilities"].items():
print(f" {alias}: {score:.4f}")
JavaScript — Получение ML-скоров
const API_KEY = "your_api_key";
async function getTodayTargets() {
const response = await fetch(
"https://api.app-trading.ru/v1/targets/today",
{ headers: { "X-API-Key": API_KEY } }
);
const result = await response.json();
if (!result.success) {
throw new Error(result.error.message);
}
console.log(`Снимок: ${result.data.generated_at} → ${result.data.valid_until}`);
console.log(`Инструментов: ${result.data.count}`);
return result.data.targets.map((t) => ({ ticker: t.ticker, probabilities: t.probabilities }));
}
getTodayTargets();
Python — Смена набора таргетов (Lite/Standard)
import requests
API_KEY = "your_api_key"
headers = {"X-API-Key": API_KEY, "Content-Type": "application/json"}
# Посмотреть текущий выбор
current = requests.get("https://api.app-trading.ru/v1/targets/available", headers=headers).json()
print(f"Можно изменить: {current['data']['selection']['can_change']}")
# Сменить набор (не чаще 1 раза за 7 суток)
new_selection = {"target_aliases": ["base_vector", "sequence_stability"]}
response = requests.put(
"https://api.app-trading.ru/v1/targets/available",
headers=headers,
json=new_selection
)
if response.status_code == 409:
# cooldown 7 суток: точное время разблокировки в selection.next_change_at
raise RuntimeError(response.json()["error"]["message"])
if response.status_code == 403:
# тариф не допускает смены набора (Trial / Pro)
raise RuntimeError(response.json()["error"]["message"])
print(response.json())
Лимиты и аутентификация
Аутентификация
Все защищённые запросы должны содержать заголовок
X-API-Key
с вашим API-ключом. Публичные endpoints (/auth/plans, /v1/targets/meta) не требуют ключа.
Тарифные лимиты
| Тариф | Таргеты | REST-история | Запросов/день | WebSocket | Маркетинг CSV |
|---|---|---|---|---|---|
| Trial | 7 (все) | 3 торговых дня | 500 | ✗ | ✓ (одноразово) |
| Lite | 2 на выбор | 30 торговых дней | 500 | ✗ | ✓ (одноразово) |
| Standard | 5 на выбор | 90 торговых дней | 2 000 | ✓ | ✓ (одноразово) |
| Pro | 7 (все) | с 2022-01-01 | 10 000 | ✓ | ✓ + CSV за период |
Коды ответов
| Код | Описание |
|---|---|
200 |
Успех |
401 |
Отсутствует заголовок X-API-Key (Missing X-API-Key header) |
403 |
Неизвестный или неактивный ключ; недостаточный тариф: WS на Trial/Lite, PUT на Trial/Pro, история глубже лимита тарифа |
404 |
Ресурс не найден (Instrument not found для неизвестного ISIN) |
409 |
Конфликт: PUT внутри 7-суточного cooldown; повторное скачивание маркетингового CSV |
422 |
Ошибка валидации: неверное количество или названия alias в PUT, некорректные даты выгрузки CSV |
429 |
Превышен дневной лимит запросов; в теле — error.limit и error.reset_at, в ответах — заголовки x-ratelimit-* |
500 |
Внутренняя ошибка сервера |
503 |
ErmiData недоступно: access_config не настроен или имеет неподдерживаемую версию |
504 |
Gateway timeout (длительная операция, например выгрузка CSV за период) |