unicex 0.1.18__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. unicex-0.2.0/PKG-INFO +122 -0
  2. unicex-0.2.0/README.md +76 -0
  3. {unicex-0.1.18 → unicex-0.2.0}/pyproject.toml +1 -3
  4. {unicex-0.1.18 → unicex-0.2.0}/unicex/__init__.py +18 -8
  5. {unicex-0.1.18 → unicex-0.2.0}/unicex/_abc/__init__.py +2 -1
  6. {unicex-0.1.18/unicex/_abc/asyncio → unicex-0.2.0/unicex/_abc}/uni_client.py +2 -2
  7. {unicex-0.1.18/unicex/_abc/asyncio → unicex-0.2.0/unicex/_abc}/uni_websocket_manager.py +1 -1
  8. {unicex-0.1.18/unicex/binance/asyncio → unicex-0.2.0/unicex/binance}/__init__.py +1 -1
  9. {unicex-0.1.18/unicex/binance/asyncio → unicex-0.2.0/unicex/binance}/client.py +72 -4
  10. {unicex-0.1.18/unicex/binance/asyncio → unicex-0.2.0/unicex/binance}/uni_client.py +2 -2
  11. {unicex-0.1.18/unicex/binance/asyncio → unicex-0.2.0/unicex/binance}/uni_websocket_manager.py +3 -3
  12. {unicex-0.1.18/unicex/binance/asyncio → unicex-0.2.0/unicex/binance}/user_websocket.py +21 -4
  13. {unicex-0.1.18/unicex/binance/asyncio → unicex-0.2.0/unicex/binance}/websocket_manager.py +39 -4
  14. {unicex-0.1.18/unicex/bitget/asyncio → unicex-0.2.0/unicex/bitget}/__init__.py +4 -1
  15. {unicex-0.1.18/unicex/bitget/asyncio → unicex-0.2.0/unicex/bitget}/client.py +118 -4
  16. {unicex-0.1.18/unicex/bitget/asyncio → unicex-0.2.0/unicex/bitget}/uni_client.py +2 -2
  17. {unicex-0.1.18/unicex/bitget/asyncio → unicex-0.2.0/unicex/bitget}/uni_websocket_manager.py +3 -3
  18. {unicex-0.1.18/unicex/bitget/asyncio → unicex-0.2.0/unicex/bitget}/websocket_manager.py +42 -4
  19. unicex-0.2.0/unicex/mapper.py +57 -0
  20. unicex-0.2.0/unicex.egg-info/PKG-INFO +122 -0
  21. unicex-0.2.0/unicex.egg-info/SOURCES.txt +35 -0
  22. {unicex-0.1.18 → unicex-0.2.0}/unicex.egg-info/requires.txt +0 -2
  23. unicex-0.1.18/PKG-INFO +0 -114
  24. unicex-0.1.18/README.md +0 -66
  25. unicex-0.1.18/unicex/_abc/asyncio/__init__.py +0 -4
  26. unicex-0.1.18/unicex/_abc/sync/__init__.py +0 -4
  27. unicex-0.1.18/unicex/_abc/sync/uni_client.py +0 -275
  28. unicex-0.1.18/unicex/_abc/sync/uni_websocket_manager.py +0 -294
  29. unicex-0.1.18/unicex/_base/__init__.py +0 -6
  30. unicex-0.1.18/unicex/_base/sync/__init__.py +0 -7
  31. unicex-0.1.18/unicex/_base/sync/client.py +0 -186
  32. unicex-0.1.18/unicex/_base/sync/websocket.py +0 -239
  33. unicex-0.1.18/unicex/binance/__init__.py +0 -13
  34. unicex-0.1.18/unicex/binance/_mixins/__init__.py +0 -7
  35. unicex-0.1.18/unicex/binance/_mixins/client.py +0 -78
  36. unicex-0.1.18/unicex/binance/_mixins/user_websocket.py +0 -27
  37. unicex-0.1.18/unicex/binance/_mixins/websocket_manager.py +0 -45
  38. unicex-0.1.18/unicex/binance/sync/__init__.py +0 -9
  39. unicex-0.1.18/unicex/binance/sync/client.py +0 -1536
  40. unicex-0.1.18/unicex/binance/sync/uni_client.py +0 -176
  41. unicex-0.1.18/unicex/binance/sync/uni_websocket_manager.py +0 -166
  42. unicex-0.1.18/unicex/binance/sync/user_websocket.py +0 -165
  43. unicex-0.1.18/unicex/binance/sync/websocket_manager.py +0 -876
  44. unicex-0.1.18/unicex/bitget/__init__.py +0 -1
  45. unicex-0.1.18/unicex/bitget/_mixins/__init__.py +0 -7
  46. unicex-0.1.18/unicex/bitget/_mixins/client.py +0 -125
  47. unicex-0.1.18/unicex/bitget/_mixins/user_websocket.py +0 -0
  48. unicex-0.1.18/unicex/bitget/_mixins/websocket_manager.py +0 -47
  49. unicex-0.1.18/unicex/bitget/sync/__init__.py +0 -0
  50. unicex-0.1.18/unicex/mapper.py +0 -110
  51. unicex-0.1.18/unicex.egg-info/PKG-INFO +0 -114
  52. unicex-0.1.18/unicex.egg-info/SOURCES.txt +0 -60
  53. {unicex-0.1.18 → unicex-0.2.0}/LICENSE +0 -0
  54. {unicex-0.1.18 → unicex-0.2.0}/setup.cfg +0 -0
  55. {unicex-0.1.18 → unicex-0.2.0}/unicex/_abc/adapter.py +0 -0
  56. {unicex-0.1.18/unicex/_base/asyncio → unicex-0.2.0/unicex/_base}/__init__.py +0 -0
  57. {unicex-0.1.18/unicex/_base/asyncio → unicex-0.2.0/unicex/_base}/client.py +0 -0
  58. {unicex-0.1.18/unicex/_base/asyncio → unicex-0.2.0/unicex/_base}/websocket.py +0 -0
  59. {unicex-0.1.18 → unicex-0.2.0}/unicex/binance/adapter.py +0 -0
  60. {unicex-0.1.18 → unicex-0.2.0}/unicex/bitget/adapter.py +0 -0
  61. {unicex-0.1.18 → unicex-0.2.0}/unicex/enums.py +0 -0
  62. {unicex-0.1.18 → unicex-0.2.0}/unicex/exceptions.py +0 -0
  63. {unicex-0.1.18 → unicex-0.2.0}/unicex/extra.py +0 -0
  64. {unicex-0.1.18 → unicex-0.2.0}/unicex/types.py +0 -0
  65. {unicex-0.1.18 → unicex-0.2.0}/unicex/utils.py +0 -0
  66. {unicex-0.1.18 → unicex-0.2.0}/unicex.egg-info/dependency_links.txt +0 -0
  67. {unicex-0.1.18 → unicex-0.2.0}/unicex.egg-info/top_level.txt +0 -0
