DYOR Public API

Документация по работе с публичным batch-эндпоинтом DYOR Platform

1. Что это

DYOR Public API — это единый batch-эндпоинт, через который вы можете запросить агрегированные исторические и рыночные данные платформы DYOR (информация по монетам, рыночные индексы, ликвидации, фандинг, открытый интерес, ордерхистори и т.д.) одним HTTP-запросом, объединяющим до нескольких независимых запросов разных типов.

Объединение запросов в batch снижает накладные расходы (CORS preflight, TLS handshake, установка соединения) и позволяет сократить латентность при загрузке нескольких графиков одновременно.

2. Получение доступа

Доступ продаётся как помесячный апгрейд «Доступ к API» в магазине апгрейдов DYOR. После покупки вы создаёте API-ключ на странице /apiAccount и указываете до двух разрешённых IP-адресов, с которых будут приниматься запросы.

Перейти в магазин апгрейдов →

3. Аутентификация и IP-whitelist

Каждый запрос должен содержать HTTP-заголовок X-API-Key со значением вашего ключа. IP-адрес отправителя сравнивается со списком разрешённых IP, привязанных к ключу. Запросы с IP вне whitelist'а отклоняются с кодом 401.

Управление ключом и IP-списком — на странице /apiAccount. Один ключ на пользователя, до 2 IP в whitelist.

При перегенерации ключа старое значение моментально перестаёт работать. Сохраняйте новый ключ сразу — повторно посмотреть его нельзя, только перегенерировать.

4. Endpoint и примеры запросов

Метод: POST
URL: https://api.dyorplatform.com/publicApi/v1/batch
Content-Type: application/json
Accept: application/json

Пример (curl)

curl -X POST https://api.dyorplatform.com/publicApi/v1/batch \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "requests": [
      {"type": "coinInfo", "params": {"symbol": "btcusdt", "from": 1760081100, "to": 1760081536, "interval": "1m"}},
      {"type": "marketInfo", "params": {"from": 1760081100, "to": 1760081536, "interval": "1m"}}
    ]
  }'

Пример (JavaScript fetch)

const response = await fetch('https://api.dyorplatform.com/publicApi/v1/batch', {
    method: 'POST',
    headers: {
        'X-API-Key': 'YOUR_API_KEY',
        'Content-Type': 'application/json',
        'Accept': 'application/json',
    },
    body: JSON.stringify({
        requests: [
            { type: 'coinInfo', params: { symbol: 'btcusdt', from: 1760081100, to: 1760081536, interval: '1m' } },
            { type: 'funding',  params: { from: 1760000000, to: 1760086400, interval: '1h' } },
        ],
    }),
});
const data = await response.json();
console.log(data.results);

Вспомогательный эндпоинт: список монет

Метод: GET
URL: https://api.dyorplatform.com/publicApi/v1/supportedCoins
Возвращает список всех монет, доступных на платформе — используйте чтобы знать какие symbol можно передавать в batch / WebSocket. Авторизация — тот же ключ X-API-Key с правом batch.

curl https://api.dyorplatform.com/publicApi/v1/supportedCoins \
  -H "X-API-Key: YOUR_API_KEY"

// Ответ — массив:
// [
//   {"symbol": "BTCUSDT", "base": "BTC", "quote": "USDT", "exchangeTypes": ["SPOT", "FUTURES"]},
//   {"symbol": "ETHUSDT", "base": "ETH", "quote": "USDT", "exchangeTypes": ["SPOT", "FUTURES"]},
//   ...
// ]

5. Playground — попробовать вживую

Вставьте ваш API-ключ и тело запроса, нажмите «Отправить» — запрос уйдёт напрямую с вашего браузера на /publicApi/v1/batch. Ключ нигде не сохраняется и не покидает вашу машину между сессиями.

IP-адрес отправителя — это IP вашего браузера. Убедитесь что он есть в whitelist'е ключа на /apiAccount, иначе запрос вернёт 401.

6. WebSocket — real-time стрим

Для real-time данных доступен публичный WebSocket-эндпоинт. Он работает поверх той же подписки «Доступ к API», что и REST batch — отдельной покупки не нужно.

Подключение

URL: wss://api.dyorplatform.com/publicApi/v1/ws?apiKey=YOUR_API_KEY

