# Stage 07.3.5 — WebSocket Probe + REST Fallback

## Статус этапа

Этап не переводит рынок на WebSocket в production-режим.

В рамках этапа была выполнена проверка WebSocket API Dzengi и подготовлена архитектурная заготовка:

- WebSocket client;
- market cache;
- market stream task;
- fallback через REST.

Но реальный WebSocket endpoint не удалось подтвердить на runtime-уровне.

---

## Что проверялось

В Swagger есть группа `websocket-api`, где endpoints отображаются в формате:

```text
wss:/api/v2/depth
wss:/api/v2/account
wss:/api/v2/aggTrades
wss:/api/v2/exchangeInfo
...
```

Для рынка был выбран endpoint:

```text
wss:/api/v2/depth
```

Он описан как `orderBook`.

Параметры запроса:

```json
{
  "limit": 0,
  "symbol": "string"
}
```

Для нашего случая:

```json
{
  "limit": 5,
  "symbol": "BTC/USD_LEVERAGE"
}
```

---

## Что означают параметры

### symbol

Инструмент, по которому нужно получить данные стакана.

Пример:

```text
BTC/USD_LEVERAGE
```

### limit

Количество уровней стакана.

Например:

```json
"limit": 5
```

означает получить 5 лучших уровней ask и 5 лучших уровней bid.

---

## Проверенные варианты подключения

Были проверены варианты:

```text
/api/v2/depth
/api/v1/depth
/ws/api/v2/depth
/ws/api/v1/depth
/ws
/websocket
/stream
/api/v2/ws
/api/v1/ws
```

Также проверялись варианты:

```text
без query parameters
?symbol=BTC/USD_LEVERAGE&limit=5
?symbolName=BTC/USD_LEVERAGE&limit=5
```

И варианты headers:

```text
без headers
X-MBX-APIKEY
Origin
Content-Type: application/json
subprotocol: json
```

---

## Фактический результат

Ни один вариант не вернул:

```text
101 Switching Protocols
```

А именно `101 Switching Protocols` является признаком успешного WebSocket Upgrade.

Фактические ответы:

```text
HTTP 404
HTTP 400
HTTP 200
```

---

## Интерпретация ошибок

### HTTP 404

Endpoint не найден как WebSocket route.

### HTTP 400

Сервер получил WebSocket handshake, но отклонил запрос как некорректный.

### HTTP 200

Endpoint существует как обычный HTTP endpoint, но не выполняет WebSocket Upgrade.

Это значит, что сервер отвечает как REST API, а не как WebSocket.

---

## Вывод

На текущих URL и по текущей Swagger-документации WebSocket endpoint Dzengi не подтверждён.

Swagger показывает `wss:/api/v2/*`, но runtime-проверка не нашла endpoint, который реально открывает WebSocket-соединение.

Поэтому рынок временно остаётся на REST polling через существующий `LiveScreenRunner`.

---

## Что оставить в коде

Можно оставить заготовки:

```text
app/src/integrations/exchange/ws_client.py
app/src/integrations/exchange/market_cache.py
app/src/integrations/exchange/market_stream.py
app/tools/ws_probe.py
```

Они пригодятся, если Dzengi подтвердит настоящий WebSocket endpoint.

Также можно оставить зависимость:

```text
websockets==13.1
```

---

## Что отключить сейчас

Нужно отключить автозапуск WebSocket stream в `app/src/main.py`.

### Было

```python
import asyncio
from contextlib import suppress

from src.bootstrap.app_factory import create_app
from src.integrations.exchange.market_stream import start_market_stream


async def main() -> None:
    bot, dispatcher = create_app()

    market_stream_task = asyncio.create_task(start_market_stream())

    try:
        await dispatcher.start_polling(bot)
    finally:
        market_stream_task.cancel()

        with suppress(asyncio.CancelledError):
            await market_stream_task


if __name__ == "__main__":
    asyncio.run(main())
```

### Должно стать временно

```python
import asyncio

from src.bootstrap.app_factory import create_app


async def main() -> None:
    # создаём bot + dispatcher
    bot, dispatcher = create_app()

    # WebSocket stream временно отключён.
    # Причина: Dzengi Swagger содержит wss:/api/v2/* endpoints,
    # но runtime probe не нашёл endpoint с WebSocket Upgrade 101.
    #
    # Когда Dzengi подтвердит рабочий WS endpoint,
    # можно будет вернуть запуск:
    #
    # from src.integrations.exchange.market_stream import start_market_stream
    # market_stream_task = asyncio.create_task(start_market_stream())

    # запускаем Telegram polling
    await dispatcher.start_polling(bot)


if __name__ == "__main__":
    asyncio.run(main())
```

---

## Что НЕ нужно отключать

Не нужно откатывать:

- live-экран рынка;
- live-экран портфеля;
- `LiveScreenRunner`;
- REST polling;
- `ExchangeService.get_price()`;
- `ExchangeService.get_market_snapshot()`.

REST fallback должен остаться рабочим.

---

## Текущее поведение после отключения stream

После отключения WebSocket task:

- бот больше не спамит `market_ws_reconnect`;
- экран 📈 Рынок продолжает обновляться через REST polling;
- экран 💼 Портфель продолжает работать;
- архитектурная заготовка WebSocket остаётся в проекте.

---

## Что нужно запросить у Dzengi / брокера

Для продолжения WebSocket-интеграции нужен один из вариантов:

1. настоящий WebSocket base URL;
2. пример рабочего подключения;
3. required headers;
4. required subprotocol;
5. пример handshake;
6. пример Python/JavaScript клиента;
7. подтверждение, что `wss:/api/v2/depth` действительно поддерживает WebSocket Upgrade.

Ключевой вопрос:

```text
Какой полный URL должен вернуть 101 Switching Protocols для market depth stream?
```

---

## Commit

Рекомендуемый commit message:

```bash
git add .
git commit -m "Stage 07.3.5 - websocket probe with REST fallback"
git push
```

---

## Следующий этап

После фиксации 07.3.5 можно перейти к:

```text
Stage 07.4 — Strategy Plugins
```

Потому что UI, мониторинг и REST fallback уже стабильны.