unicex-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,122 @@
1
+ Metadata-Version: 2.4
2
+ Name: unicex
3
+ Version: 0.2.0
4
+ Summary: Unified Crypto Exchange API
5
+ Author-email: LoveBloodAndDiamonds <ayazshakirzyanov27@gmail.com>
6
+ License: BSD 3-Clause License
7
+
8
+ Copyright (c) 2025, LoveBloodAndDiamonds
9
+
10
+ Redistribution and use in source and binary forms, with or without
11
+ modification, are permitted provided that the following conditions are met:
12
+
13
+ 1. Redistributions of source code must retain the above copyright notice, this
14
+ list of conditions and the following disclaimer.
15
+
16
+ 2. Redistributions in binary form must reproduce the above copyright notice,
17
+ this list of conditions and the following disclaimer in the documentation
18
+ and/or other materials provided with the distribution.
19
+
20
+ 3. Neither the name of the copyright holder nor the names of its
21
+ contributors may be used to endorse or promote products derived from
22
+ this software without specific prior written permission.
23
+
24
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
28
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
+
35
+ Project-URL: Github, https://github.com/LoveBloodAndDiamonds/uni-cex-api
36
+ Project-URL: Author, https://t.me/LoveBloodAndDiamonds
37
+ Project-URL: Readthedocs, https://unicex.readthedocs.io/ru/latest/
38
+ Requires-Python: >=3.12
39
+ Description-Content-Type: text/markdown
40
+ License-File: LICENSE
41
+ Requires-Dist: aiohttp>=3.12.15
42
+ Requires-Dist: loguru>=0.7.3
43
+ Requires-Dist: orjson>=3.11.3
44
+ Requires-Dist: websockets>=15.0.1
45
+ Dynamic: license-file
46
+
47
+ # Unified Crypto Exchange API
48
+
49
+ `unicex` — асинхронная библиотека для работы с криптовалютными биржами, реализующая унифицированный интерфейс поверх «сырых» REST и WebSocket API разных бирж.
50
+
51
+ ## ✅ Статус реализации
52
+
53
+ | Exchange | Client | UniClient | Adapter | WebsocketManager | UniWebsocketManager | UserWebsocket |
54
+ |----------|--------|-----------|---------|------------------|---------------------|---------------|
55
+ | Binance | [x] | [x] | [x] | [x] | [x] | [x] |
56
+ | Bybit | [ ] | [ ] | [ ] | [ ] | [ ] | [ ] |
57
+ | Bitget | [ ] | [ ] | [ ] | [ ] | [ ] | [ ] |
58
+ | Okx | [ ] | [ ] | [ ] | [ ] | [ ] | [ ] |
59
+ | Mexc | [ ] | [ ] | [ ] | [ ] | [ ] | [ ] |
60
+ | Gate | [ ] | [ ] | [ ] | [ ] | [ ] | [ ] |
61
+
62
+ ---
63
+
64
+ ## 🚀 Быстрый старт
65
+
66
+ - Установка: `pip install unicex` или из исходников: `pip install -e .`
67
+ - Библиотека полностью асинхронная. Примеры импорта:
68
+ - Сырые клиенты: `from unicex.binance import Client`
69
+ - Унифицированные клиенты: `from unicex.binance import UniClient`
70
+ - Менеджеры WS: `from unicex.binance import WebsocketManager, UniWebsocketManager`
71
+
72
+ Пример: получить последние цены через унифицированный клиент Binance
73
+
74
+ ```
75
+ import asyncio
76
+ from unicex.binance import UniClient
77
+
78
+
79
+ async def main():
80
+ client = await UniClient.create()
81
+ prices = await client.last_price()
82
+ print(prices["BTCUSDT"])
83
+ await client.close()
84
+
85
+
86
+ if __name__ == "__main__":
87
+ asyncio.run(main())
88
+ ```
89
+
90
+ Пример: подписаться на трейды через унифицированный WS‑менеджер Bitget
91
+
92
+ ```
93
+ import asyncio
94
+ from unicex.bitget import UniWebsocketManager
95
+ from unicex import TradeDict
96
+
97
+
98
+ async def on_trade(msg: TradeDict):
99
+ print(msg)
100
+
101
+
102
+ async def main():
103
+ uwm = UniWebsocketManager()
104
+ socket = uwm.trades(callback=on_trade, symbol="BTCUSDT")
105
+ await socket.start()
106
+
107
+
108
+ if __name__ == "__main__":
109
+ asyncio.run(main())
110
+ ```
111
+
112
+ ---
113
+
114
+ ## 🧑‍💻 Блок для разработчика
115
+
116
+ ### 📋 Todo
117
+ - Добавить веса и рейт‑лимиты в документацию клиентов
118
+ - Пересмотреть вопрос: должен ли быть адаптер интерфейсом?
119
+ - Доделать BitgetClient и проверить типы
120
+ - Добавить overload к методам с `None, None`
121
+ - Определить порядок полей, возвращаемых адаптером
122
+ - Написать 1–2 примера
unicex-0.2.0/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # Unified Crypto Exchange API
2
+
3
+ `unicex` — асинхронная библиотека для работы с криптовалютными биржами, реализующая унифицированный интерфейс поверх «сырых» REST и WebSocket API разных бирж.
4
+
5
+ ## ✅ Статус реализации
6
+
7
+ | Exchange | Client | UniClient | Adapter | WebsocketManager | UniWebsocketManager | UserWebsocket |
8
+ |----------|--------|-----------|---------|------------------|---------------------|---------------|
9
+ | Binance | [x] | [x] | [x] | [x] | [x] | [x] |
10
+ | Bybit | [ ] | [ ] | [ ] | [ ] | [ ] | [ ] |
11
+ | Bitget | [ ] | [ ] | [ ] | [ ] | [ ] | [ ] |
12
+ | Okx | [ ] | [ ] | [ ] | [ ] | [ ] | [ ] |
13
+ | Mexc | [ ] | [ ] | [ ] | [ ] | [ ] | [ ] |
14
+ | Gate | [ ] | [ ] | [ ] | [ ] | [ ] | [ ] |
15
+
16
+ ---
17
+
18
+ ## 🚀 Быстрый старт
19
+
20
+ - Установка: `pip install unicex` или из исходников: `pip install -e .`
21
+ - Библиотека полностью асинхронная. Примеры импорта:
22
+ - Сырые клиенты: `from unicex.binance import Client`
23
+ - Унифицированные клиенты: `from unicex.binance import UniClient`
24
+ - Менеджеры WS: `from unicex.binance import WebsocketManager, UniWebsocketManager`
25
+
26
+ Пример: получить последние цены через унифицированный клиент Binance
27
+
28
+ ```
29
+ import asyncio
30
+ from unicex.binance import UniClient
31
+
32
+
33
+ async def main():
34
+ client = await UniClient.create()
35
+ prices = await client.last_price()
36
+ print(prices["BTCUSDT"])
37
+ await client.close()
38
+
39
+
40
+ if __name__ == "__main__":
41
+ asyncio.run(main())
42
+ ```
43
+
44
+ Пример: подписаться на трейды через унифицированный WS‑менеджер Bitget
45
+
46
+ ```
47
+ import asyncio
48
+ from unicex.bitget import UniWebsocketManager
49
+ from unicex import TradeDict
50
+
51
+
52
+ async def on_trade(msg: TradeDict):
53
+ print(msg)
54
+
55
+
56
+ async def main():
57
+ uwm = UniWebsocketManager()
58
+ socket = uwm.trades(callback=on_trade, symbol="BTCUSDT")
59
+ await socket.start()
60
+
61
+
62
+ if __name__ == "__main__":
63
+ asyncio.run(main())
64
+ ```
65
+
66
+ ---
67
+
68
+ ## 🧑‍💻 Блок для разработчика
69
+
70
+ ### 📋 Todo
71
+ - Добавить веса и рейт‑лимиты в документацию клиентов
72
+ - Пересмотреть вопрос: должен ли быть адаптер интерфейсом?
73
+ - Доделать BitgetClient и проверить типы
74
+ - Добавить overload к методам с `None, None`
75
+ - Определить порядок полей, возвращаемых адаптером
76
+ - Написать 1–2 примера
@@ -4,7 +4,7 @@ name = "unicex"
4
4
  # • PATCH (x.y.Z) → увеличивается при багфиксе, который не ломает совместимость.