IP-адрес отправителя должен входить в whitelist ключа. Если ключ или IP не валиден, либо подписка api_access не активна — соединение закрывается с кодом 1008 и причиной (missing_api_key, invalid_api_key, subscription_required).

Протокол сообщений

Клиент отправляет JSON-сообщения с полем action:

// Подписаться
{"action":"subscribe","type":"coinInfo","params":{"symbol":"btcusdt","interval":"1m"}}

// Отписаться
{"action":"unsubscribe","type":"coinInfo","params":{"symbol":"btcusdt","interval":"1m"}}

// Получить список текущих подписок
{"action":"list"}

// Heartbeat (опционально)
{"action":"ping"}

Сервер отвечает JSON-сообщениями с полем type:

// Подтверждение подписки
{"type":"subscribed","for":"coinInfo","params":{"symbol":"btcusdt","interval":"1m"}}

// Подтверждение отписки
{"type":"unsubscribed","for":"coinInfo","params":{"symbol":"btcusdt","interval":"1m"}}

// Список активных подписок (ответ на "list")
{"type":"subscriptions","items":[{"for":"coinInfo","params":{...}}, ...]}

// Real-time обновление — поле data это ОДИН элемент того же типа,
// что возвращается в массиве batch-ответа для соответствующего type
{"type":"update","for":"coinInfo","params":{"symbol":"btcusdt","interval":"1m"},"data":{...}}

// Ошибка — echo действия в поле action для отладки
{"type":"error","code":"unsupported_stream_type","message":"...","action":{...}}

// Heartbeat ответ
{"type":"pong"}

// Перед закрытием по причине истечения подписки
{"type":"closing","reason":"subscription_expired","message":"Active api_access required"}

Массовая подписка (bulk)

Чтобы подписаться на много тикеров одним сообщением — передайте массив symbols в params. Такое сообщение считается за 1 action для rate-limit, независимо от количества тикеров. Поддерживается для типов coinInfo и marginLendingCoin.

// Подписаться сразу на N тикеров (одно action-сообщение)
{
    "action": "subscribe",
    "type": "coinInfo",
    "params": {
        "interval": "1m",
        "symbols": ["btcusdt", "ethusdt", "solusdt", "bnbusdt"]
    }
}

// То же для отписки
{
    "action": "unsubscribe",
    "type": "coinInfo",
    "params": {
        "interval": "1m",
        "symbols": ["btcusdt", "ethusdt"]
    }
}

Сервер возвращает агрегированный ответ с per-symbol статусами:

{
    "type": "bulk_subscribed",
    "for": "coinInfo",
    "params": {"interval": "1m", "symbols": ["btcusdt", "ethusdt", "solusdt", "bnbusdt"]},
    "results": [
        {"symbol": "btcusdt", "status": "ok"},
        {"symbol": "ethusdt", "status": "ok"},
        {"symbol": "solusdt", "status": "ok"},
        {"symbol": "bnbusdt", "status": "error", "code": "invalid_params",
         "message": "type=coinInfo missing or invalid params"}
    ]
}

// Симметрично для unsubscribe:
{"type": "bulk_unsubscribed", "for": "coinInfo", "params": {...}, "results": [...]}

Поддерживаемые типы стрима

Через WebSocket стримятся 5 типов из batch API. Поле data в update-сообщении содержит один элемент той же схемы, которая описана в разделе «Типы запросов» для соответствующего batch-типа.

typeparamsСхема data
coinInfosymbol, intervalсм. coinInfo
marketInfointerval, totalType (опц.)см. marketInfo
minervaScreenerсм. minervaScreener
marginLendingCoinsymbol, intervalсм. marginLendingCoin
marginLendingTotalintervalсм. marginLendingTotal

Типы доступные только через REST batch

Следующие типы не имеют real-time стрима и доступны только через POST /publicApi/v1/batch:

При попытке подписаться на любой из этих типов сервер ответит ошибкой unsupported_stream_type.

Лимиты WebSocket

Коды ошибок

