hyperquant 1.2__tar.gz → 1.21__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.
- {hyperquant-1.2 → hyperquant-1.21}/PKG-INFO +1 -1
- {hyperquant-1.2 → hyperquant-1.21}/pyproject.toml +1 -1
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/bitmart.py +45 -25
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/models/bitmart.py +58 -3
- {hyperquant-1.2 → hyperquant-1.21}/tests/test_bitmart.py +126 -25
- {hyperquant-1.2 → hyperquant-1.21}/uv.lock +1 -1
- {hyperquant-1.2 → hyperquant-1.21}/.gitignore +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/.python-version +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/README.md +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/apis.json +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/data/alpine_smoke.log +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/data/logs/notikit.log +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/data/logs/test_order_sync.log +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/data/records_swap.csv +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/data/records_swapc.csv +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/doc/bitmart.md +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/doc/coinup.md +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/doc/lbank.md +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/pub.sh +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/requirements-dev.lock +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/requirements.lock +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/__init__.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/auth.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/bitget.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/coinup.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/coinw.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/edgex.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/hyperliquid.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/lbank.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/lib/edgex_sign.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/lib/hpstore.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/lib/hyper_types.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/lib/util.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/lighter.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/models/bitget.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/models/coinup.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/models/coinw.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/models/edgex.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/models/hyperliquid.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/models/lbank.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/models/lighter.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/models/ourbit.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/ourbit.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/broker/ws.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/core.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/datavison/_util.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/datavison/binance.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/datavison/coinglass.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/datavison/okx.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/db.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/draw.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/logkit.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/src/hyperquant/notikit.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/test.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/tests/test_bitget.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/tests/test_coinup.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/tests/test_coinw.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/tests/test_draw.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/tests/test_edgex.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/tests/test_lbank.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/tests/test_lighter.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/tests/test_ourbit.py +0 -0
- {hyperquant-1.2 → hyperquant-1.21}/tests/tmp.py +0 -0
|
@@ -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
|
|
@@ -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:
|
|
@@ -10,9 +10,8 @@ from hyperquant.logkit import get_logger
|
|
|
10
10
|
from hyperquant.broker.bitmart import Bitmart
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
|
|
14
13
|
async def test_update():
|
|
15
|
-
async with pybotters.Client(apis=
|
|
14
|
+
async with pybotters.Client(apis="./apis.json") as client:
|
|
16
15
|
async with Bitmart(client=client) as broker:
|
|
17
16
|
# print(broker.store.detail.find()[0])
|
|
18
17
|
# await broker.update('balances')
|
|
@@ -23,14 +22,14 @@ async def test_update():
|
|
|
23
22
|
# await broker.update('history_orders')
|
|
24
23
|
# print(broker.store.orders.find())
|
|
25
24
|
# print(broker.store.orders.get({'order_id':3000237069605967}))
|
|
26
|
-
await broker.update(
|
|
25
|
+
await broker.update("positions")
|
|
27
26
|
print(broker.store.positions.find())
|
|
28
27
|
|
|
29
28
|
# print(broker.store.detail.find({'name':'PUMPUSDT'}))
|
|
30
29
|
|
|
31
30
|
|
|
32
31
|
async def test_place():
|
|
33
|
-
async with pybotters.Client(apis=
|
|
32
|
+
async with pybotters.Client(apis="./apis.json") as client:
|
|
34
33
|
async with Bitmart(client=client) as broker:
|
|
35
34
|
# [2025-10-31 17:34:15] 🔵 准备建仓: VIRTUAL_USDT entry=short qty=20.498804 lag_px=1.4635 lead=binance
|
|
36
35
|
# [2025-11-01 01:33:22] 🔵 准备建仓: PUMP_USDT entry=long qty=18872.375560 lag_px=0.004239 lead=binance
|
|
@@ -38,17 +37,19 @@ async def test_place():
|
|
|
38
37
|
for i in range(2):
|
|
39
38
|
start = time.time()
|
|
40
39
|
oid = await broker.place_order(
|
|
41
|
-
symbol=
|
|
42
|
-
side=
|
|
43
|
-
category=
|
|
40
|
+
symbol="PUMPUSDT",
|
|
41
|
+
side="sell",
|
|
42
|
+
category="limit",
|
|
44
43
|
price=0.004239,
|
|
45
44
|
qty=18872.375560,
|
|
46
|
-
mode=
|
|
47
|
-
leverage=40
|
|
45
|
+
mode="ioc",
|
|
46
|
+
leverage=40,
|
|
48
47
|
# qty_contract=1
|
|
49
48
|
)
|
|
50
49
|
|
|
51
|
-
print(
|
|
50
|
+
print(
|
|
51
|
+
f"Placed order ID: {oid}, 下单毫秒数: {(time.time() - start)*1000:.2f} ms"
|
|
52
|
+
)
|
|
52
53
|
|
|
53
54
|
# resp = await broker.cancel_order(
|
|
54
55
|
# symbol='VIRTUALUSDT',
|
|
@@ -57,6 +58,7 @@ async def test_place():
|
|
|
57
58
|
|
|
58
59
|
# print(f"Cancel response: {resp}")
|
|
59
60
|
|
|
61
|
+
|
|
60
62
|
@dataclass
|
|
61
63
|
class OrderSyncResult:
|
|
62
64
|
position: dict[str, Any]
|
|
@@ -90,7 +92,7 @@ async def order_sync_polling(
|
|
|
90
92
|
if logger:
|
|
91
93
|
logger.warning(f"Order placement failed: {e}")
|
|
92
94
|
return OrderSyncResult(position={}, order={})
|
|
93
|
-
|
|
95
|
+
|
|
94
96
|
async def sync() -> OrderSyncResult:
|
|
95
97
|
await broker.update("history_orders")
|
|
96
98
|
await broker.update("positions")
|
|
@@ -104,7 +106,6 @@ async def order_sync_polling(
|
|
|
104
106
|
position = positions[0]
|
|
105
107
|
return OrderSyncResult(position=position or {}, order=order or {})
|
|
106
108
|
|
|
107
|
-
|
|
108
109
|
for attempt in range(cancel_retry):
|
|
109
110
|
await asyncio.sleep(1)
|
|
110
111
|
await broker.update("history_orders")
|
|
@@ -124,16 +125,17 @@ async def order_sync_polling(
|
|
|
124
125
|
|
|
125
126
|
return OrderSyncResult(position={}, order={})
|
|
126
127
|
|
|
128
|
+
|
|
127
129
|
async def test_sub_book():
|
|
128
130
|
async with pybotters.Client() as client:
|
|
129
131
|
async with Bitmart(client=client) as broker:
|
|
130
132
|
broker.store.book.limit = 1
|
|
131
|
-
await broker.sub_orderbook(["
|
|
133
|
+
await broker.sub_orderbook(["ASRUSDT"])
|
|
132
134
|
while True:
|
|
133
135
|
# await broker.store.book.wait()
|
|
134
136
|
# print(broker.store.book.find())
|
|
135
|
-
asks = broker.store.book.find({"S": "a",
|
|
136
|
-
bids = broker.store.book.find({"S": "b",
|
|
137
|
+
asks = broker.store.book.find({"S": "a", "s": "ASRUSDT"})
|
|
138
|
+
bids = broker.store.book.find({"S": "b", "s": "ASRUSDT"})
|
|
137
139
|
# 订单薄format化输出
|
|
138
140
|
print("Asks:")
|
|
139
141
|
for ask in asks:
|
|
@@ -144,20 +146,21 @@ async def test_sub_book():
|
|
|
144
146
|
print("-" * 30)
|
|
145
147
|
await asyncio.sleep(1)
|
|
146
148
|
|
|
147
|
-
|
|
148
149
|
# with broker.store.book.watch() as stream:
|
|
149
150
|
# async for change in stream:
|
|
150
151
|
# print(change)
|
|
151
152
|
|
|
153
|
+
|
|
152
154
|
async def test_auto_refresh():
|
|
153
|
-
async with pybotters.Client(apis=
|
|
154
|
-
async with Bitmart(client=client, apis=
|
|
155
|
+
async with pybotters.Client(apis="./apis.json") as client:
|
|
156
|
+
async with Bitmart(client=client, apis="./apis.json") as broker:
|
|
155
157
|
await broker.auto_refresh(0, test=True)
|
|
156
158
|
await asyncio.sleep(2)
|
|
157
159
|
|
|
160
|
+
|
|
158
161
|
async def test_sync_place():
|
|
159
162
|
logger = get_logger("test_sync_place")
|
|
160
|
-
async with pybotters.Client(apis=
|
|
163
|
+
async with pybotters.Client(apis="./apis.json") as client:
|
|
161
164
|
async with Bitmart(client=client) as broker:
|
|
162
165
|
# place_task = broker.place_order(
|
|
163
166
|
# symbol='VIRTUALUSDT',
|
|
@@ -170,10 +173,10 @@ async def test_sync_place():
|
|
|
170
173
|
|
|
171
174
|
place_task = broker.place_order( # type: ignore[attr-defined]
|
|
172
175
|
symbol="VELODROMEUSDT",
|
|
173
|
-
side=
|
|
176
|
+
side="sell",
|
|
174
177
|
qty_contract=int(round(1.000000)),
|
|
175
178
|
price=0.040645,
|
|
176
|
-
category=
|
|
179
|
+
category="market",
|
|
177
180
|
)
|
|
178
181
|
result = await order_sync_polling(
|
|
179
182
|
broker,
|
|
@@ -185,13 +188,111 @@ async def test_sync_place():
|
|
|
185
188
|
)
|
|
186
189
|
logger.info(f"Order Sync Result: {result}")
|
|
187
190
|
|
|
191
|
+
|
|
188
192
|
async def test_set_leverage():
|
|
189
|
-
async with pybotters.Client(apis=
|
|
193
|
+
async with pybotters.Client(apis="./apis.json") as client:
|
|
190
194
|
async with Bitmart(client=client) as broker:
|
|
191
|
-
await broker.bind_leverage(symbol=
|
|
195
|
+
await broker.bind_leverage(symbol="BTCUSDT", leverage=10)
|
|
192
196
|
# get current leverage
|
|
193
|
-
lev_info = await broker.get_leverage(symbol=
|
|
197
|
+
lev_info = await broker.get_leverage(symbol="BTCUSDT")
|
|
194
198
|
print(lev_info)
|
|
195
199
|
|
|
200
|
+
|
|
201
|
+
async def test_close_all():
|
|
202
|
+
async with pybotters.Client(apis="./apis.json") as client:
|
|
203
|
+
async with Bitmart(client=client) as broker:
|
|
204
|
+
await broker.place_order(
|
|
205
|
+
symbol="PORT3USDT",
|
|
206
|
+
side="buy",
|
|
207
|
+
qty_contract=5,
|
|
208
|
+
category="market",
|
|
209
|
+
price=0,
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
async def test_sub_book_compare():
|
|
214
|
+
async with pybotters.Client() as client:
|
|
215
|
+
async with Bitmart(client=client) as broker:
|
|
216
|
+
mst_t = None
|
|
217
|
+
a_counter = 0
|
|
218
|
+
a_last_time = None
|
|
219
|
+
a_total_interval = 0.0
|
|
220
|
+
|
|
221
|
+
def book_handler(msg: dict, ws):
|
|
222
|
+
nonlocal mst_t
|
|
223
|
+
nonlocal a_counter
|
|
224
|
+
nonlocal a_last_time
|
|
225
|
+
nonlocal a_total_interval
|
|
226
|
+
a_counter += 1
|
|
227
|
+
now = time.time() * 1000 # ms
|
|
228
|
+
if a_last_time is not None:
|
|
229
|
+
a_total_interval += (now - a_last_time)
|
|
230
|
+
a_last_time = now
|
|
231
|
+
mst_t = msg.get("data", {}).get("ms_t", None)
|
|
232
|
+
|
|
233
|
+
b_counter = 0
|
|
234
|
+
b_last_time = None
|
|
235
|
+
b_total_interval = 0.0
|
|
236
|
+
|
|
237
|
+
def book_handler_2(msg: dict, ws):
|
|
238
|
+
nonlocal mst_t
|
|
239
|
+
nonlocal b_counter
|
|
240
|
+
nonlocal b_last_time
|
|
241
|
+
nonlocal b_total_interval
|
|
242
|
+
way = msg.get("data", {}).get("way", None)
|
|
243
|
+
if way == 1:
|
|
244
|
+
b_counter += 1
|
|
245
|
+
now = time.time() * 1000 # ms
|
|
246
|
+
if b_last_time is not None:
|
|
247
|
+
b_total_interval += (now - b_last_time)
|
|
248
|
+
b_last_time = now
|
|
249
|
+
mst_t = msg.get("data", {}).get("ms_t", None)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
await client.ws_connect(
|
|
254
|
+
url="wss://openapi-ws-v2.bitmart.com/api?protocol=1.1",
|
|
255
|
+
send_json=[
|
|
256
|
+
{"action": "subscribe", "args": ["futures/depth5:BTCUSDT@100ms"]}
|
|
257
|
+
],
|
|
258
|
+
hdlr_json=book_handler,
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
await client.ws_connect(
|
|
263
|
+
url="wss://contract-ws-v2.bitmart.com/v1/ifcontract/realTime",
|
|
264
|
+
send_json=[
|
|
265
|
+
{
|
|
266
|
+
"action": "subscribe",
|
|
267
|
+
"args": [
|
|
268
|
+
"Depth:1",
|
|
269
|
+
],
|
|
270
|
+
}
|
|
271
|
+
],
|
|
272
|
+
hdlr_json=book_handler_2,
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
await asyncio.sleep(10)
|
|
276
|
+
print(f"Handler A received {a_counter} messages.")
|
|
277
|
+
if a_counter > 1:
|
|
278
|
+
print(f"Handler A average interval: {a_total_interval / (a_counter - 1):.2f} ms")
|
|
279
|
+
else:
|
|
280
|
+
print("Handler A average interval: N/A")
|
|
281
|
+
|
|
282
|
+
print(f"Handler B received {b_counter} messages.")
|
|
283
|
+
if b_counter > 1:
|
|
284
|
+
print(f"Handler B average interval: {b_total_interval / (b_counter - 1):.2f} ms")
|
|
285
|
+
else:
|
|
286
|
+
print("Handler B average interval: N/A")
|
|
287
|
+
|
|
288
|
+
async def test_sub_book_api():
|
|
289
|
+
async with pybotters.Client() as client:
|
|
290
|
+
async with Bitmart(client=client) as broker:
|
|
291
|
+
await broker.sub_orderbook(['TRXUSDT', 'DOTUSDT'], depth_limit=1, use_api_ws=True)
|
|
292
|
+
await broker.store.book.wait()
|
|
293
|
+
while True:
|
|
294
|
+
await broker.store.book.wait()
|
|
295
|
+
print(broker.store.book.find())
|
|
296
|
+
|
|
196
297
|
if __name__ == "__main__":
|
|
197
|
-
asyncio.run(
|
|
298
|
+
asyncio.run(test_sub_book_api())
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|