5
5
  # • MINOR (x.Y.z) → увеличивается при добавлении новой функциональности, но без ломающих изменений (backward-compatible).
6
6
  # • MAJOR (X.y.z) → увеличивается при изменениях, которые ломают обратную совместимость.
7
- version = "0.1.18"
7
+ version = "0.2.0"
8
8
 
9
9
  description = "Unified Crypto Exchange API "
10
10
  readme = "README.md"
@@ -17,8 +17,6 @@ dependencies = [
17
17
  "aiohttp>=3.12.15",
18
18
  "loguru>=0.7.3",
19
19
  "orjson>=3.11.3",
20
- "requests>=2.32.5",
21
- "websocket-client>=1.8.0",
22
20
  "websockets>=15.0.1",
23
21
  ]
24
22
 
@@ -20,21 +20,31 @@ __all__ = [
20
20
  "IUniClient",
21
21
  "IUniWebsocketManager",
22
22
  "IAdapter",
23
- "IUniAsyncClient",
24
- "IUniAsyncWebsocketManager",
25
23
  # Base clients and websockets
26
24
  "Websocket",
27
25
  "BaseClient",
28
- "AsyncWebsocket",
29
- "BaseAsyncClient",
26
+ # Binance
27
+ "BinanceClient",
28
+ "BinanceUniClient",
29
+ "BinanceWebsocketManager",
30
+ "BinanceUniWebsocketManager",
31
+ # Bitget
32
+ "BitgetClient",
33
+ "BitgetUniClient",
34
+ "BitgetUniWebsocketManager",
35
+ "BitgetWebsocketManager",
30
36
  ]
