hyperquant 1.2__py3-none-any.whl → 1.21__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.
hyperquant/broker/bitmart.py
CHANGED
|
@@ -30,6 +30,7 @@ class Bitmart:
|
|
|
30
30
|
self.private_api = "https://derivatives.bitmart.com"
|
|
31
31
|
self.forward_api = f'{self.private_api}/gw-api/contract-tiger/forward'
|
|
32
32
|
self.ws_url = ws_url or "wss://contract-ws-v2.bitmart.com/v1/ifcontract/realTime"
|
|
33
|
+
self.api_ws_url = "wss://openapi-ws-v2.bitmart.com/api?protocol=1.1"
|
|
33
34
|
|
|
34
35
|
self.account_index = account_index
|
|
35
36
|
self.apis = apis
|
|
@@ -281,6 +282,7 @@ class Bitmart:
|
|
|
281
282
|
*,
|
|
282
283
|
depth: str = "Depth",
|
|
283
284
|
depth_limit: int | None = None,
|
|
285
|
+
use_api_ws: bool = True,
|
|
284
286
|
) -> pybotters.ws.WebSocketApp:
|
|
285
287
|
"""Subscribe order book channel(s)."""
|
|
286
288
|
|
|
@@ -289,37 +291,55 @@ class Bitmart:
|
|
|
289
291
|
|
|
290
292
|
if not symbols:
|
|
291
293
|
raise ValueError("symbols must not be empty")
|
|
292
|
-
|
|
293
|
-
missing = [sym for sym in symbols if self.get_contract_id(sym) is None]
|
|
294
|
-
if missing:
|
|
295
|
-
await self.update("detail")
|
|
296
|
-
still_missing = [sym for sym in missing if self.get_contract_id(sym) is None]
|
|
297
|
-
if still_missing:
|
|
298
|
-
raise ValueError(f"Unknown symbols: {', '.join(still_missing)}")
|
|
299
|
-
|
|
300
294
|
if depth_limit is not None:
|
|
301
295
|
self.store.book.limit = depth_limit
|
|
296
|
+
if not use_api_ws:
|
|
297
|
+
missing = [sym for sym in symbols if self.get_contract_id(sym) is None]
|
|
298
|
+
if missing:
|
|
299
|
+
await self.update("detail")
|
|
300
|
+
still_missing = [sym for sym in missing if self.get_contract_id(sym) is None]
|
|
301
|
+
if still_missing:
|
|
302
|
+
raise ValueError(f"Unknown symbols: {', '.join(still_missing)}")
|
|
302
303
|
|
|
303
|
-
channels: list[str] = []
|
|
304
|
-
for symbol in symbols:
|
|
305
|
-
contract_id = self.get_contract_id(symbol)
|
|
306
|
-
if contract_id is None:
|
|
307
|
-
continue
|
|
308
|
-
self.store.book.id_to_symbol[str(contract_id)] = symbol
|
|
309
|
-
channels.append(f"{depth}:{contract_id}")
|
|
310
304
|
|
|
311
|
-
if not channels:
|
|
312
|
-
raise ValueError("No channels resolved for subscription")
|
|
313
305
|
|
|
314
|
-
|
|
315
|
-
|
|
306
|
+
channels: list[str] = []
|
|
307
|
+
for symbol in symbols:
|
|
308
|
+
contract_id = self.get_contract_id(symbol)
|
|
309
|
+
if contract_id is None:
|
|
310
|
+
continue
|
|
311
|
+
self.store.book.id_to_symbol[str(contract_id)] = symbol
|
|
312
|
+
channels.append(f"{depth}:{contract_id}")
|
|
313
|
+
|
|
314
|
+
if not channels:
|
|
315
|
+
raise ValueError("No channels resolved for subscription")
|
|
316
|
+
|
|
317
|
+
payload = {"action": "subscribe", "args": channels}
|
|
318
|
+
# print(payload)
|
|
319
|
+
|
|
320
|
+
ws_app = self.client.ws_connect(
|
|
321
|
+
self.api_ws_url,
|
|
322
|
+
send_json=payload,
|
|
323
|
+
hdlr_json=self.store.onmessage,
|
|
324
|
+
)
|
|
325
|
+
else:
|
|
326
|
+
channels: list[str] = []
|
|
327
|
+
for symbol in symbols:
|
|
328
|
+
channels.append(f"futures/depthAll5:{symbol}@100ms")
|
|
329
|
+
|
|
330
|
+
if not channels:
|
|
331
|
+
raise ValueError("No channels resolved for subscription")
|
|
332
|
+
|
|
333
|
+
payload = {"action": "subscribe", "args": channels}
|
|
334
|
+
# print(payload)
|
|
335
|
+
|
|
336
|
+
ws_app = self.client.ws_connect(
|
|
337
|
+
self.api_ws_url,
|
|
338
|
+
send_json=payload,
|
|
339
|
+
hdlr_json=self.store.onmessage,
|
|
340
|
+
autoping=False,
|
|
341
|
+
)
|
|
316
342
|
|
|
317
|
-
ws_app = self.client.ws_connect(
|
|
318
|
-
self.ws_url,
|
|
319
|
-
send_json=payload,
|
|
320
|
-
hdlr_json=self.store.onmessage,
|
|
321
|
-
autoping=False,
|
|
322
|
-
)
|
|
323
343
|
await ws_app._event.wait()
|
|
324
344
|
return ws_app
|
|
325
345
|
|
|
@@ -62,6 +62,7 @@ class Book(DataStore):
|
|
|
62
62
|
def _on_message(self, msg: dict[str, Any]) -> None:
|
|
63
63
|
data = msg.get("data")
|
|
64
64
|
group = msg.get("group")
|
|
65
|
+
ms_t = msg.get("ms_t")
|
|
65
66
|
if not isinstance(data, dict) or not isinstance(group, str):
|
|
66
67
|
return
|
|
67
68
|
|
|
@@ -94,7 +95,57 @@ class Book(DataStore):
|
|
|
94
95
|
for entry in depths
|
|
95
96
|
])
|
|
96
97
|
|
|
97
|
-
self._last_update =
|
|
98
|
+
self._last_update = ms_t
|
|
99
|
+
|
|
100
|
+
def _on_message_api(self, msg: dict[str, Any]) -> None:
|
|
101
|
+
# {
|
|
102
|
+
# "data": {
|
|
103
|
+
# "symbol": "BTCUSDT",
|
|
104
|
+
# "asks": [
|
|
105
|
+
# {
|
|
106
|
+
# "price": "70294.4",
|
|
107
|
+
# "vol": "455"
|
|
108
|
+
# }
|
|
109
|
+
# ],
|
|
110
|
+
# "bids": [
|
|
111
|
+
# {
|
|
112
|
+
# "price": "70293.9",
|
|
113
|
+
# "vol": "1856"
|
|
114
|
+
# }
|
|
115
|
+
# ],
|
|
116
|
+
# "ms_t": 1730399750402
|
|
117
|
+
# },
|
|
118
|
+
# "group": "futures/depthAll20:BTCUSDT@200ms"
|
|
119
|
+
# }
|
|
120
|
+
data = msg.get("data")
|
|
121
|
+
if not isinstance(data, dict):
|
|
122
|
+
return
|
|
123
|
+
symbol = data.get("symbol")
|
|
124
|
+
asks = data.get("asks") or []
|
|
125
|
+
bids = data.get("bids") or []
|
|
126
|
+
if self.limit:
|
|
127
|
+
asks = asks[: self.limit]
|
|
128
|
+
bids = bids[: self.limit]
|
|
129
|
+
|
|
130
|
+
self._find_and_delete({'s': symbol})
|
|
131
|
+
self._update([
|
|
132
|
+
self._make_entry(
|
|
133
|
+
symbol,
|
|
134
|
+
"a",
|
|
135
|
+
entry.get("price", '0'),
|
|
136
|
+
entry.get("vol", '0'),
|
|
137
|
+
)
|
|
138
|
+
for entry in asks
|
|
139
|
+
])
|
|
140
|
+
self._update([
|
|
141
|
+
self._make_entry(
|
|
142
|
+
symbol,
|
|
143
|
+
"b",
|
|
144
|
+
entry.get("price", '0'),
|
|
145
|
+
entry.get("vol", '0'),
|
|
146
|
+
)
|
|
147
|
+
for entry in bids
|
|
148
|
+
])
|
|
98
149
|
|
|
99
150
|
def sorted(self, query: Item | None = None, limit: int | None = None) -> dict[str, list[Item]]:
|
|
100
151
|
return self._sorted(
|
|
@@ -278,8 +329,12 @@ class BitmartDataStore(DataStoreCollection):
|
|
|
278
329
|
def onmessage(self, msg: Item, ws: ClientWebSocketResponse | None = None) -> None:
|
|
279
330
|
if isinstance(msg, dict):
|
|
280
331
|
group = msg.get("group")
|
|
281
|
-
|
|
282
|
-
|
|
332
|
+
|
|
333
|
+
if isinstance(group, str):
|
|
334
|
+
if group.startswith("futures/depth"):
|
|
335
|
+
self.book._on_message_api(msg)
|
|
336
|
+
if group.startswith("Depth"):
|
|
337
|
+
self.book._on_message(msg)
|
|
283
338
|
|
|
284
339
|
@property
|
|
285
340
|
def book(self) -> Book:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hyperquant
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.21
|
|
4
4
|
Summary: A minimal yet hyper-efficient backtesting framework for quantitative trading
|
|
5
5
|
Project-URL: Homepage, https://github.com/yourusername/hyperquant
|
|
6
6
|
Project-URL: Issues, https://github.com/yourusername/hyperquant/issues
|
|
@@ -6,7 +6,7 @@ hyperquant/logkit.py,sha256=nUo7nx5eONvK39GOhWwS41zNRL756P2J7-5xGzwXnTY,8462
|
|
|
6
6
|
hyperquant/notikit.py,sha256=x5yAZ_tAvLQRXcRbcg-VabCaN45LUhvlTZnUqkIqfAA,3596
|
|
7
7
|
hyperquant/broker/auth.py,sha256=C8B5-x8Qcaeafm4ZwPCVFR7GRURmHC3CE4_vdg00Qgw,12139
|
|
8
8
|
hyperquant/broker/bitget.py,sha256=X_S0LKZ7FZAEb6oEMr1vdGP1fondzK74BhmNTpRDSEA,9488
|
|
9
|
-
hyperquant/broker/bitmart.py,sha256=
|
|
9
|
+
hyperquant/broker/bitmart.py,sha256=2Yd_Jzn0XYzl3rYN1rmNuwy7Wy74T3bBQ-ue7RvIbMU,22206
|
|
10
10
|
hyperquant/broker/coinup.py,sha256=eOr8BTRXiTb5tCU2FDmvBdXXgqiwVmCbP5pdeA1ORJ8,20390
|
|
11
11
|
hyperquant/broker/coinw.py,sha256=SnJU0vASh77rfcpMGWaIfTblQSjQk3vjlW_4juYdbcs,17214
|
|
12
12
|
hyperquant/broker/edgex.py,sha256=TqUO2KRPLN_UaxvtLL6HnA9dAQXC1sGxOfqTHd6W5k8,18378
|
|
@@ -20,7 +20,7 @@ hyperquant/broker/lib/hpstore.py,sha256=LnLK2zmnwVvhEbLzYI-jz_SfYpO1Dv2u2cJaRAb8
|
|
|
20
20
|
hyperquant/broker/lib/hyper_types.py,sha256=HqjjzjUekldjEeVn6hxiWA8nevAViC2xHADOzDz9qyw,991
|
|
21
21
|
hyperquant/broker/lib/util.py,sha256=iMU1qF0CHj5zzlIMEQGwjz-qtEVosEe7slXOCuB7Rcw,566
|
|
22
22
|
hyperquant/broker/models/bitget.py,sha256=0RwDY75KrJb-c-oYoMxbqxWfsILe-n_Npojz4UFUq7c,11389
|
|
23
|
-
hyperquant/broker/models/bitmart.py,sha256=
|
|
23
|
+
hyperquant/broker/models/bitmart.py,sha256=hPxSFLmsJif9wm4nTln5G_zCbsoRnM1BF9fnfciZIHo,22061
|
|
24
24
|
hyperquant/broker/models/coinup.py,sha256=X_ngB2_sgTOdfAZqTyeWvCN03j-0_inZ6ugZKW6hR7k,11173
|
|
25
25
|
hyperquant/broker/models/coinw.py,sha256=LvLMVP7i-qkkTK1ubw8eBkMK2RQmFoKPxdKqmC4IToY,22157
|
|
26
26
|
hyperquant/broker/models/edgex.py,sha256=vPAkceal44cjTYKQ_0BoNAskOpmkno_Yo1KxgMLPc6Y,33954
|
|
@@ -32,6 +32,6 @@ hyperquant/datavison/_util.py,sha256=92qk4vO856RqycO0YqEIHJlEg-W9XKapDVqAMxe6rbw
|
|
|
32
32
|
hyperquant/datavison/binance.py,sha256=3yNKTqvt_vUQcxzeX4ocMsI5k6Q6gLZrvgXxAEad6Kc,5001
|
|
33
33
|
hyperquant/datavison/coinglass.py,sha256=PEjdjISP9QUKD_xzXNzhJ9WFDTlkBrRQlVL-5pxD5mo,10482
|
|
34
34
|
hyperquant/datavison/okx.py,sha256=yg8WrdQ7wgWHNAInIgsWPM47N3Wkfr253169IPAycAY,6898
|
|
35
|
-
hyperquant-1.
|
|
36
|
-
hyperquant-1.
|
|
37
|
-
hyperquant-1.
|
|
35
|
+
hyperquant-1.21.dist-info/METADATA,sha256=1ZJFW9uGSQFzXQTBy74LLbaay4lUmc_pTOzSOugj_nU,4409
|
|
36
|
+
hyperquant-1.21.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
37
|
+
hyperquant-1.21.dist-info/RECORD,,
|
|
File without changes
|