walrasquant-lib 0.4.20__py3-none-any.whl
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.
- walrasquant/__init__.py +7 -0
- walrasquant/aggregation.py +449 -0
- walrasquant/backends/__init__.py +5 -0
- walrasquant/backends/db.py +109 -0
- walrasquant/backends/db_memory.py +61 -0
- walrasquant/backends/db_postgresql.py +321 -0
- walrasquant/backends/db_sqlite.py +310 -0
- walrasquant/base/__init__.py +24 -0
- walrasquant/base/api_client.py +46 -0
- walrasquant/base/connector.py +863 -0
- walrasquant/base/ems.py +794 -0
- walrasquant/base/exchange.py +213 -0
- walrasquant/base/oms.py +428 -0
- walrasquant/base/retry.py +220 -0
- walrasquant/base/sms.py +545 -0
- walrasquant/base/ws_client.py +408 -0
- walrasquant/config.py +284 -0
- walrasquant/constants.py +413 -0
- walrasquant/core/__init__.py +0 -0
- walrasquant/core/cache.py +688 -0
- walrasquant/core/clock.py +59 -0
- walrasquant/core/connection.py +41 -0
- walrasquant/core/entity.py +504 -0
- walrasquant/core/nautilius_core.py +103 -0
- walrasquant/core/registry.py +41 -0
- walrasquant/engine.py +745 -0
- walrasquant/error.py +34 -0
- walrasquant/exchange/__init__.py +13 -0
- walrasquant/exchange/base_factory.py +172 -0
- walrasquant/exchange/binance/__init__.py +30 -0
- walrasquant/exchange/binance/connector.py +1093 -0
- walrasquant/exchange/binance/constants.py +934 -0
- walrasquant/exchange/binance/ems.py +140 -0
- walrasquant/exchange/binance/error.py +48 -0
- walrasquant/exchange/binance/exchange.py +144 -0
- walrasquant/exchange/binance/factory.py +115 -0
- walrasquant/exchange/binance/oms.py +1807 -0
- walrasquant/exchange/binance/rest_api.py +1653 -0
- walrasquant/exchange/binance/schema.py +1063 -0
- walrasquant/exchange/binance/websockets.py +389 -0
- walrasquant/exchange/bitget/__init__.py +28 -0
- walrasquant/exchange/bitget/connector.py +578 -0
- walrasquant/exchange/bitget/constants.py +392 -0
- walrasquant/exchange/bitget/ems.py +202 -0
- walrasquant/exchange/bitget/error.py +36 -0
- walrasquant/exchange/bitget/exchange.py +128 -0
- walrasquant/exchange/bitget/factory.py +135 -0
- walrasquant/exchange/bitget/oms.py +1619 -0
- walrasquant/exchange/bitget/rest_api.py +610 -0
- walrasquant/exchange/bitget/schema.py +885 -0
- walrasquant/exchange/bitget/websockets.py +753 -0
- walrasquant/exchange/bybit/__init__.py +32 -0
- walrasquant/exchange/bybit/connector.py +819 -0
- walrasquant/exchange/bybit/constants.py +479 -0
- walrasquant/exchange/bybit/ems.py +93 -0
- walrasquant/exchange/bybit/error.py +36 -0
- walrasquant/exchange/bybit/exchange.py +108 -0
- walrasquant/exchange/bybit/factory.py +128 -0
- walrasquant/exchange/bybit/oms.py +1195 -0
- walrasquant/exchange/bybit/rest_api.py +570 -0
- walrasquant/exchange/bybit/schema.py +867 -0
- walrasquant/exchange/bybit/websockets.py +307 -0
- walrasquant/exchange/hyperliquid/__init__.py +28 -0
- walrasquant/exchange/hyperliquid/connector.py +370 -0
- walrasquant/exchange/hyperliquid/constants.py +371 -0
- walrasquant/exchange/hyperliquid/ems.py +156 -0
- walrasquant/exchange/hyperliquid/error.py +48 -0
- walrasquant/exchange/hyperliquid/exchange.py +120 -0
- walrasquant/exchange/hyperliquid/factory.py +135 -0
- walrasquant/exchange/hyperliquid/oms.py +1081 -0
- walrasquant/exchange/hyperliquid/rest_api.py +348 -0
- walrasquant/exchange/hyperliquid/schema.py +583 -0
- walrasquant/exchange/hyperliquid/websockets.py +592 -0
- walrasquant/exchange/okx/__init__.py +25 -0
- walrasquant/exchange/okx/connector.py +931 -0
- walrasquant/exchange/okx/constants.py +518 -0
- walrasquant/exchange/okx/ems.py +144 -0
- walrasquant/exchange/okx/error.py +66 -0
- walrasquant/exchange/okx/exchange.py +102 -0
- walrasquant/exchange/okx/factory.py +138 -0
- walrasquant/exchange/okx/oms.py +1199 -0
- walrasquant/exchange/okx/rest_api.py +799 -0
- walrasquant/exchange/okx/schema.py +1449 -0
- walrasquant/exchange/okx/websockets.py +420 -0
- walrasquant/exchange/registry.py +201 -0
- walrasquant/execution/__init__.py +24 -0
- walrasquant/execution/algorithm.py +968 -0
- walrasquant/execution/algorithms/__init__.py +3 -0
- walrasquant/execution/algorithms/twap.py +392 -0
- walrasquant/execution/config.py +34 -0
- walrasquant/execution/constants.py +27 -0
- walrasquant/execution/schema.py +62 -0
- walrasquant/indicator.py +382 -0
- walrasquant/push.py +77 -0
- walrasquant/schema.py +755 -0
- walrasquant/strategy.py +1805 -0
- walrasquant/tools/__init__.py +0 -0
- walrasquant/tools/pm2_wrapper.py +1016 -0
- walrasquant/web/__init__.py +26 -0
- walrasquant/web/app.py +157 -0
- walrasquant/web/server.py +92 -0
- walrasquant_lib-0.4.20.dist-info/METADATA +162 -0
- walrasquant_lib-0.4.20.dist-info/RECORD +105 -0
- walrasquant_lib-0.4.20.dist-info/WHEEL +4 -0
- walrasquant_lib-0.4.20.dist-info/entry_points.txt +3 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
from typing import Callable, List, Dict
|
|
2
|
+
from typing import Any
|
|
3
|
+
from urllib.parse import urlencode
|
|
4
|
+
from walrasquant.base import WSClient
|
|
5
|
+
from walrasquant.exchange.binance.constants import (
|
|
6
|
+
BinanceAccountType,
|
|
7
|
+
BinanceKlineInterval,
|
|
8
|
+
BinanceRateLimiter,
|
|
9
|
+
)
|
|
10
|
+
from walrasquant.core.entity import TaskManager
|
|
11
|
+
from walrasquant.core.nautilius_core import hmac_signature, LiveClock
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BinanceWSClient(WSClient):
|
|
15
|
+
def __init__(
|
|
16
|
+
self,
|
|
17
|
+
account_type: BinanceAccountType,
|
|
18
|
+
handler: Callable[..., Any],
|
|
19
|
+
task_manager: TaskManager,
|
|
20
|
+
clock: LiveClock,
|
|
21
|
+
ws_suffix: str = "/ws",
|
|
22
|
+
custom_url: str | None = None,
|
|
23
|
+
max_subscriptions_per_client: int | None = None,
|
|
24
|
+
max_clients: int | None = None,
|
|
25
|
+
):
|
|
26
|
+
self._account_type = account_type
|
|
27
|
+
url = account_type.ws_url
|
|
28
|
+
|
|
29
|
+
if ws_suffix not in ["/ws", "/stream"]:
|
|
30
|
+
raise ValueError(f"Invalid ws_suffix: {ws_suffix}")
|
|
31
|
+
|
|
32
|
+
url += ws_suffix
|
|
33
|
+
|
|
34
|
+
if custom_url is not None:
|
|
35
|
+
url = custom_url
|
|
36
|
+
|
|
37
|
+
super().__init__(
|
|
38
|
+
url,
|
|
39
|
+
handler=handler,
|
|
40
|
+
task_manager=task_manager,
|
|
41
|
+
clock=clock,
|
|
42
|
+
enable_auto_ping=False,
|
|
43
|
+
max_subscriptions_per_client=max_subscriptions_per_client,
|
|
44
|
+
max_clients=max_clients,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
def _send_payload(
|
|
48
|
+
self,
|
|
49
|
+
params: List[str],
|
|
50
|
+
method: str = "SUBSCRIBE",
|
|
51
|
+
chunk_size: int = 50,
|
|
52
|
+
client_id: int | None = None,
|
|
53
|
+
):
|
|
54
|
+
# Split params into chunks of 100 if length exceeds 100
|
|
55
|
+
params_chunks = [
|
|
56
|
+
params[i : i + chunk_size] for i in range(0, len(params), chunk_size)
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
for chunk in params_chunks:
|
|
60
|
+
payload = {
|
|
61
|
+
"method": method,
|
|
62
|
+
"params": chunk,
|
|
63
|
+
"id": self._clock.timestamp_ms(),
|
|
64
|
+
}
|
|
65
|
+
self.send(payload, client_id=client_id)
|
|
66
|
+
|
|
67
|
+
def _subscribe(self, params: List[str]):
|
|
68
|
+
assigned = self._register_subscriptions(params)
|
|
69
|
+
if not assigned:
|
|
70
|
+
return
|
|
71
|
+
for client_id, client_params in assigned.items():
|
|
72
|
+
for param in client_params:
|
|
73
|
+
self._log.debug(f"Subscribing to {param}...")
|
|
74
|
+
if self._is_client_connected(client_id):
|
|
75
|
+
self._send_payload(
|
|
76
|
+
client_params, method="SUBSCRIBE", client_id=client_id
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
def _unsubscribe(self, params: List[str]):
|
|
80
|
+
removed = self._unregister_subscriptions(params)
|
|
81
|
+
if not removed:
|
|
82
|
+
return
|
|
83
|
+
for client_id, client_params in removed.items():
|
|
84
|
+
for param in client_params:
|
|
85
|
+
self._log.debug(f"Unsubscribing from {param}...")
|
|
86
|
+
self._send_payload(client_params, method="UNSUBSCRIBE", client_id=client_id)
|
|
87
|
+
|
|
88
|
+
def subscribe_agg_trade(self, symbols: List[str]):
|
|
89
|
+
if (
|
|
90
|
+
self._account_type.is_isolated_margin_or_margin
|
|
91
|
+
or self._account_type.is_portfolio_margin
|
|
92
|
+
):
|
|
93
|
+
raise ValueError(
|
|
94
|
+
"Not Supported for `Margin Account` or `Portfolio Margin Account`"
|
|
95
|
+
)
|
|
96
|
+
params = [f"{symbol.lower()}@aggTrade" for symbol in symbols]
|
|
97
|
+
self._subscribe(params)
|
|
98
|
+
|
|
99
|
+
def subscribe_trade(self, symbols: List[str]):
|
|
100
|
+
if (
|
|
101
|
+
self._account_type.is_isolated_margin_or_margin
|
|
102
|
+
or self._account_type.is_portfolio_margin
|
|
103
|
+
):
|
|
104
|
+
raise ValueError(
|
|
105
|
+
"Not Supported for `Margin Account` or `Portfolio Margin Account`"
|
|
106
|
+
)
|
|
107
|
+
params = [f"{symbol.lower()}@trade" for symbol in symbols]
|
|
108
|
+
self._subscribe(params)
|
|
109
|
+
|
|
110
|
+
def subscribe_book_ticker(self, symbols: List[str]):
|
|
111
|
+
if (
|
|
112
|
+
self._account_type.is_isolated_margin_or_margin
|
|
113
|
+
or self._account_type.is_portfolio_margin
|
|
114
|
+
):
|
|
115
|
+
raise ValueError(
|
|
116
|
+
"Not Supported for `Margin Account` or `Portfolio Margin Account`"
|
|
117
|
+
)
|
|
118
|
+
params = [f"{symbol.lower()}@bookTicker" for symbol in symbols]
|
|
119
|
+
self._subscribe(params)
|
|
120
|
+
|
|
121
|
+
def subscribe_partial_book_depth(self, symbols: List[str], level: int):
|
|
122
|
+
if level not in (5, 10, 20):
|
|
123
|
+
raise ValueError("Level must be 5, 10, or 20")
|
|
124
|
+
params = [f"{symbol.lower()}@depth{level}@100ms" for symbol in symbols]
|
|
125
|
+
self._subscribe(params)
|
|
126
|
+
|
|
127
|
+
def subscribe_mark_price(self, symbols: List[str]):
|
|
128
|
+
if not self._account_type.is_future:
|
|
129
|
+
raise ValueError("Only Supported for `Future Account`")
|
|
130
|
+
params = [f"{symbol.lower()}@markPrice@1s" for symbol in symbols]
|
|
131
|
+
self._subscribe(params)
|
|
132
|
+
|
|
133
|
+
def subscribe_user_data_stream(self, listen_key: str):
|
|
134
|
+
self._subscribe([listen_key])
|
|
135
|
+
|
|
136
|
+
def subscribe_kline(
|
|
137
|
+
self,
|
|
138
|
+
symbols: List[str],
|
|
139
|
+
interval: BinanceKlineInterval,
|
|
140
|
+
):
|
|
141
|
+
if (
|
|
142
|
+
self._account_type.is_isolated_margin_or_margin
|
|
143
|
+
or self._account_type.is_portfolio_margin
|
|
144
|
+
):
|
|
145
|
+
raise ValueError(
|
|
146
|
+
"Not Supported for `Margin Account` or `Portfolio Margin Account`"
|
|
147
|
+
)
|
|
148
|
+
params = [f"{symbol.lower()}@kline_{interval.value}" for symbol in symbols]
|
|
149
|
+
self._subscribe(params)
|
|
150
|
+
|
|
151
|
+
def unsubscribe_agg_trade(self, symbols: List[str]):
|
|
152
|
+
if (
|
|
153
|
+
self._account_type.is_isolated_margin_or_margin
|
|
154
|
+
or self._account_type.is_portfolio_margin
|
|
155
|
+
):
|
|
156
|
+
raise ValueError(
|
|
157
|
+
"Not Supported for `Margin Account` or `Portfolio Margin Account`"
|
|
158
|
+
)
|
|
159
|
+
params = [f"{symbol.lower()}@aggTrade" for symbol in symbols]
|
|
160
|
+
self._unsubscribe(params)
|
|
161
|
+
|
|
162
|
+
def unsubscribe_trade(self, symbols: List[str]):
|
|
163
|
+
if (
|
|
164
|
+
self._account_type.is_isolated_margin_or_margin
|
|
165
|
+
or self._account_type.is_portfolio_margin
|
|
166
|
+
):
|
|
167
|
+
raise ValueError(
|
|
168
|
+
"Not Supported for `Margin Account` or `Portfolio Margin Account`"
|
|
169
|
+
)
|
|
170
|
+
params = [f"{symbol.lower()}@trade" for symbol in symbols]
|
|
171
|
+
self._unsubscribe(params)
|
|
172
|
+
|
|
173
|
+
def unsubscribe_book_ticker(self, symbols: List[str]):
|
|
174
|
+
if (
|
|
175
|
+
self._account_type.is_isolated_margin_or_margin
|
|
176
|
+
or self._account_type.is_portfolio_margin
|
|
177
|
+
):
|
|
178
|
+
raise ValueError(
|
|
179
|
+
"Not Supported for `Margin Account` or `Portfolio Margin Account`"
|
|
180
|
+
)
|
|
181
|
+
params = [f"{symbol.lower()}@bookTicker" for symbol in symbols]
|
|
182
|
+
self._unsubscribe(params)
|
|
183
|
+
|
|
184
|
+
def unsubscribe_partial_book_depth(self, symbols: List[str], level: int):
|
|
185
|
+
if level not in (5, 10, 20):
|
|
186
|
+
raise ValueError("Level must be 5, 10, or 20")
|
|
187
|
+
params = [f"{symbol.lower()}@depth{level}@100ms" for symbol in symbols]
|
|
188
|
+
self._unsubscribe(params)
|
|
189
|
+
|
|
190
|
+
def subscribe_diff_depth(self, symbols: List[str]):
|
|
191
|
+
params = [f"{symbol.lower()}@depth@100ms" for symbol in symbols]
|
|
192
|
+
self._subscribe(params)
|
|
193
|
+
|
|
194
|
+
def unsubscribe_diff_depth(self, symbols: List[str]):
|
|
195
|
+
params = [f"{symbol.lower()}@depth@100ms" for symbol in symbols]
|
|
196
|
+
self._unsubscribe(params)
|
|
197
|
+
|
|
198
|
+
def unsubscribe_mark_price(self, symbols: List[str]):
|
|
199
|
+
if not self._account_type.is_future:
|
|
200
|
+
raise ValueError("Only Supported for `Future Account`")
|
|
201
|
+
params = [f"{symbol.lower()}@markPrice@1s" for symbol in symbols]
|
|
202
|
+
self._unsubscribe(params)
|
|
203
|
+
|
|
204
|
+
def unsubscribe_user_data_stream(self, listen_key: str):
|
|
205
|
+
self._unsubscribe([listen_key])
|
|
206
|
+
|
|
207
|
+
def unsubscribe_kline(
|
|
208
|
+
self,
|
|
209
|
+
symbols: List[str],
|
|
210
|
+
interval: BinanceKlineInterval,
|
|
211
|
+
):
|
|
212
|
+
if (
|
|
213
|
+
self._account_type.is_isolated_margin_or_margin
|
|
214
|
+
or self._account_type.is_portfolio_margin
|
|
215
|
+
):
|
|
216
|
+
raise ValueError(
|
|
217
|
+
"Not Supported for `Margin Account` or `Portfolio Margin Account`"
|
|
218
|
+
)
|
|
219
|
+
params = [f"{symbol.lower()}@kline_{interval.value}" for symbol in symbols]
|
|
220
|
+
self._unsubscribe(params)
|
|
221
|
+
|
|
222
|
+
async def _resubscribe_for_client(self, client_id: int, subscriptions: List[str]):
|
|
223
|
+
if not subscriptions:
|
|
224
|
+
return
|
|
225
|
+
self._send_payload(subscriptions, client_id=client_id)
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class BinanceWSApiClient(WSClient):
|
|
229
|
+
def __init__(
|
|
230
|
+
self,
|
|
231
|
+
account_type: BinanceAccountType,
|
|
232
|
+
api_key: str,
|
|
233
|
+
secret: str,
|
|
234
|
+
handler: Callable[..., Any],
|
|
235
|
+
task_manager: TaskManager,
|
|
236
|
+
clock: LiveClock,
|
|
237
|
+
enable_rate_limit: bool,
|
|
238
|
+
):
|
|
239
|
+
self._account_type = account_type
|
|
240
|
+
self._api_key = api_key
|
|
241
|
+
self._secret = secret
|
|
242
|
+
self._limiter = BinanceRateLimiter(enable_rate_limit)
|
|
243
|
+
|
|
244
|
+
url = account_type.ws_order_url
|
|
245
|
+
|
|
246
|
+
if not url:
|
|
247
|
+
raise ValueError(f"WebSocket URL not supported for {account_type}")
|
|
248
|
+
|
|
249
|
+
super().__init__(
|
|
250
|
+
url=url,
|
|
251
|
+
handler=handler,
|
|
252
|
+
task_manager=task_manager,
|
|
253
|
+
clock=clock,
|
|
254
|
+
enable_auto_ping=False,
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
def _generate_signature_v2(self, query: str) -> str:
|
|
258
|
+
signature = hmac_signature(self._secret, query)
|
|
259
|
+
return signature
|
|
260
|
+
|
|
261
|
+
def _send_payload(
|
|
262
|
+
self,
|
|
263
|
+
id: str,
|
|
264
|
+
method: str,
|
|
265
|
+
params: Dict[str, Any],
|
|
266
|
+
required_ts: bool = True,
|
|
267
|
+
auth: bool = True,
|
|
268
|
+
):
|
|
269
|
+
if required_ts:
|
|
270
|
+
params["timestamp"] = self._clock.timestamp_ms()
|
|
271
|
+
|
|
272
|
+
if auth:
|
|
273
|
+
params["apiKey"] = self._api_key
|
|
274
|
+
query = urlencode(sorted(params.items()))
|
|
275
|
+
signature = self._generate_signature_v2(query)
|
|
276
|
+
params["signature"] = signature
|
|
277
|
+
|
|
278
|
+
payload = {
|
|
279
|
+
"method": method,
|
|
280
|
+
"id": id,
|
|
281
|
+
"params": params,
|
|
282
|
+
}
|
|
283
|
+
self.send(payload)
|
|
284
|
+
|
|
285
|
+
async def spot_new_order(
|
|
286
|
+
self, oid: str, symbol: str, side: str, type: str, quantity: str, **kwargs: Any
|
|
287
|
+
):
|
|
288
|
+
params = {
|
|
289
|
+
"symbol": symbol,
|
|
290
|
+
"side": side,
|
|
291
|
+
"type": type,
|
|
292
|
+
"quantity": quantity,
|
|
293
|
+
**kwargs,
|
|
294
|
+
}
|
|
295
|
+
await self._limiter.api_order_limit(cost=1)
|
|
296
|
+
self._send_payload(id=f"n{oid}", method="order.place", params=params)
|
|
297
|
+
|
|
298
|
+
async def spot_cancel_order(
|
|
299
|
+
self, oid: str, symbol: str, origClientOrderId: int, **kwargs: Any
|
|
300
|
+
):
|
|
301
|
+
params = {
|
|
302
|
+
"symbol": symbol,
|
|
303
|
+
"origClientOrderId": origClientOrderId,
|
|
304
|
+
**kwargs,
|
|
305
|
+
}
|
|
306
|
+
self._send_payload(id=f"c{oid}", method="order.cancel", params=params)
|
|
307
|
+
|
|
308
|
+
async def usdm_new_order(
|
|
309
|
+
self, oid: str, symbol: str, side: str, type: str, quantity: str, **kwargs: Any
|
|
310
|
+
):
|
|
311
|
+
params = {
|
|
312
|
+
"symbol": symbol,
|
|
313
|
+
"side": side,
|
|
314
|
+
"type": type,
|
|
315
|
+
"quantity": quantity,
|
|
316
|
+
**kwargs,
|
|
317
|
+
}
|
|
318
|
+
await self._limiter.fapi_order_limit(cost=0)
|
|
319
|
+
self._send_payload(id=f"n{oid}", method="order.place", params=params)
|
|
320
|
+
|
|
321
|
+
async def usdm_cancel_order(
|
|
322
|
+
self, oid: str, symbol: str, origClientOrderId: int, **kwargs: Any
|
|
323
|
+
):
|
|
324
|
+
params = {
|
|
325
|
+
"symbol": symbol,
|
|
326
|
+
"origClientOrderId": origClientOrderId,
|
|
327
|
+
**kwargs,
|
|
328
|
+
}
|
|
329
|
+
self._send_payload(id=f"c{oid}", method="order.cancel", params=params)
|
|
330
|
+
|
|
331
|
+
async def coinm_new_order(
|
|
332
|
+
self, oid: str, symbol: str, side: str, type: str, quantity: str, **kwargs: Any
|
|
333
|
+
):
|
|
334
|
+
params = {
|
|
335
|
+
"symbol": symbol,
|
|
336
|
+
"side": side,
|
|
337
|
+
"type": type,
|
|
338
|
+
"quantity": quantity,
|
|
339
|
+
**kwargs,
|
|
340
|
+
}
|
|
341
|
+
await self._limiter.dapi_order_limit(cost=0)
|
|
342
|
+
self._send_payload(id=f"n{oid}", method="order.place", params=params)
|
|
343
|
+
|
|
344
|
+
async def coinm_cancel_order(
|
|
345
|
+
self, oid: str, symbol: str, origClientOrderId: int, **kwargs: Any
|
|
346
|
+
):
|
|
347
|
+
params = {
|
|
348
|
+
"symbol": symbol,
|
|
349
|
+
"origClientOrderId": origClientOrderId,
|
|
350
|
+
**kwargs,
|
|
351
|
+
}
|
|
352
|
+
self._send_payload(id=f"c{oid}", method="order.cancel", params=params)
|
|
353
|
+
|
|
354
|
+
def _subscribe(self, subscriptions: List[tuple[Dict[str, Any], str]]):
|
|
355
|
+
assigned = self._register_subscriptions(subscriptions)
|
|
356
|
+
if not assigned:
|
|
357
|
+
return
|
|
358
|
+
for client_id, client_subs in assigned.items():
|
|
359
|
+
for params, method in client_subs:
|
|
360
|
+
self._log.debug(f"Subscribing to {method} with {params}...")
|
|
361
|
+
if self._is_client_connected(client_id):
|
|
362
|
+
for params, method in client_subs:
|
|
363
|
+
request_id = f"{self._clock.timestamp_ms()}"
|
|
364
|
+
self._send_payload(
|
|
365
|
+
id=request_id,
|
|
366
|
+
method=method,
|
|
367
|
+
params=dict(params),
|
|
368
|
+
auth=True,
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
async def _resubscribe_for_client(
|
|
372
|
+
self, client_id: int, subscriptions: List[tuple[Dict[str, Any], str]]
|
|
373
|
+
):
|
|
374
|
+
if not subscriptions:
|
|
375
|
+
return
|
|
376
|
+
for params, method in subscriptions:
|
|
377
|
+
request_id = f"s{self._clock.timestamp_ms()}"
|
|
378
|
+
self._send_payload(
|
|
379
|
+
id=request_id,
|
|
380
|
+
method=method,
|
|
381
|
+
params=dict(params),
|
|
382
|
+
auth=True,
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
def subscribe_spot_user_data_stream(self):
|
|
386
|
+
if not self._account_type.is_spot:
|
|
387
|
+
raise ValueError("Only Supported for `Spot Account`")
|
|
388
|
+
params: Dict[str, Any] = {}
|
|
389
|
+
self._subscribe([(params, "userDataStream.subscribe.signature")])
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from walrasquant.exchange.bitget.exchange import BitgetExchangeManager
|
|
2
|
+
from walrasquant.exchange.bitget.connector import (
|
|
3
|
+
BitgetPublicConnector,
|
|
4
|
+
BitgetPrivateConnector,
|
|
5
|
+
)
|
|
6
|
+
from walrasquant.exchange.bitget.constants import BitgetAccountType
|
|
7
|
+
from walrasquant.exchange.bitget.ems import BitgetExecutionManagementSystem
|
|
8
|
+
from walrasquant.exchange.bitget.oms import BitgetOrderManagementSystem
|
|
9
|
+
from walrasquant.exchange.bitget.factory import BitgetFactory
|
|
10
|
+
|
|
11
|
+
# Auto-register factory on import
|
|
12
|
+
try:
|
|
13
|
+
from walrasquant.exchange.registry import register_factory
|
|
14
|
+
|
|
15
|
+
register_factory(BitgetFactory())
|
|
16
|
+
except ImportError:
|
|
17
|
+
# Registry not available yet during bootstrap
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"BitgetExchangeManager",
|
|
22
|
+
"BitgetPublicConnector",
|
|
23
|
+
"BitgetPrivateConnector",
|
|
24
|
+
"BitgetAccountType",
|
|
25
|
+
"BitgetExecutionManagementSystem",
|
|
26
|
+
"BitgetOrderManagementSystem",
|
|
27
|
+
"BitgetFactory",
|
|
28
|
+
]
|