codeОписание
invalid_actionНеизвестное поле action или невалидный JSON.
invalid_paramsОтсутствуют обязательные параметры (например, symbol) или они некорректны.
unsupported_stream_typeТип не поддерживается WebSocket'ом, используйте REST batch.
already_subscribedПодписка с такими параметрами уже активна.
not_subscribedПопытка unsubscribe для несуществующей подписки.
rate_limit_exceededПревышен лимит action-сообщений. В message — через сколько секунд можно повторить.
too_many_subscriptionsДостигнут лимит в 1000 подписок на коннект.
bulk_too_largeВ bulk-сообщении больше 1000 символов в params.symbols.
unsupported_bulkТип не поддерживает массовую подписку через params.symbols (например, marketInfo).
internal_errorВнутренняя ошибка сервера.

v2 endpoint — батчинг сообщений (рекомендуется для high-load)

Для клиентов с большим числом подписок (≥100 тикеров) или с медленным/далёким каналом доступен v2-эндпоинт:

URL: wss://api.dyorplatform.com/publicApi/v2/ws?apiKey=YOUR_API_KEY

Протокол идентичен v1 — те же команды subscribe / unsubscribe / list / ping, те же типы стримов, те же лимиты, те же коды ошибок. Отличие одно: real-time апдейты группируются в батч и отправляются раз в 200 мс одним сообщением. Вместо отдельных сообщений type=update приходит одно сообщение type=batch_update с массивом updates:

{
    "type": "batch_update",
    "updates": [
        {"for": "coinInfo", "params": {"symbol": "btcusdt", "interval": "1m"}, "data": {...}},
        {"for": "coinInfo", "params": {"symbol": "ethusdt", "interval": "1m"}, "data": {...}},
        {"for": "marketInfo", "params": {"interval": "1m"}, "data": {...}}
    ]
}

Каждый элемент массива updates — то же самое, что приходило бы отдельным сообщением type=update в v1, минус поле type. Схема data для каждого for — та же, что в таблице «Поддерживаемые типы стрима» выше.

Контрольные сообщения (subscribed, bulk_subscribed, subscriptions, error, pong, closing) не батчатся — приходят сразу, как в v1.

Когда переходить на v2: если вы получаете ≥50 апдейтов в секунду или видите дисконнекты с кодом 1006 — батчинг резко снижает количество WebSocket-фреймов и нагрузку на TCP, что устраняет основную причину разрывов на медленных каналах (slow-consumer / высокий RTT / packet loss).

Пример (JavaScript)

const ws = new WebSocket('wss://api.dyorplatform.com/publicApi/v1/ws?apiKey=YOUR_API_KEY');

ws.onopen = () => {
    // Подписка на один тикер
    ws.send(JSON.stringify({
        action: 'subscribe',
        type: 'coinInfo',
        params: { symbol: 'btcusdt', interval: '1m' }
    }));

    // Или массовая подписка — одно сообщение, одно action для rate-limit
    ws.send(JSON.stringify({
        action: 'subscribe',
        type: 'coinInfo',
        params: {
            interval: '1m',
            symbols: ['ethusdt', 'solusdt', 'bnbusdt', 'xrpusdt']
        }
    }));
};

ws.onmessage = (event) => {
    const msg = JSON.parse(event.data);
    if (msg.type === 'update' && msg.for === 'coinInfo') {
        console.log('New coinInfo tick:', msg.data);
    } else if (msg.type === 'bulk_subscribed') {
        const ok = msg.results.filter(r => r.status === 'ok').length;
        const errors = msg.results.filter(r => r.status === 'error');
        console.log(`Bulk subscribed: ${ok}/${msg.results.length}`, errors);
    }
};

ws.onclose = (event) => {
    console.log('Closed:', event.code, event.reason);
};

Пример для v2 (JavaScript)

const ws = new WebSocket('wss://api.dyorplatform.com/publicApi/v2/ws?apiKey=YOUR_API_KEY');

ws.onopen = () => {
    ws.send(JSON.stringify({
        action: 'subscribe',
        type: 'coinInfo',
        params: {
            interval: '1m',
            symbols: ['btcusdt', 'ethusdt', 'solusdt', 'bnbusdt']
        }
    }));
};