31
37
 
32
38
  from ._abc import IAdapter, IUniClient, IUniWebsocketManager
33
- from ._abc.asyncio import IUniClient as IUniAsyncClient
34
- from ._abc.asyncio import IUniWebsocketManager as IUniAsyncWebsocketManager
35
39
  from ._base import BaseClient, Websocket
36
- from ._base.asyncio import BaseClient as BaseAsyncClient
37
- from ._base.asyncio import Websocket as AsyncWebsocket
40
+ from .binance import Client as BinanceClient
41
+ from .binance import UniClient as BinanceUniClient
42
+ from .binance import UniWebsocketManager as BinanceUniWebsocketManager
43
+ from .binance import WebsocketManager as BinanceWebsocketManager
44
+ from .bitget import Client as BitgetClient
45
+ from .bitget import UniClient as BitgetUniClient
46
+ from .bitget import UniWebsocketManager as BitgetUniWebsocketManager
47
+ from .bitget import WebsocketManager as BitgetWebsocketManager
38
48
  from .enums import Exchange, MarketType, Side, Timeframe
39
49
  from .mapper import get_uni_client, get_uni_websocket_manager
40
50
  from .types import AggTradeDict, KlineDict, LoggerLike, RequestMethod, TickerDailyDict, TradeDict
@@ -5,4 +5,5 @@ __all__ = [
5
5
  ]
