1111 lines
30 KiB
Markdown
1111 lines
30 KiB
Markdown
# Build 057 — Исследование REST/WebSocket Trade Feed (Time & Sales)
|
||
|
||
**Engineering Migration Report**
|
||
|
||
---
|
||
|
||
# Контроль документа
|
||
|
||
| Свойство | Значение |
|
||
|----------|----------|
|
||
| Build | 057 |
|
||
| Название | Исследование REST/WebSocket Trade Feed (Time & Sales) |
|
||
| Статус | Completed |
|
||
| Проект | Dzentra |
|
||
| Подсистема | Market Data Acquisition |
|
||
| Компонент | Trades Feed |
|
||
| Версия | 1.0 |
|
||
| Дата | 2026-07-16 |
|
||
|
||
---
|
||
|
||
# Цель Build
|
||
|
||
После завершения полной миграции OHLCV было принято решение перейти к следующему типу рыночных данных — **Trade Feed (Time & Sales)**.
|
||
|
||
Перед реализацией нового канонического модуля требовалось определить:
|
||
|
||
- существует ли полноценный REST API;
|
||
- существует ли полноценный WebSocket Feed;
|
||
- совпадают ли данные REST и WebSocket;
|
||
- какие поля действительно предоставляет биржа;
|
||
- имеются ли скрытые ограничения;
|
||
- какие особенности необходимо учитывать при проектировании новой архитектуры.
|
||
|
||
Главной целью Build являлось **не написание кода**, а инженерное исследование поведения API.
|
||
|
||
---
|
||
|
||
# Исследуемые интерфейсы
|
||
|
||
Были исследованы два независимых источника данных.
|
||
|
||
## REST
|
||
|
||
```
|
||
GET /api/v2/aggTrades
|
||
```
|
||
|
||
Назначение:
|
||
|
||
получение последних агрегированных сделок.
|
||
|
||
Swagger предоставляет параметры:
|
||
|
||
- symbol
|
||
- fromId
|
||
- startTime
|
||
- endTime
|
||
- limit
|
||
|
||
---
|
||
|
||
## WebSocket
|
||
|
||
```
|
||
destination = trades.subscribe
|
||
```
|
||
|
||
назначение:
|
||
|
||
подписка на поток новых сделок.
|
||
|
||
Получаемые события:
|
||
|
||
```
|
||
destination = internal.trade
|
||
```
|
||
|
||
---
|
||
|
||
# Выполненные задачи
|
||
|
||
В рамках Build были последовательно проверены:
|
||
|
||
- REST endpoint;
|
||
- WebSocket endpoint;
|
||
- формат ответа;
|
||
- соответствие Swagger документации;
|
||
- работа Demo;
|
||
- работа Production;
|
||
- соответствие REST и WebSocket;
|
||
- стабильность подписки;
|
||
- возможность дальнейшего использования в Dzentra.
|
||
|
||
---
|
||
|
||
# Проверка REST API
|
||
|
||
Для исследования использовались реальные запросы.
|
||
|
||
Основная команда:
|
||
|
||
```bash
|
||
curl -sS -G \
|
||
"https://api-adapter.dzengi.com/api/v2/aggTrades" \
|
||
--data-urlencode "symbol=BTC/USD_LEVERAGE" \
|
||
--data-urlencode "limit=10" \
|
||
| python -m json.tool
|
||
```
|
||
|
||
---
|
||
|
||
# Полученный формат REST
|
||
|
||
Каждая запись имеет вид:
|
||
|
||
```json
|
||
{
|
||
"a": 2134857062,
|
||
"p": "64497.25",
|
||
"q": "0.005",
|
||
"T": 1784218066823,
|
||
"m": false
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
# Расшифровка полей
|
||
|
||
| Поле | Значение |
|
||
|------|----------|
|
||
| a | идентификатор сделки |
|
||
| p | цена исполнения |
|
||
| q | объём сделки |
|
||
| T | timestamp сделки |
|
||
| m | сторона инициатора сделки |
|
||
|
||
---
|
||
|
||
# Особенности REST
|
||
|
||
Во время исследования было установлено:
|
||
|
||
- данные отсортированы по времени;
|
||
- записи идут от новых к старым;
|
||
- timestamp имеет миллисекундную точность;
|
||
- объём может возвращаться в научной записи (`1.0E-4`);
|
||
- API поддерживает выборку по limit;
|
||
- идентификатор сделки монотонно возрастает.
|
||
|
||
---
|
||
|
||
# Проверка Demo окружения
|
||
|
||
Первоначально исследования проводились через Demo API.
|
||
|
||
Использовался endpoint:
|
||
|
||
```text
|
||
https://demo-api-adapter.dzengi.com/api/v2/aggTrades
|
||
```
|
||
|
||
Во время длительного наблюдения было обнаружено:
|
||
|
||
- результаты практически не меняются;
|
||
- новые сделки появляются крайне редко;
|
||
- иногда ответы полностью совпадают на протяжении нескольких минут.
|
||
|
||
Из этого был сделан вывод, что Demo нельзя использовать для проверки непрерывного потока сделок.
|
||
|
||
---
|
||
|
||
# Проверка Production
|
||
|
||
После перехода на Production API ситуация изменилась.
|
||
|
||
Использовался endpoint:
|
||
|
||
```text
|
||
https://api-adapter.dzengi.com/api/v2/aggTrades
|
||
```
|
||
|
||
Повторные запросы начали возвращать постоянно обновляющийся поток последних сделок.
|
||
|
||
Это подтвердило:
|
||
|
||
- REST endpoint является рабочим;
|
||
- данные обновляются в реальном времени;
|
||
- Production подходит для проверки Time & Sales.
|
||
|
||
---
|
||
|
||
# Проверка поддержки символов
|
||
|
||
Во время тестирования было установлено:
|
||
|
||
```
|
||
BTC/USD
|
||
```
|
||
|
||
не поддерживается.
|
||
|
||
REST возвращает ошибку:
|
||
|
||
```json
|
||
{
|
||
"code": -1128,
|
||
"msg": "Invalid symbol: BTC/USD"
|
||
}
|
||
```
|
||
|
||
При этом корректным является символ:
|
||
|
||
```
|
||
BTC/USD_LEVERAGE
|
||
```
|
||
|
||
Именно его необходимо использовать в дальнейшем при работе с Trade Feed.
|
||
|
||
---
|
||
|
||
# Предварительные выводы по REST
|
||
|
||
На данном этапе исследования было подтверждено:
|
||
|
||
✔ endpoint полностью работоспособен;
|
||
|
||
✔ формат данных соответствует Swagger;
|
||
|
||
✔ поля достаточны для построения Time & Sales;
|
||
|
||
✔ данные поступают в режиме реального времени;
|
||
|
||
✔ Demo окружение не подходит для полноценного тестирования активности рынка;
|
||
|
||
✔ дальнейшие исследования следует проводить исключительно через Production API.
|
||
|
||
---
|
||
|
||
# Исследование WebSocket
|
||
|
||
После завершения анализа REST был исследован поток WebSocket.
|
||
|
||
Использовался раздел Swagger:
|
||
|
||
```
|
||
trades.subscribe
|
||
```
|
||
|
||
Документация описывает механизм подписки на поток сделок.
|
||
|
||
---
|
||
|
||
# Формат подписки
|
||
|
||
Клиент отправляет сообщение:
|
||
|
||
```json
|
||
{
|
||
"correlationId": "<uuid>",
|
||
"destination": "trades.subscribe",
|
||
"payload": {
|
||
"symbols": [
|
||
"BTC/USD_LEVERAGE"
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
После успешной обработки сервер отвечает подтверждением.
|
||
|
||
---
|
||
|
||
# ACK-сообщение
|
||
|
||
Первое сообщение всегда имеет вид:
|
||
|
||
```json
|
||
{
|
||
"correlationId": "...",
|
||
"destination": "trades.subscribe",
|
||
"payload": {
|
||
"subscriptions": {
|
||
"BTC/USD_LEVERAGE": "PROCESSED"
|
||
}
|
||
},
|
||
"status": "OK"
|
||
}
|
||
```
|
||
|
||
Это сообщение не содержит рыночных данных.
|
||
|
||
Оно означает исключительно успешную регистрацию подписки.
|
||
|
||
---
|
||
|
||
# Проверка нескольких символов
|
||
|
||
Для проверки обработки ошибок была отправлена подписка одновременно на два символа:
|
||
|
||
```json
|
||
{
|
||
"symbols": [
|
||
"BTC/USD",
|
||
"BTC/USD_LEVERAGE"
|
||
]
|
||
}
|
||
```
|
||
|
||
Ответ сервера:
|
||
|
||
```json
|
||
{
|
||
"subscriptions": {
|
||
"BTC/USD": "ERROR: BTC/USD not found",
|
||
"BTC/USD_LEVERAGE": "PROCESSED"
|
||
}
|
||
}
|
||
```
|
||
|
||
Из этого был сделан важный вывод.
|
||
|
||
Подписка обрабатывается отдельно для каждого инструмента.
|
||
|
||
Ошибка одного символа не приводит к отмене остальных подписок.
|
||
|
||
---
|
||
|
||
# Первоначальное тестирование Demo
|
||
|
||
Первые проверки выполнялись на Demo окружении.
|
||
|
||
Подписка проходила успешно.
|
||
|
||
Получалось корректное ACK.
|
||
|
||
Однако далее:
|
||
|
||
- сообщения сделок не приходили;
|
||
- соединение оставалось открытым;
|
||
- Ping/Pong работал корректно;
|
||
- сервер не разрывал соединение.
|
||
|
||
Несмотря на пятиминутное ожидание поток оставался пустым.
|
||
|
||
---
|
||
|
||
# Вывод по Demo
|
||
|
||
Полученные результаты полностью совпали с поведением REST.
|
||
|
||
Demo практически не генерирует торговую активность.
|
||
|
||
Поэтому отсутствие сообщений не является ошибкой клиента.
|
||
|
||
---
|
||
|
||
# Переход на Production
|
||
|
||
Для окончательной проверки было принято решение перейти на Production API.
|
||
|
||
Использовались настройки:
|
||
|
||
```text
|
||
EXCHANGE_BASE_URL=https://api-adapter.dzengi.com
|
||
EXCHANGE_WS_URL=wss://api-adapter.dzengi.com
|
||
```
|
||
|
||
После этого поток начал немедленно передавать сделки.
|
||
|
||
---
|
||
|
||
# Первый Trade Event
|
||
|
||
Первое сообщение выглядело следующим образом.
|
||
|
||
```json
|
||
{
|
||
"destination": "internal.trade",
|
||
"payload": {
|
||
"buyer": false,
|
||
"id": 2134846831,
|
||
"orderId": "00a02503-0079-54c4-0000-000081e62b58",
|
||
"price": 64555.55,
|
||
"size": 0.002,
|
||
"symbol": "BTC/USD_LEVERAGE",
|
||
"ts": 1784218012030
|
||
},
|
||
"status": "OK"
|
||
}
|
||
```
|
||
|
||
Именно это сообщение является каноническим Trade Event.
|
||
|
||
---
|
||
|
||
# Структура Trade Event
|
||
|
||
Сервер публикует сообщения типа
|
||
|
||
```
|
||
destination = internal.trade
|
||
```
|
||
|
||
Поля сообщения:
|
||
|
||
| Поле | Назначение |
|
||
|------|------------|
|
||
| id | уникальный идентификатор сделки |
|
||
| price | цена исполнения |
|
||
| size | объём |
|
||
| ts | время исполнения |
|
||
| buyer | направление сделки |
|
||
| symbol | торговый инструмент |
|
||
| orderId | внутренний идентификатор биржи |
|
||
|
||
---
|
||
|
||
# Семантика buyer
|
||
|
||
Экспериментально подтверждено:
|
||
|
||
```
|
||
buyer = true
|
||
```
|
||
|
||
означает
|
||
|
||
> инициатор сделки — покупатель.
|
||
|
||
Соответственно
|
||
|
||
```
|
||
buyer = false
|
||
```
|
||
|
||
означает
|
||
|
||
> инициатор сделки — продавец.
|
||
|
||
Данное поле полностью соответствует REST-полю:
|
||
|
||
```
|
||
m
|
||
```
|
||
|
||
по следующему правилу:
|
||
|
||
```
|
||
buyer == !m
|
||
```
|
||
|
||
То есть:
|
||
|
||
| REST m | WebSocket buyer |
|
||
|---------|-----------------|
|
||
| true | false |
|
||
| false | true |
|
||
|
||
Это полностью соответствует классической Binance-семантике:
|
||
|
||
```
|
||
m = isBuyerMaker
|
||
```
|
||
|
||
---
|
||
|
||
# Частота сообщений
|
||
|
||
Во время наблюдения было получено множество последовательных сообщений.
|
||
|
||
Интервал между ними не фиксирован.
|
||
|
||
Были зарегистрированы:
|
||
|
||
- менее секунды;
|
||
- несколько секунд;
|
||
- десятки секунд.
|
||
|
||
Таким образом поток является событийным.
|
||
|
||
Сообщения появляются только после фактического исполнения новой сделки.
|
||
|
||
---
|
||
|
||
# Стабильность соединения
|
||
|
||
Во время длительного тестирования:
|
||
|
||
- соединение не разрывалось;
|
||
- Ping/Pong работал корректно;
|
||
- подписка сохранялась;
|
||
- повторной регистрации не требовалось.
|
||
|
||
Это подтверждает возможность использования данного WebSocket для постоянной фоновой работы Dzentra.
|
||
|
||
---
|
||
|
||
# Диагностический скрипт
|
||
|
||
Для исследования был разработан отдельный диагностический инструмент:
|
||
|
||
```
|
||
scripts/check_trades_websocket.py
|
||
```
|
||
|
||
Назначение:
|
||
|
||
- открытие WebSocket;
|
||
- регистрация подписки;
|
||
- вывод ACK;
|
||
- вывод всех Trade Event;
|
||
- отображение времени получения сообщений;
|
||
- автоматический Ping;
|
||
- контроль таймаутов;
|
||
- длительное наблюдение за потоком.
|
||
|
||
Скрипт не является частью рабочей архитектуры.
|
||
|
||
Он предназначен исключительно для инженерной диагностики и проверки API.
|
||
|
||
---
|
||
|
||
# Запуск скрипта
|
||
|
||
Для Demo:
|
||
|
||
```bash
|
||
PYTHONPATH=. python scripts/check_trades_websocket.py
|
||
```
|
||
|
||
Для Production:
|
||
|
||
```bash
|
||
EXCHANGE_BASE_URL=https://api-adapter.dzengi.com \
|
||
EXCHANGE_WS_URL=wss://api-adapter.dzengi.com \
|
||
EXCHANGE_API_KEY="" \
|
||
PYTHONPATH=. \
|
||
python scripts/check_trades_websocket.py
|
||
```
|
||
|
||
---
|
||
|
||
# Проверенные сценарии
|
||
|
||
Во время исследования были успешно проверены:
|
||
|
||
- успешная регистрация подписки;
|
||
- получение ACK;
|
||
- получение Trade Event;
|
||
- получение нескольких подряд Trade Event;
|
||
- работа Ping/Pong;
|
||
- длительное соединение;
|
||
- отсутствие ложных сообщений;
|
||
- корректная обработка нескольких символов;
|
||
- обработка ошибки неизвестного символа.
|
||
|
||
---
|
||
|
||
# Сопоставление REST и WebSocket
|
||
|
||
Главной задачей исследования было доказать, что REST и WebSocket описывают **одни и те же биржевые сделки**, а не различные представления рынка.
|
||
|
||
Для этого была выполнена серия сравнительных экспериментов.
|
||
|
||
---
|
||
|
||
# Методика проверки
|
||
|
||
Алгоритм проверки был следующим.
|
||
|
||
1. Запустить подписку `trades.subscribe`.
|
||
2. Дождаться получения новой сделки через WebSocket.
|
||
3. Зафиксировать:
|
||
- id;
|
||
- цену;
|
||
- объём;
|
||
- timestamp;
|
||
- направление сделки.
|
||
4. Немедленно запросить последние сделки через REST.
|
||
5. Найти сделку по идентификатору.
|
||
|
||
---
|
||
|
||
# Проверка №1
|
||
|
||
Через WebSocket была получена сделка:
|
||
|
||
```json
|
||
{
|
||
"buyer": false,
|
||
"id": 2134846831,
|
||
"price": 64555.55,
|
||
"size": 0.002,
|
||
"symbol": "BTC/USD_LEVERAGE",
|
||
"ts": 1784218012030
|
||
}
|
||
```
|
||
|
||
После этого был выполнен REST-запрос:
|
||
|
||
```bash
|
||
curl -G \
|
||
https://api-adapter.dzengi.com/api/v2/aggTrades \
|
||
--data-urlencode "symbol=BTC/USD_LEVERAGE" \
|
||
--data-urlencode "limit=100"
|
||
```
|
||
|
||
Далее был выполнен поиск по ID сделки.
|
||
|
||
Полученный результат:
|
||
|
||
```json
|
||
{
|
||
"a": 2134846831,
|
||
"p": "64555.55",
|
||
"q": "0.002",
|
||
"T": 1784218012030,
|
||
"m": true
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
# Совпадение полей
|
||
|
||
Было подтверждено полное совпадение.
|
||
|
||
| REST | WebSocket |
|
||
|-------|-----------|
|
||
| a | id |
|
||
| p | price |
|
||
| q | size |
|
||
| T | ts |
|
||
| m | !buyer |
|
||
|
||
Все значения совпали полностью.
|
||
|
||
---
|
||
|
||
# Проверка нескольких сообщений
|
||
|
||
Аналогичная проверка была выполнена ещё для нескольких последовательных событий.
|
||
|
||
Каждый раз наблюдалось одинаковое соответствие:
|
||
|
||
- идентификатор сделки совпадает;
|
||
- цена совпадает;
|
||
- объём совпадает;
|
||
- timestamp совпадает;
|
||
- направление определяется инверсией поля `buyer`.
|
||
|
||
Таким образом экспериментально доказано, что REST и WebSocket используют единую торговую базу данных.
|
||
|
||
---
|
||
|
||
# Итоговая схема соответствия
|
||
|
||
```text
|
||
Exchange Matching Engine
|
||
│
|
||
┌─────────────┴─────────────┐
|
||
│ │
|
||
REST aggTrades WebSocket trades.subscribe
|
||
│ │
|
||
▼ ▼
|
||
Aggregated Trade internal.trade
|
||
│ │
|
||
└─────────────┬─────────────┘
|
||
▼
|
||
Canonical Trade Model
|
||
```
|
||
|
||
Это означает, что в архитектуре Dzentra оба источника должны преобразовываться **в одну каноническую модель**, а не существовать как независимые типы данных.
|
||
|
||
---
|
||
|
||
# Архитектурные выводы
|
||
|
||
По результатам исследования были сформированы следующие инженерные выводы.
|
||
|
||
## 1. REST и WebSocket описывают одну сущность
|
||
|
||
Различается только транспорт доставки.
|
||
|
||
REST используется для получения истории.
|
||
|
||
WebSocket используется для получения новых событий.
|
||
|
||
Модель данных должна быть общей.
|
||
|
||
---
|
||
|
||
## 2. Канонической сущностью становится Trade
|
||
|
||
Не существует причин создавать отдельные модели:
|
||
|
||
- RestTrade;
|
||
- WsTrade;
|
||
- InternalTrade.
|
||
|
||
Должна существовать одна модель:
|
||
|
||
```text
|
||
Trade
|
||
```
|
||
|
||
которая используется всеми компонентами системы.
|
||
|
||
---
|
||
|
||
## 3. Trade Feed должен быть независимым модулем
|
||
|
||
Как и Candle Feed, новый модуль должен располагаться в подсистеме Market Data Acquisition.
|
||
|
||
Предварительная структура:
|
||
|
||
```text
|
||
market_data/acquisition/
|
||
|
||
models/
|
||
trade.py
|
||
|
||
feeds/
|
||
trades_feed.py
|
||
|
||
handlers/
|
||
trades_handler.py
|
||
|
||
adapters/dzengi/
|
||
rest.py
|
||
websocket.py
|
||
|
||
validation/
|
||
schema.py
|
||
values.py
|
||
```
|
||
|
||
---
|
||
|
||
## 4. REST и WebSocket должны использовать общий Handler
|
||
|
||
Различаться должны только источники получения документов.
|
||
|
||
Схема обработки должна повторять архитектуру Candle Feed:
|
||
|
||
```text
|
||
REST Document
|
||
│
|
||
▼
|
||
Parser
|
||
│
|
||
▼
|
||
Validation
|
||
│
|
||
▼
|
||
Mapper
|
||
│
|
||
▼
|
||
Trade
|
||
```
|
||
|
||
и
|
||
|
||
```text
|
||
WebSocket Document
|
||
│
|
||
▼
|
||
Parser
|
||
│
|
||
▼
|
||
Validation
|
||
│
|
||
▼
|
||
Mapper
|
||
│
|
||
▼
|
||
Trade
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Внутри Dzentra не должно существовать транспортных моделей
|
||
|
||
После обработки все компоненты должны работать исключительно с:
|
||
|
||
```text
|
||
Trade
|
||
```
|
||
|
||
Они не должны знать:
|
||
|
||
- откуда пришли данные;
|
||
- были ли они получены через REST;
|
||
- были ли они получены через WebSocket.
|
||
|
||
---
|
||
|
||
# Возможности будущего Trade Feed
|
||
|
||
После реализации модуль сможет использоваться для решения задач, которые невозможно решить только по свечам.
|
||
|
||
В частности:
|
||
|
||
- построение Time & Sales;
|
||
- определение текущего торгового потока;
|
||
- оценка направления агрессора (Buyer / Seller);
|
||
- обнаружение крупных рыночных сделок;
|
||
- поиск всплесков активности;
|
||
- вычисление Buy/Sell Imbalance;
|
||
- вычисление Trade Delta;
|
||
- обнаружение поглощений;
|
||
- обнаружение кульминаций объёма;
|
||
- анализ последовательности исполнения сделок;
|
||
- подтверждение истинности пробоев;
|
||
- подтверждение ложных пробоев;
|
||
- анализ микроструктуры рынка.
|
||
|
||
Все эти алгоритмы будут использовать одну и ту же каноническую модель `Trade`.
|
||
|
||
---
|
||
|
||
# Итоги Build 057
|
||
|
||
В рамках Build были полностью исследованы REST и WebSocket интерфейсы Trade Feed.
|
||
|
||
Подтверждено:
|
||
|
||
- ✔ REST `GET /api/v2/aggTrades` полностью работоспособен.
|
||
- ✔ WebSocket `trades.subscribe` полностью работоспособен.
|
||
- ✔ Demo окружение практически не генерирует поток сделок и не подходит для тестирования.
|
||
- ✔ Production окружение генерирует полноценный поток Trade Event.
|
||
- ✔ REST и WebSocket описывают одну и ту же сделку.
|
||
- ✔ Идентификаторы, цены, объёмы и временные метки полностью совпадают.
|
||
- ✔ Поле `buyer` является логической инверсией REST-поля `m`.
|
||
- ✔ Разработан и протестирован диагностический скрипт `scripts/check_trades_websocket.py`.
|
||
- ✔ Подготовлена архитектурная база для реализации канонического Trade Feed.
|
||
|
||
---
|
||
|
||
# Следующий этап
|
||
|
||
Следующим Build станет **Build 058 — Canonical Trade Model Foundation**.
|
||
|
||
В его рамках будет разработан первый полноценный компонент нового Trade Feed:
|
||
|
||
- каноническая модель `Trade`;
|
||
- REST Parser;
|
||
- REST Validation;
|
||
- REST Mapper;
|
||
- базовые unit-тесты;
|
||
- интеграция в существующую архитектуру `Market Data Acquisition`.
|
||
|
||
После этого система Dzentra получит вторую полноценную каноническую рыночную сущность после завершённой миграции OHLCV — поток реальных биржевых сделок (Time & Sales).
|
||
|
||
# Приложение A — Использование диагностического скрипта Trade WebSocket
|
||
|
||
---
|
||
|
||
# Назначение скрипта
|
||
|
||
В рамках Build 057 был разработан отдельный диагностический инструмент
|
||
|
||
```
|
||
scripts/check_trades_websocket.py
|
||
```
|
||
|
||
Скрипт предназначен исключительно для инженерной проверки работы биржевого
|
||
Trade WebSocket API.
|
||
|
||
Он не является частью рабочего Runtime Dzentra и не используется торговой
|
||
логикой.
|
||
|
||
Его задачи:
|
||
|
||
- проверка открытия WebSocket-соединения;
|
||
- проверка успешной регистрации подписки;
|
||
- проверка получения ACK;
|
||
- проверка получения новых сделок;
|
||
- проверка корректности Ping/Pong;
|
||
- длительное наблюдение за потоком;
|
||
- диагностика работы Demo и Production окружений;
|
||
- подтверждение соответствия WebSocket и REST.
|
||
|
||
---
|
||
|
||
# Проверяемые возможности
|
||
|
||
Во время работы скрипт автоматически проверяет:
|
||
|
||
- возможность подключения к серверу;
|
||
- правильность формирования запроса подписки;
|
||
- успешность регистрации подписки;
|
||
- получение сообщений подтверждения;
|
||
- получение сообщений Trade Event;
|
||
- сохранение соединения при отсутствии новых сделок;
|
||
- работу Ping/Pong;
|
||
- получение нескольких последовательных сделок;
|
||
- возможность длительной непрерывной работы.
|
||
|
||
---
|
||
|
||
# Используемые переменные окружения
|
||
|
||
Скрипт использует стандартные настройки проекта.
|
||
|
||
Основные переменные:
|
||
|
||
```
|
||
EXCHANGE_BASE_URL
|
||
```
|
||
|
||
```
|
||
EXCHANGE_WS_URL
|
||
```
|
||
|
||
```
|
||
EXCHANGE_API_KEY
|
||
```
|
||
|
||
Если переменные не заданы, используются значения из конфигурации Dzentra.
|
||
|
||
---
|
||
|
||
# Запуск Demo
|
||
|
||
```bash
|
||
PYTHONPATH=. python scripts/check_trades_websocket.py
|
||
```
|
||
|
||
Используется:
|
||
|
||
```
|
||
wss://demo-api-adapter.dzengi.com/connect
|
||
```
|
||
|
||
---
|
||
|
||
# Ожидаемый результат Demo
|
||
|
||
При корректной работе вывод должен быть примерно следующим.
|
||
|
||
```
|
||
Subscription request sent.
|
||
|
||
Message #1
|
||
|
||
ACK
|
||
```
|
||
|
||
После этого возможно длительное отсутствие сообщений Trade Event.
|
||
|
||
Периодически выводится сообщение:
|
||
|
||
```
|
||
No trade event yet; connection is alive.
|
||
```
|
||
|
||
Это означает:
|
||
|
||
- соединение активно;
|
||
- Ping/Pong работает;
|
||
- новых сделок пока нет.
|
||
|
||
Подобное поведение является нормальным для Demo окружения.
|
||
|
||
---
|
||
|
||
# Запуск Production
|
||
|
||
Для проверки реального рынка используется:
|
||
|
||
```bash
|
||
EXCHANGE_BASE_URL=https://api-adapter.dzengi.com \
|
||
EXCHANGE_WS_URL=wss://api-adapter.dzengi.com \
|
||
EXCHANGE_API_KEY="" \
|
||
PYTHONPATH=. \
|
||
python scripts/check_trades_websocket.py
|
||
```
|
||
|
||
---
|
||
|
||
# Ожидаемый результат Production
|
||
|
||
После ACK начинают поступать реальные сделки.
|
||
|
||
Типичный вывод:
|
||
|
||
```
|
||
Message #2
|
||
|
||
TRADE EVENT
|
||
```
|
||
|
||
```json
|
||
{
|
||
"destination": "internal.trade",
|
||
"payload": {
|
||
"id": 2134846831,
|
||
"price": 64555.55,
|
||
"size": 0.002,
|
||
"buyer": false,
|
||
"symbol": "BTC/USD_LEVERAGE",
|
||
"ts": 1784218012030
|
||
}
|
||
}
|
||
```
|
||
|
||
Затем по мере появления новых сделок будут выводиться:
|
||
|
||
```
|
||
Message #3
|
||
|
||
TRADE EVENT
|
||
```
|
||
|
||
```
|
||
Message #4
|
||
|
||
TRADE EVENT
|
||
```
|
||
|
||
и так далее.
|
||
|
||
---
|
||
|
||
# Интерпретация сообщений
|
||
|
||
Во время работы возможны два типа сообщений.
|
||
|
||
## ACK
|
||
|
||
```text
|
||
destination = trades.subscribe
|
||
```
|
||
|
||
означает успешную регистрацию подписки.
|
||
|
||
---
|
||
|
||
## TRADE EVENT
|
||
|
||
```text
|
||
destination = internal.trade
|
||
```
|
||
|
||
означает получение новой сделки с биржи.
|
||
|
||
---
|
||
|
||
# Проверка соответствия REST
|
||
|
||
После получения Trade Event рекомендуется выполнить запрос:
|
||
|
||
```bash
|
||
curl -G \
|
||
"https://api-adapter.dzengi.com/api/v2/aggTrades" \
|
||
--data-urlencode "symbol=BTC/USD_LEVERAGE" \
|
||
--data-urlencode "limit=100"
|
||
```
|
||
|
||
Затем убедиться, что сделка с полученным ID присутствует в REST.
|
||
|
||
Пример поиска:
|
||
|
||
```bash
|
||
curl -sS -G \
|
||
"https://api-adapter.dzengi.com/api/v2/aggTrades" \
|
||
--data-urlencode "symbol=BTC/USD_LEVERAGE" \
|
||
--data-urlencode "limit=100" \
|
||
| python -c '
|
||
|
||
import json
|
||
import sys
|
||
|
||
target_id = 2134846831
|
||
|
||
items = json.load(sys.stdin)
|
||
|
||
matches = [
|
||
item
|
||
for item in items
|
||
if item["a"] == target_id
|
||
]
|
||
|
||
print(json.dumps(matches, indent=2))
|
||
'
|
||
```
|
||
|
||
Если вывод содержит одну запись с тем же идентификатором, значит соответствие REST и WebSocket подтверждено.
|
||
|
||
---
|
||
|
||
# Диагностические признаки корректной работы
|
||
|
||
Работа скрипта считается полностью успешной, если выполняются все условия:
|
||
|
||
- успешно устанавливается WebSocket-соединение;
|
||
- получено ACK;
|
||
- подписка имеет статус `PROCESSED`;
|
||
- поступают сообщения `internal.trade`;
|
||
- соединение не разрывается при длительном ожидании;
|
||
- Ping/Pong выполняется успешно;
|
||
- сделки из WebSocket присутствуют в REST `aggTrades`.
|
||
|
||
---
|
||
|
||
# Итог
|
||
|
||
Диагностический скрипт полностью подтвердил работоспособность биржевого интерфейса Trade Feed и стал основным инженерным инструментом проверки перед началом реализации канонического модуля **Trade (Time & Sales)** в Build 058. |