ws.onmessage = (event) => {
    const msg = JSON.parse(event.data);
    if (msg.type === 'batch_update') {
        // Один батч может содержать N апдейтов от разных тикеров/типов
        for (const u of msg.updates) {
            if (u.for === 'coinInfo') {
                console.log(`tick ${u.params.symbol}:`, u.data);
            }
        }
    } else if (msg.type === 'bulk_subscribed') {
        const ok = msg.results.filter(r => r.status === 'ok').length;
        console.log(`Bulk subscribed: ${ok}/${msg.results.length}`);
    }
};

ws.onclose = (event) => {
    console.log('Closed:', event.code, event.reason);
};

7. Типы запросов и схемы ответов

Каждый элемент массива requests — объект с полем type и полем params. Общие обязательные параметры для всех типов:

Поле data в каждом результате — массив объектов соответствующего типа, упорядоченный по timestamp. Ниже описаны схемы для всех 13 типов.

coinInfo — данные по монете

Свечи и метрики DYOR по конкретной монете: spot/futures объёмы, ликвидации, глубина стакана.

Доп. параметры: symbol (например, btcusdt).

Ответ: массив CoinData:

{
  "_id": 1760081100,
  "interval": "1h",
  "spotTrade": {
    "buys": 125.5, "sells": 98.3,
    "buysUsdt": 5650000.0, "sellsUsdt": 4400000.0,
    "delta": 27.2, "buyTradesCount": 1520, "sellTradesCount": 1340
  },
  "futuresTrade": { "buys": 450.0, "sells": 380.0, "buysUsdt": 20250000.0, "sellsUsdt": 17100000.0, "delta": 70.0 },
  "futuresLiquidation": { "totalLiquidatedLong": 250000.0, "totalLiquidatedShort": 180000.0 },
  "depths": [
    { "percentage": 1.5, "asks": 12.0, "bids": 18.5, "asksUsdt": 540000.0, "bidsUsdt": 832500.0, "delta": 292500.0 }
  ],
  "futuresDepths": []
}

marketInfo — рыночные индексы

Агрегированные индексы рынка: суммарные spot/futures объёмы, ликвидации, дельты стакана.

Доп. параметры (опц.): totalTypeTOTAL, TOTAL2, TOTAL3, TOP100, BOTTOM100. Без него возвращается базовая агрегация.

Ответ: массив TotalData:

{
  "_id": 1760081100,
  "interval": "1h",
  "delta": [
    { "percentage": 1.5, "totalAsks": 450000.0, "totalBids": 520000.0, "delta": 70000.0, "avg": 70000.0 }
  ],
  "futuresDelta": [],
  "totalSpotBuysUsdt": 12500000.0,
  "totalSpotSellsUsdt": 11800000.0,
  "totalSpotBuyTradesCount": 25000,
  "totalSpotSellTradesCount": 24000,
  "totalFuturesBuysUsdt": 45000000.0,
  "totalFuturesSellsUsdt": 42000000.0,
  "totalLiquidatedLong": 5000000.0,
  "totalLiquidatedShort": 3200000.0
}

minervaScreener — Minerva long/short

Тайм-серия по количеству long/short монет из скринера Minerva.

Доп. параметры: нет.

Ответ: массив MinervaScreenerItem:

{ "timestamp": 1760081100, "longCoins": 45, "shortCoins": 38 }

funding — funding rate

Распределение монет по категориям funding rate. Только интервал 1h.

Доп. параметры: нет.

Ответ: объект {items: Funding[]}. Каждый Funding:

{
  "items": [
    {
      "_id": 1760081100,
      "types": [
        { "type": "higher",   "coinsCount": 120, "percentage": 35.2 },
        { "type": "standard", "coinsCount": 150, "percentage": 44.1 },
        { "type": "lower",    "coinsCount":  60, "percentage": 17.6 },
        { "type": "negative", "coinsCount":  10, "percentage":  3.1 }
      ]
    }
  ]
}

totalLiquidations — ликвидации (Coinglass)

Совокупные ликвидации по рынку с разбивкой по биржам.

Доп. параметры: нет.

Ответ: объект {data: CoinglassLiquidation[]}. Каждый элемент:

{
  "data": [
    {
      "_id": 1760081100000,
      "buyQty": 125.5, "sellQty": 98.3,
      "buyVolUsd": 500000.0, "sellVolUsd": 441350.0,
      "buyTurnoverNumber": 42, "sellTurnoverNumber": 35,
      "price": 45000.0,
      "list": [
        { "exchangeName": "Binance", "buyQty": 75.0, "sellQty": 60.0, "buyVolUsd": 300000.0, "sellVolUsd": 270000.0, "buyTurnoverNumber": 25, "sellTurnoverNumber": 20 }
      ]
    }
  ]
}

askBidAnomalies — аномалии стакана

Счётчик аномалий стакана (ask/bid, spot/futures). Только интервал 1h.

Доп. параметры: нет.

Ответ: объект {items: Anomaly[]}:

{
  "items": [
    { "timestamp": 1760081100, "ask": 5, "bid": 3, "askFutures": 2, "bidFutures": 1 }
  ]
}

marginLendingCoin — margin lending по монете

Динамика margin lending по конкретному активу.

Доп. параметры: symbol.

Ответ: массив MarginLendingCoinInterval:

marginLendingTotal — суммарный margin lending

Агрегированный margin lending по всему рынку.

Доп. параметры: нет.

Ответ: массив MarginLendingTotalInterval:

binanceOpenInterestCoin — open interest по монете (Binance)

Доп. параметры: symbol.

Ответ: массив BinanceOpenInterest:

{ "_id": 1760081100, "value": 12500000.0 }

binanceOpenInterestTotal — суммарный open interest

Доп. параметры: нет.

Ответ: массив того же типа что и binanceOpenInterestCoin; value — сумма по всем монетам.

marketCap — market cap нескольких монет

Доп. параметры: symbols — массив строк (например, ["btcusdt", "ethusdt"]).

Ответ: массив MarketCap:

{
  "_id": 1760081100,
  "coinData": { "BTC": 1250000000000.0, "ETH": 285000000000.0 },
  "totalData": { "total": 2100000000000.0, "top100": 1950000000000.0 }
}

marketCapV2 — market cap одной монеты

Доп. параметры: symbol.

Ответ: та же схема MarketCap, но coinData содержит только запрошенный символ.

orderHistory — крупные лимитные ордера

История крупных лимитных ордеров с событиями исполнения.

Доп. параметры: symbol; exchangeTypespot или futures (по умолчанию spot); и либо top (int) — top-N ордеров, либо пара priceRangeStart/priceRangeEnd (double) — фильтр по цене; опционально minQuantityInQuote (double) — минимальный размер ордера в USDT.

Ответ: объект OrderHistoryResponse:

Поля LimitOrder:

{
  "orders": [
    {
      "_id": "order-123456789",
      "side": "BID",
      "price": 45000.0,
      "createdAt": 1760081100000,
      "removedAt": 1760081700000,
      "duration": 600000,
      "coin": "BTC",
      "exchangeType": "SPOT",
      "maxQuantity": 1.5,
      "maxQuantityInQuoteAsset": 67500.0,
      "events": [
        { "timestamp": 1760081150000, "quantity": 0.5 },
        { "timestamp": 1760081500000, "quantity": 1.0 }
      ]
    }
  ],
  "error": ""
}

8. Формат BatchResponse

Ответ всего batch'а — объект с массивом results, элементы которого соответствуют запросам в исходном порядке. Каждый элемент содержит либо data (полезная нагрузка по схеме конкретного типа из раздела 6), либо error (строка с описанием ошибки). Ошибка одного запроса не отменяет batch — остальные результаты возвращаются как обычно.

{
  "results": [
    { "data": [ /* ... */ ], "error": null },
    { "data": null, "error": "Invalid symbol: xxxusdt" }
  ]
}

9. Лимиты

Дефолтный лимит для ключей, выпущенных через подписку «Доступ к API» — 60 запросов в минуту. На каждый ответ возвращаются заголовки:

При превышении лимита возвращается код 429 Too Many Requests и JSON-тело с полями error, limit, remaining, reset.

10. Коды ошибок

КодКогда возвращается
400Невалидный JSON в теле запроса либо неправильная структура batch.
401Отсутствует X-API-Key, ключ невалиден или IP не в whitelist.
403Подписка «Доступ к API» неактивна или на паузе.
429Превышен лимит запросов в минуту (см. раздел «Лимиты»).
500Внутренняя ошибка сервера. Обычно временная — повторите запрос с экспоненциальной задержкой.