6
6
 
7
7
  from .adapter import IAdapter
8
- from .sync import IUniClient, IUniWebsocketManager
8
+ from .uni_client import IUniClient
9
+ from .uni_websocket_manager import IUniWebsocketManager
@@ -6,12 +6,12 @@ from typing import Generic, Self, TypeVar, overload
6
6
 
7
7
  import aiohttp
8
8
 
9
- from unicex._base.asyncio import BaseClient
9
+ from unicex._base import BaseClient
10
10
  from unicex.enums import Timeframe
11
11
  from unicex.types import KlineDict, LoggerLike, TickerDailyDict
12
12
  from unicex.utils import batched_list
13
13
 
14
- from ..adapter import IAdapter
14
+ from .adapter import IAdapter
15
15
 
16
16
  TClient = TypeVar("TClient", bound="BaseClient")
17
17
 
@@ -6,7 +6,7 @@ from typing import Any, overload
6
6
 
7
7
  from loguru import logger as _logger
8
8
 
9
- from unicex._base.asyncio import BaseClient, Websocket
9
+ from unicex._base import BaseClient, Websocket
10
10
  from unicex.enums import Timeframe
11
11
  from unicex.types import LoggerLike
12
12
 
@@ -1,4 +1,4 @@
1
- """Пакет содержит асинхронные клиенты и менеджеры для работы с биржей Binance."""
1
+ """Пакет, содержащий реализации клиентов и менеджеров для работы с биржей Binance."""
2
2
 
