hyperquant 0.94__py3-none-any.whl → 0.95__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.

@@ -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
- qty: float,
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(qty) / contract_size_val
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"qty too small for contract size ({contract_size_val}): qty={qty}"
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"qty must be a multiple of contract_size ({contract_size_val}). "
359
- f"Received qty={qty} -> {contracts_float} contracts."
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
- adjusted_price = float(fmt_value(price, price_unit))
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": adjusted_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.94
3
+ Version: 0.95
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=ish5SXenO1f1MCDnuRbkatPApHvUiyer8fmSGylIk2A,15914
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=7DgnuDlD-ZneDpyilW-V-mEwVSniwBTre1xlFaJiK6o,16578
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.94.dist-info/METADATA,sha256=UofH3N5NelHoWQnfrfAdEnAbtwesIsXerHl_ExVoMSU,4409
36
- hyperquant-0.94.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
37
- hyperquant-0.94.dist-info/RECORD,,
35
+ hyperquant-0.95.dist-info/METADATA,sha256=VCnz-XozwQFVbD3iQCz_Xg1kmKFOSqLCqyQwmeIq_iU,4409
36
+ hyperquant-0.95.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
37
+ hyperquant-0.95.dist-info/RECORD,,