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.
- unicex-0.2.0/PKG-INFO +122 -0
- unicex-0.2.0/README.md +76 -0
- {unicex-0.1.18 → unicex-0.2.0}/pyproject.toml +1 -3
- {unicex-0.1.18 → unicex-0.2.0}/unicex/__init__.py +18 -8
- {unicex-0.1.18 → unicex-0.2.0}/unicex/_abc/__init__.py +2 -1
- {unicex-0.1.18/unicex/_abc/asyncio → unicex-0.2.0/unicex/_abc}/uni_client.py +2 -2
- {unicex-0.1.18/unicex/_abc/asyncio → unicex-0.2.0/unicex/_abc}/uni_websocket_manager.py +1 -1
- {unicex-0.1.18/unicex/binance/asyncio → unicex-0.2.0/unicex/binance}/__init__.py +1 -1
- {unicex-0.1.18/unicex/binance/asyncio → unicex-0.2.0/unicex/binance}/client.py +72 -4
- {unicex-0.1.18/unicex/binance/asyncio → unicex-0.2.0/unicex/binance}/uni_client.py +2 -2
- {unicex-0.1.18/unicex/binance/asyncio → unicex-0.2.0/unicex/binance}/uni_websocket_manager.py +3 -3
- {unicex-0.1.18/unicex/binance/asyncio → unicex-0.2.0/unicex/binance}/user_websocket.py +21 -4
- {unicex-0.1.18/unicex/binance/asyncio → unicex-0.2.0/unicex/binance}/websocket_manager.py +39 -4
- {unicex-0.1.18/unicex/bitget/asyncio → unicex-0.2.0/unicex/bitget}/__init__.py +4 -1
- {unicex-0.1.18/unicex/bitget/asyncio → unicex-0.2.0/unicex/bitget}/client.py +118 -4
- {unicex-0.1.18/unicex/bitget/asyncio → unicex-0.2.0/unicex/bitget}/uni_client.py +2 -2
- {unicex-0.1.18/unicex/bitget/asyncio → unicex-0.2.0/unicex/bitget}/uni_websocket_manager.py +3 -3
- {unicex-0.1.18/unicex/bitget/asyncio → unicex-0.2.0/unicex/bitget}/websocket_manager.py +42 -4
- unicex-0.2.0/unicex/mapper.py +57 -0
- unicex-0.2.0/unicex.egg-info/PKG-INFO +122 -0
- unicex-0.2.0/unicex.egg-info/SOURCES.txt +35 -0
- {unicex-0.1.18 → unicex-0.2.0}/unicex.egg-info/requires.txt +0 -2
- unicex-0.1.18/PKG-INFO +0 -114
- unicex-0.1.18/README.md +0 -66
- unicex-0.1.18/unicex/_abc/asyncio/__init__.py +0 -4
- unicex-0.1.18/unicex/_abc/sync/__init__.py +0 -4
- unicex-0.1.18/unicex/_abc/sync/uni_client.py +0 -275
- unicex-0.1.18/unicex/_abc/sync/uni_websocket_manager.py +0 -294
- unicex-0.1.18/unicex/_base/__init__.py +0 -6
- unicex-0.1.18/unicex/_base/sync/__init__.py +0 -7
- unicex-0.1.18/unicex/_base/sync/client.py +0 -186
- unicex-0.1.18/unicex/_base/sync/websocket.py +0 -239
- unicex-0.1.18/unicex/binance/__init__.py +0 -13
- unicex-0.1.18/unicex/binance/_mixins/__init__.py +0 -7
- unicex-0.1.18/unicex/binance/_mixins/client.py +0 -78
- unicex-0.1.18/unicex/binance/_mixins/user_websocket.py +0 -27
- unicex-0.1.18/unicex/binance/_mixins/websocket_manager.py +0 -45
- unicex-0.1.18/unicex/binance/sync/__init__.py +0 -9
- unicex-0.1.18/unicex/binance/sync/client.py +0 -1536
- unicex-0.1.18/unicex/binance/sync/uni_client.py +0 -176
- unicex-0.1.18/unicex/binance/sync/uni_websocket_manager.py +0 -166
- unicex-0.1.18/unicex/binance/sync/user_websocket.py +0 -165
- unicex-0.1.18/unicex/binance/sync/websocket_manager.py +0 -876
- unicex-0.1.18/unicex/bitget/__init__.py +0 -1
- unicex-0.1.18/unicex/bitget/_mixins/__init__.py +0 -7
- unicex-0.1.18/unicex/bitget/_mixins/client.py +0 -125
- unicex-0.1.18/unicex/bitget/_mixins/user_websocket.py +0 -0
- unicex-0.1.18/unicex/bitget/_mixins/websocket_manager.py +0 -47
- unicex-0.1.18/unicex/bitget/sync/__init__.py +0 -0
- unicex-0.1.18/unicex/mapper.py +0 -110
- unicex-0.1.18/unicex.egg-info/PKG-INFO +0 -114
- unicex-0.1.18/unicex.egg-info/SOURCES.txt +0 -60
- {unicex-0.1.18 → unicex-0.2.0}/LICENSE +0 -0
- {unicex-0.1.18 → unicex-0.2.0}/setup.cfg +0 -0
- {unicex-0.1.18 → unicex-0.2.0}/unicex/_abc/adapter.py +0 -0
- {unicex-0.1.18/unicex/_base/asyncio → unicex-0.2.0/unicex/_base}/__init__.py +0 -0
- {unicex-0.1.18/unicex/_base/asyncio → unicex-0.2.0/unicex/_base}/client.py +0 -0
- {unicex-0.1.18/unicex/_base/asyncio → unicex-0.2.0/unicex/_base}/websocket.py +0 -0
- {unicex-0.1.18 → unicex-0.2.0}/unicex/binance/adapter.py +0 -0
- {unicex-0.1.18 → unicex-0.2.0}/unicex/bitget/adapter.py +0 -0
- {unicex-0.1.18 → unicex-0.2.0}/unicex/enums.py +0 -0
- {unicex-0.1.18 → unicex-0.2.0}/unicex/exceptions.py +0 -0
- {unicex-0.1.18 → unicex-0.2.0}/unicex/extra.py +0 -0
- {unicex-0.1.18 → unicex-0.2.0}/unicex/types.py +0 -0
- {unicex-0.1.18 → unicex-0.2.0}/unicex/utils.py +0 -0
- {unicex-0.1.18 → unicex-0.2.0}/unicex.egg-info/dependency_links.txt +0 -0
- {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.
|
|
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
|
-
|
|
29
|
-
"
|
|
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 .
|
|
37
|
-
from .
|
|
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
|
|
@@ -6,12 +6,12 @@ from typing import Generic, Self, TypeVar, overload
|
|
|
6
6
|
|
|
7
7
|
import aiohttp
|
|
8
8
|
|
|
9
|
-
from unicex._base
|
|
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
|
|
14
|
+
from .adapter import IAdapter
|
|
15
15
|
|
|
16
16
|
TClient = TypeVar("TClient", bound="BaseClient")
|
|
17
17
|
|
|
@@ -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
|
|
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
|
|
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
|
|
9
|
+
from .adapter import Adapter
|
|
10
10
|
from .client import Client
|
|
11
11
|
|
|
12
12
|
|
{unicex-0.1.18/unicex/binance/asyncio → unicex-0.2.0/unicex/binance}/uni_websocket_manager.py
RENAMED
|
@@ -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
|
|
7
|
-
from unicex._base
|
|
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
|
|
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
|
|
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
|
|
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
|
-
"""Инициализирует
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|