3
3
  __all__ = ["Client", "UniClient", "UserWebsocket", "WebsocketManager", "UniWebsocketManager"]
4
4
 
@@ -1,18 +1,86 @@
1
1
  __all__ = ["Client"]
2
2
 
3
3
  import json
4
+ import time
4
5
  import warnings
5
6
  from typing import Any
6
7
 
7
- from unicex._base.asyncio import BaseClient
8
+ from unicex._base import BaseClient
9
+ from unicex.exceptions import NotAuthorized
8
10
  from unicex.types import RequestMethod
11
+ from unicex.utils import dict_to_query_string, filter_params, generate_hmac_sha256_signature
9
12
 
10
- from .._mixins import ClientMixin
11
13
 
12
-
13
- class Client(ClientMixin, BaseClient):
14
+ class Client(BaseClient):
14
15
  """Клиент для работы с Binance API."""
15
16
 
17
+ _BASE_SPOT_URL: str = "https://api.binance.com"
18
+ """Базовый URL для REST API Binance Spot."""
19
+
20
+ _BASE_FUTURES_URL: str = "https://fapi.binance.com"
21
+ """Базовый URL для REST API Binance Futures."""
22
+
23
+ _RECV_WINDOW: int = 5000
24
+ """Стандартный интервал времени для получения ответа от сервера."""
25
+
26
+ def _get_headers(self) -> dict:
27
+ """Возвращает заголовки для запросов к Binance API."""
28
+ headers = {"Accept": "application/json"}
29
+ if self._api_key: # type: ignore[attr-defined]
30
+ headers["X-MBX-APIKEY"] = self._api_key # type: ignore[attr-defined]
31
+ return headers
32
+
33
+ def _prepare_payload(
34
+ self,
35
+ *,
36
+ signed: bool,
37
+ params: dict[str, Any] | None,
38
+ data: dict[str, Any] | None,
39
+ ) -> tuple[dict[str, Any], dict[str, Any] | None]:
40
+ """Подготавливает payload и заголовки для запроса.
41
+
42
+ Если signed=True:
43
+ - добавляет подпись и все обязательные параметры в заголовки
44
+
45
+ Если signed=False:
46
+ - возвращает только отфильтрованные params/data.
47
+
48
+ Параметры:
49
+ signed (`bool`): Нужно ли подписывать запрос.
50
+ params (`dict | None`): Параметры для query string.
51
+ data (`dict | None`): Параметры для тела запроса.
52
+
53
+ Возвращает:
54
+ tuple:
55
+ - payload (`dict`): Параметры/тело запроса с подписью (если нужно).
56
+ - headers (`dict | None`): Заголовки для запроса или None.
57
+ """
58
+ # Фильтруем параметры от None значений
59
+ params = filter_params(params) if params else {}
60
+ data = filter_params(data) if data else {}
61
+
62
+ if not signed:
63
+ return {"params": params, "data": data}, None
64
+
65
+ if not self._api_key or not self._api_secret: # type: ignore[attr-defined]
66
+ raise NotAuthorized("Api key is required to private endpoints")
67
+
68
+ # Объединяем все параметры в payload
69
+ payload = {**params, **data}
70
+ payload["timestamp"] = int(time.time() * 1000)
71
+ payload["recvWindow"] = self._RECV_WINDOW
72
+
73
+ # Генерируем подпись
74
+ query_string = dict_to_query_string(payload)
75
+ payload["signature"] = generate_hmac_sha256_signature(
76
+ self._api_secret, # type: ignore[attr-defined]
77
+ query_string,
78
+ "hex",
79
+ )
80
+
81
+ headers = self._get_headers()
82
+ return payload, headers
83
+
16
84
  async def _make_request(
17
85
  self,
18
86
  method: RequestMethod,
@@ -2,11 +2,11 @@ __all__ = ["UniClient"]
2
2
 
3
3
  from functools import cached_property
4
4
 
5
- from unicex._abc.asyncio import IUniClient
5
+ from unicex._abc import IUniClient
6
6
  from unicex.enums import Exchange, Timeframe
7
7
  from unicex.types import KlineDict, TickerDailyDict
8
8
 
9
- from ..adapter import Adapter
9
+ from .adapter import Adapter
10
10
  from .client import Client
11
11
 
12
12
 
@@ -3,12 +3,12 @@ __all__ = ["UniWebsocketManager"]
3
3
  from collections.abc import Awaitable, Callable
4
4
  from typing import Any
5
5
 
6
- from unicex._abc.asyncio import IUniWebsocketManager
7
- from unicex._base.asyncio import Websocket
6
+ from unicex._abc import IUniWebsocketManager
7
+ from unicex._base import Websocket
8
8
  from unicex.enums import Exchange, Timeframe
9
9
  from unicex.types import LoggerLike
10
10
 
11
- from ..adapter import Adapter
11
+ from .adapter import Adapter
12
12
  from .client import Client
13
13
  from .uni_client import UniClient
14
14
  from .websocket_manager import WebsocketManager
@@ -6,20 +6,28 @@ from typing import Any
6
6
 
7
7
  from loguru import logger as _logger
8
8
 
9
- from unicex._base.asyncio import Websocket
9
+ from unicex._base import Websocket
10
10
  from unicex.exceptions import NotSupported
11
11
  from unicex.types import AccountType, LoggerLike
12
12
 
13
- from .._mixins import UserWebsocketMixin
14
13
  from .client import Client
15
14
 
16
15
 
17
- class UserWebsocket(UserWebsocketMixin):
16
+ class UserWebsocket:
18
17
  """Пользовательский вебсокет Binance с авто‑продлением listenKey.
19
18
 
20
19
  Поддержка типов аккаунта: "SPOT" и "FUTURES" (USDT‑M фьючерсы).
21
20
  """
22
21
 
22
+ _BASE_SPOT_URL: str = "wss://stream.binance.com:9443"
23
+ """Базовый URL для вебсокета на спот."""
24
+
25
+ _BASE_FUTURES_URL: str = "wss://fstream.binance.com"
26
+ """Базовый URL для вебсокета на фьючерсы."""
27
+
28
+ _RENEW_INTERVAL: int = 30 * 60
29
+ """Интервал продления listenKey (сек.)"""
30
+
23
31
  def __init__(
24
32
  self,
25
33
  callback: Callable[[Any], Awaitable[None]],
@@ -28,7 +36,7 @@ class UserWebsocket(UserWebsocketMixin):
28
36
  logger: LoggerLike | None = None,
29
37
  **kwargs: Any, # Не дадим сломаться, если юзер передал ненужные аргументы
30
38
  ) -> None:
31
- """Инициализирует асинхронный пользовательский вебсокет для работы с биржей Binance.
39
+ """Инициализирует пользовательский вебсокет для работы с биржей Binance.
32
40
 
33
41
  Параметры:
34
42
  callback (`Callable`): Асинхронная функция обратного вызова, которая принимает сообщение с вебсокета.
@@ -48,6 +56,15 @@ class UserWebsocket(UserWebsocketMixin):
48
56
 
49
57
  self._running = False
50
58
 
59
+ @classmethod
60
+ def _create_ws_url(cls, type: AccountType, listen_key: str) -> str:
61
+ """Создает URL для подключения к WebSocket."""
62
+ if type == "FUTURES":
63
+ return f"{cls._BASE_FUTURES_URL}/ws/{listen_key}"
64
+ if type == "SPOT":
65
+ return f"{cls._BASE_SPOT_URL}/ws/{listen_key}"
66
+ raise NotSupported(f"Account type '{type}' not supported")
67
+
51
68
  async def start(self) -> None:
52
69
  """Запускает пользовательский стрим с автопродлением listenKey."""
53
70
  self._running = True
@@ -1,22 +1,26 @@
1
1
  __all__ = ["WebsocketManager"]
2
2
 
3
-
4
3
  from collections.abc import Awaitable, Callable, Sequence
5
4
  from typing import Any
6
5
 
7
- from unicex._base.asyncio import Websocket
6
+ from unicex._base import Websocket
8
7
  from unicex.exceptions import NotAuthorized
9
8
 
10
- from .._mixins import WebsocketManagerMixin
11
9
  from .client import Client
12
10
  from .user_websocket import UserWebsocket
13
11
 
14
12
  type CallbackType = Callable[[Any], Awaitable[None]]
15
13
 
16
14
 
17
- class WebsocketManager(WebsocketManagerMixin):
15
+ class WebsocketManager:
18
16
  """Менеджер асинхронных вебсокетов для Binance."""
19
17
 
18
+ _BASE_SPOT_URL: str = "wss://stream.binance.com:9443"
19
+ """Базовый URL для вебсокета на спот."""
20
+
21
+ _BASE_FUTURES_URL: str = "wss://fstream.binance.com"
22
+ """Базовый URL для вебсокета на фьючерсы."""
23
+
20
24
  def __init__(self, client: Client | None = None, **ws_kwargs: Any) -> None:
21
25
  """Инициализирует менеджер вебсокетов для Binance.
22
26
 
@@ -27,6 +31,37 @@ class WebsocketManager(WebsocketManagerMixin):
27
31
  self.client = client
28
32
  self._ws_kwargs = ws_kwargs
29
33
 
34
+ def _generate_stream_url(
35
+ self,
36
+ type: str,
37
+ url: str,
38
+ symbol: str | None = None,
39
+ symbols: Sequence[str] | None = None,
40
+ require_symbol: bool = False,
41
+ ) -> str:
42
+ """Генерирует URL для вебсокета Binance. Параметры symbol и symbols не могут быть использованы вместе.
43
+
44
+ Параметры:
45
+ type (`str`): Тип вебсокета.
46
+ url (`str`): Базовый URL для вебсокета.
47
+ symbol (`str | None`): Символ для подписки.
48
+ symbols (`Sequence[str] | None`): Список символов для подписки.
49
+ require_symbol (`bool`): Требуется ли символ для подписки.
50
+
51
+ Возвращает:
52
+ str: URL для вебсокета.
53
+ """
54
+ if symbol and symbols:
55
+ raise ValueError("Parameters symbol and symbols cannot be used together")
56
+ if require_symbol and not (symbol or symbols):
57
+ raise ValueError("Either symbol or symbols must be provided")
58
+ if symbol:
59
+ return f"{url}/ws/{symbol.lower()}@{type}"
60
+ if symbols:
61
+ streams = "/".join(f"{s.lower()}@{type}" for s in symbols)
62
+ return f"{url}/stream?streams={streams}"
63
+ return f"{url}/ws/{type}"
64
+
30
65
  def trade(
31
66
  self,
32
67
  callback: CallbackType,
@@ -1,5 +1,8 @@
1
- __all__ = ["Client", "WebsocketManager", "UniWebsocketManager", "UniClient"]
1
+ """Пакет, содержащий реализации клиентов и менеджеров для работы с биржей Bitget."""
2
2
 
3
+ __all__ = ["Client", "WebsocketManager", "UniWebsocketManager", "UniClient", "Adapter"]
4
+
5
+ from .adapter import Adapter
3
6
  from .client import Client
4
7
  from .uni_client import UniClient
5
8
  from .uni_websocket_manager import UniWebsocketManager