hyperquant 0.94__py3-none-any.whl → 0.96__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.
Potentially problematic release.
This version of hyperquant might be problematic. Click here for more details.
hyperquant/broker/bitmart.py
CHANGED
|
@@ -9,7 +9,6 @@ from typing import Any, Literal, Sequence
|
|
|
9
9
|
import pybotters
|
|
10
10
|
|
|
11
11
|
from .models.bitmart import BitmartDataStore
|
|
12
|
-
from .lib.util import fmt_value
|
|
13
12
|
|
|
14
13
|
class Bitmart:
|
|
15
14
|
"""Bitmart 合约交易(REST + WebSocket)。"""
|
|
@@ -145,6 +144,7 @@ class Bitmart:
|
|
|
145
144
|
"account",
|
|
146
145
|
"all",
|
|
147
146
|
"history_orders",
|
|
147
|
+
"ticker",
|
|
148
148
|
] = "all",
|
|
149
149
|
*,
|
|
150
150
|
orders_params: dict[str, Any] | None = None,
|
|
@@ -159,6 +159,7 @@ class Bitmart:
|
|
|
159
159
|
include_positions = update_type in {"positions", "all"}
|
|
160
160
|
include_balances = update_type in {"balances", "account", "all"}
|
|
161
161
|
include_history_orders = update_type in {"history_orders"}
|
|
162
|
+
include_ticker = update_type in {"ticker", "all"}
|
|
162
163
|
|
|
163
164
|
if include_detail:
|
|
164
165
|
tasks["detail"] = self.client.get(f"{self.public_api}/v1/ifcontract/contracts_all")
|
|
@@ -201,6 +202,11 @@ class Bitmart:
|
|
|
201
202
|
params=d_params,
|
|
202
203
|
)
|
|
203
204
|
|
|
205
|
+
if include_ticker:
|
|
206
|
+
tasks["ticker"] = self.client.get(
|
|
207
|
+
f"{self.public_api}/v1/ifcontract/tickers"
|
|
208
|
+
)
|
|
209
|
+
|
|
204
210
|
if not tasks:
|
|
205
211
|
raise ValueError(f"Unsupported update_type: {update_type}")
|
|
206
212
|
|
|
@@ -248,6 +254,12 @@ class Bitmart:
|
|
|
248
254
|
raise ValueError(f"Bitmart balances API error: {resp}")
|
|
249
255
|
self.store.balances._onresponse(resp)
|
|
250
256
|
|
|
257
|
+
if "ticker" in results:
|
|
258
|
+
resp = results["ticker"]
|
|
259
|
+
if resp.get("success") is False or resp.get("errno") not in (None, "OK"):
|
|
260
|
+
raise ValueError(f"Bitmart ticker API error: {resp}")
|
|
261
|
+
self.store.ticker._onresponse(resp)
|
|
262
|
+
|
|
251
263
|
if "history_orders" in results:
|
|
252
264
|
resp = results["history_orders"]
|
|
253
265
|
if resp.get("success") is False or resp.get("errno") not in (None, "OK"):
|
|
@@ -313,7 +325,7 @@ class Bitmart:
|
|
|
313
325
|
*,
|
|
314
326
|
category: Literal[1,2,"limit","market"] = "limit",
|
|
315
327
|
price: float,
|
|
316
|
-
|
|
328
|
+
volume: float,
|
|
317
329
|
way: Literal[1, 2, 3, 4, "open_long", "close_short", "close_long", "open_short", "buy", "sell"] = "open_long",
|
|
318
330
|
mode: Literal[1, 2, 3, 4, "gtc", "ioc", "fok", "maker_only", "maker-only", "post_only"] = "gtc",
|
|
319
331
|
open_type: Literal[1, 2, "cross", "isolated"] = "isolated",
|
|
@@ -347,20 +359,28 @@ class Bitmart:
|
|
|
347
359
|
if contract_size_val <= 0:
|
|
348
360
|
raise ValueError(f"Invalid contract_size for {symbol}: {contract_size_str}")
|
|
349
361
|
|
|
350
|
-
contracts_float = float(
|
|
362
|
+
contracts_float = float(volume) / contract_size_val
|
|
351
363
|
contracts_int = int(round(contracts_float))
|
|
352
364
|
if contracts_int <= 0:
|
|
353
365
|
raise ValueError(
|
|
354
|
-
f"
|
|
366
|
+
f"Volume too small for contract size ({contract_size_val}): volume={volume}"
|
|
355
367
|
)
|
|
356
368
|
if abs(contracts_float - contracts_int) > 1e-8:
|
|
357
369
|
raise ValueError(
|
|
358
|
-
f"
|
|
359
|
-
f"Received
|
|
370
|
+
f"Volume must be a multiple of contract_size ({contract_size_val}). "
|
|
371
|
+
f"Received volume={volume} -> {contracts_float} contracts."
|
|
360
372
|
)
|
|
361
373
|
|
|
362
374
|
price_unit = detail.get("price_unit") or 1
|
|
363
|
-
|
|
375
|
+
try:
|
|
376
|
+
price_unit_val = float(price_unit)
|
|
377
|
+
except (TypeError, ValueError):
|
|
378
|
+
price_unit_val = 1.0
|
|
379
|
+
if price_unit_val <= 0:
|
|
380
|
+
price_unit_val = 1.0
|
|
381
|
+
|
|
382
|
+
price_value = float(price)
|
|
383
|
+
adjusted_price = int(price_value / price_unit_val) * price_unit_val
|
|
364
384
|
|
|
365
385
|
category = self._normalize_enum(
|
|
366
386
|
category,
|
|
@@ -371,6 +391,10 @@ class Bitmart:
|
|
|
371
391
|
"category",
|
|
372
392
|
)
|
|
373
393
|
|
|
394
|
+
if category == 2: # market
|
|
395
|
+
adjusted_price = 0.0
|
|
396
|
+
price_fmt = f"{adjusted_price:.15f}".rstrip("0").rstrip(".") or "0"
|
|
397
|
+
|
|
374
398
|
way_value = self._normalize_enum(
|
|
375
399
|
way,
|
|
376
400
|
{
|
|
@@ -408,7 +432,7 @@ class Bitmart:
|
|
|
408
432
|
"place_all_order": False,
|
|
409
433
|
"contract_id": contract_id_int,
|
|
410
434
|
"category": category,
|
|
411
|
-
"price":
|
|
435
|
+
"price": price_fmt,
|
|
412
436
|
"vol": contracts_int,
|
|
413
437
|
"way": way_value,
|
|
414
438
|
"mode": mode_value,
|
|
@@ -19,6 +19,25 @@ def _maybe_to_dict(payload: Any) -> Any:
|
|
|
19
19
|
return payload.model_dump()
|
|
20
20
|
return payload
|
|
21
21
|
|
|
22
|
+
class Ticker(DataStore):
|
|
23
|
+
"""Bitmart 合约行情数据。"""
|
|
24
|
+
|
|
25
|
+
_KEYS = ["contract_id"]
|
|
26
|
+
|
|
27
|
+
def _onresponse(self, data: Any) -> None:
|
|
28
|
+
payload = _maybe_to_dict(data) or {}
|
|
29
|
+
tickers = payload.get("data", {}).get("tickers") or []
|
|
30
|
+
items: list[dict[str, Any]] = []
|
|
31
|
+
for entry in tickers:
|
|
32
|
+
if not isinstance(entry, dict):
|
|
33
|
+
continue
|
|
34
|
+
contract_id = entry.get("contract_id")
|
|
35
|
+
if contract_id is None:
|
|
36
|
+
continue
|
|
37
|
+
items.append(entry)
|
|
38
|
+
self._clear()
|
|
39
|
+
if items:
|
|
40
|
+
self._insert(items)
|
|
22
41
|
|
|
23
42
|
class Book(DataStore):
|
|
24
43
|
"""Bitmart 合约深度数据。"""
|
|
@@ -134,6 +153,30 @@ class Detail(DataStore):
|
|
|
134
153
|
self._insert(records)
|
|
135
154
|
|
|
136
155
|
|
|
156
|
+
class Ticker(DataStore):
|
|
157
|
+
"""24h 数据信息。"""
|
|
158
|
+
|
|
159
|
+
_KEYS = ["contract_id"]
|
|
160
|
+
|
|
161
|
+
def _onresponse(self, data: Any) -> None:
|
|
162
|
+
payload = _maybe_to_dict(data) or {}
|
|
163
|
+
tickers = payload.get("data", {}).get("tickers") or []
|
|
164
|
+
items: list[dict[str, Any]] = []
|
|
165
|
+
for entry in tickers:
|
|
166
|
+
if not isinstance(entry, dict):
|
|
167
|
+
continue
|
|
168
|
+
contract_id = entry.get("contract_id")
|
|
169
|
+
if contract_id is None:
|
|
170
|
+
continue
|
|
171
|
+
record = dict(entry)
|
|
172
|
+
record["contract_id"] = contract_id
|
|
173
|
+
items.append(record)
|
|
174
|
+
|
|
175
|
+
self._clear()
|
|
176
|
+
if items:
|
|
177
|
+
self._insert(items)
|
|
178
|
+
|
|
179
|
+
|
|
137
180
|
class Orders(DataStore):
|
|
138
181
|
"""订单列表。"""
|
|
139
182
|
|
|
@@ -230,6 +273,7 @@ class BitmartDataStore(DataStoreCollection):
|
|
|
230
273
|
self._create("orders", datastore_class=Orders)
|
|
231
274
|
self._create("positions", datastore_class=Positions)
|
|
232
275
|
self._create("balances", datastore_class=Balances)
|
|
276
|
+
self._create("ticker", datastore_class=Ticker)
|
|
233
277
|
|
|
234
278
|
def onmessage(self, msg: Item, ws: ClientWebSocketResponse | None = None) -> None:
|
|
235
279
|
if isinstance(msg, dict):
|
|
@@ -334,6 +378,24 @@ class BitmartDataStore(DataStoreCollection):
|
|
|
334
378
|
"""
|
|
335
379
|
return self._get("detail")
|
|
336
380
|
|
|
381
|
+
@property
|
|
382
|
+
def ticker(self) -> Ticker:
|
|
383
|
+
"""Bitmart 24h 行情 (`ifcontract/tickers`)。
|
|
384
|
+
|
|
385
|
+
.. code:: json
|
|
386
|
+
|
|
387
|
+
{
|
|
388
|
+
"contract_id": 1,
|
|
389
|
+
"last_price": "95500.1",
|
|
390
|
+
"open_24h": "91000",
|
|
391
|
+
"high_24h": "96000",
|
|
392
|
+
"low_24h": "90000",
|
|
393
|
+
"base_vol_24h": "12345",
|
|
394
|
+
"quote_vol_24h": "118000000"
|
|
395
|
+
}
|
|
396
|
+
"""
|
|
397
|
+
return self._get("ticker")
|
|
398
|
+
|
|
337
399
|
@property
|
|
338
400
|
def orders(self) -> Orders:
|
|
339
401
|
"""用户订单 (`userAllOrders`)。
|
|
@@ -485,3 +547,63 @@ class BitmartDataStore(DataStoreCollection):
|
|
|
485
547
|
]
|
|
486
548
|
"""
|
|
487
549
|
return self._get("balances")
|
|
550
|
+
|
|
551
|
+
@property
|
|
552
|
+
def ticker(self) -> Ticker:
|
|
553
|
+
"""Bitmart 合约行情数据(`/v1/ifcontract/tickers` 返回)。
|
|
554
|
+
|
|
555
|
+
表示 Bitmart 合约行情接口 `/v1/ifcontract/tickers` 返回的数据,包含合约的最新价格、成交量、指数价格、公允价格、资金费率等信息。
|
|
556
|
+
|
|
557
|
+
.. code:: json
|
|
558
|
+
|
|
559
|
+
[
|
|
560
|
+
{
|
|
561
|
+
"last_price": "0.002296",
|
|
562
|
+
"open": "0.002347",
|
|
563
|
+
"close": "0.002296",
|
|
564
|
+
"low": "0.00224",
|
|
565
|
+
"high": "0.002394",
|
|
566
|
+
"avg_price": "0.0023197328648874",
|
|
567
|
+
"volume": "6",
|
|
568
|
+
"total_volume": "200110472",
|
|
569
|
+
"timestamp": 1761812348,
|
|
570
|
+
"rise_fall_rate": "-0.0217298679164891",
|
|
571
|
+
"rise_fall_value": "-0.000051",
|
|
572
|
+
"contract_id": 33125,
|
|
573
|
+
"contract_name": "IOSTUSDT",
|
|
574
|
+
"position_size": "",
|
|
575
|
+
"volume24": "229630336",
|
|
576
|
+
"amount24": "533620.3631860018137124",
|
|
577
|
+
"high_price_24": "0.002394",
|
|
578
|
+
"low_price_24": "0.00224",
|
|
579
|
+
"base_coin_volume": "200110472",
|
|
580
|
+
"quote_coin_volume": "464202.8385065298408528",
|
|
581
|
+
"ask_price": "0.002302",
|
|
582
|
+
"ask_vol": "6396074",
|
|
583
|
+
"bid_price": "0.002289",
|
|
584
|
+
"bid_vol": "3214783",
|
|
585
|
+
"index_price": "0.00229906",
|
|
586
|
+
"fair_price": "0.002296",
|
|
587
|
+
"depth_price": {
|
|
588
|
+
"bid_price": "0",
|
|
589
|
+
"ask_price": "0",
|
|
590
|
+
"mid_price": "0"
|
|
591
|
+
},
|
|
592
|
+
"fair_basis": "",
|
|
593
|
+
"fair_value": "",
|
|
594
|
+
"rate": {
|
|
595
|
+
"quote_rate": "0",
|
|
596
|
+
"base_rate": "0",
|
|
597
|
+
"interest_rate": "0"
|
|
598
|
+
},
|
|
599
|
+
"premium_index": "",
|
|
600
|
+
"funding_rate": "-0.0000601",
|
|
601
|
+
"next_funding_rate": "",
|
|
602
|
+
"next_funding_at": "2025-10-30T16:00:00Z",
|
|
603
|
+
"pps": "0",
|
|
604
|
+
"quote_coin": "USDT",
|
|
605
|
+
"base_coin": "IOST"
|
|
606
|
+
|
|
607
|
+
]
|
|
608
|
+
"""
|
|
609
|
+
return self._get("ticker")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hyperquant
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.96
|
|
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=3lAkSy8J2p-M-663cUVFuRU-XtgNEwWAa4SKgeG6Vb8,16798
|
|
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=Utu67H0D1wzppKeHqZmsPLeJ0sao2-yR_iGwWP5p0wU,20800
|
|
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-0.
|
|
36
|
-
hyperquant-0.
|
|
37
|
-
hyperquant-0.
|
|
35
|
+
hyperquant-0.96.dist-info/METADATA,sha256=QrSvVyXcZYw1iM1uv6KfrWUVbt97Tyxzi4qinAyKDqw,4409
|
|
36
|
+
hyperquant-0.96.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
37
|
+
hyperquant-0.96.dist-info/RECORD,,
|
|
File without changes
|