hyperquant 0.64__py3-none-any.whl → 0.66__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.
@@ -4,6 +4,7 @@ import asyncio
4
4
  from typing import Any, Awaitable, TYPE_CHECKING
5
5
 
6
6
  from aiohttp import ClientResponse
7
+ import aiohttp
7
8
  from pybotters.store import DataStore, DataStoreCollection
8
9
 
9
10
  if TYPE_CHECKING:
@@ -121,7 +122,6 @@ class Book(DataStore):
121
122
  if updates:
122
123
  self._update(updates)
123
124
  self._trim(contract_id, contract_name)
124
-
125
125
 
126
126
  def _build_items(
127
127
  self,
@@ -279,6 +279,311 @@ class Ticker(DataStore):
279
279
  return item
280
280
 
281
281
 
282
+ class Order(DataStore):
283
+ """Order data store combining REST results with trade-event deltas.
284
+
285
+ We only keep fields that are practical for trading book-keeping: identifiers,
286
+ basic order parameters, cumulative fills, high-level status and timestamps.
287
+ Network payloads carry hundreds of fields (``l2`` signatures, TPSL templates,
288
+ liquidation metadata, etc.), but the extra data adds noise and bloats memory
289
+ consumption. This store narrows every entry to a compact schema while still
290
+ supporting diff events from the private websocket feed.
291
+ """
292
+
293
+ _KEYS = ["orderId"]
294
+
295
+ _TERMINAL_STATUSES = {
296
+ "FILLED",
297
+ "CANCELED",
298
+ "CANCELLED",
299
+ "REJECTED",
300
+ "EXPIRED",
301
+ }
302
+
303
+ _ACTIVE_STATUSES = {
304
+ "OPEN",
305
+ "PARTIALLY_FILLED",
306
+ "PENDING",
307
+ "CREATED",
308
+ "ACKNOWLEDGED",
309
+ }
310
+
311
+ _KEEP_FIELDS = (
312
+ "userId",
313
+ "accountId",
314
+ "coinId",
315
+ "contractId",
316
+ "clientOrderId",
317
+ "type",
318
+ "timeInForce",
319
+ "reduceOnly",
320
+ "price",
321
+ "size",
322
+ "cumFillSize",
323
+ "cumFillValue",
324
+ "cumMatchSize",
325
+ "cumMatchValue",
326
+ "cumMatchFee",
327
+ "triggerPrice",
328
+ "triggerPriceType",
329
+ "cancelReason",
330
+ "createdTime",
331
+ "updatedTime",
332
+ "matchSequenceId",
333
+ )
334
+
335
+ _BOOL_FIELDS = {"reduceOnly"}
336
+
337
+ def _on_message(self, msg: dict[str, Any]) -> None:
338
+ content = msg.get("content") or {}
339
+ data = content.get("data") or {}
340
+ orders = data.get("order") or []
341
+
342
+ if not isinstance(orders, list):
343
+ orders = [orders]
344
+
345
+ items = [self._format(order) for order in orders]
346
+ items = [item for item in items if item]
347
+ if not items:
348
+ return
349
+
350
+ event = (content.get("event") or "").lower()
351
+ if event == "snapshot":
352
+ self._clear()
353
+ self._insert(items)
354
+ return
355
+
356
+ for item in items:
357
+ status = str(item.get("status") or "").upper()
358
+ criteria = {"orderId": item["orderId"]}
359
+ existing = self.find(criteria)
360
+
361
+ if status in self._TERMINAL_STATUSES:
362
+ if existing:
363
+ self._update([item])
364
+ else:
365
+ self._insert([item])
366
+ self._find_and_delete(criteria)
367
+ continue
368
+
369
+ if status and status not in self._ACTIVE_STATUSES:
370
+ if existing:
371
+ self._update([item])
372
+ else:
373
+ self._insert([item])
374
+ self._find_and_delete(criteria)
375
+ continue
376
+
377
+ if existing:
378
+ self._update([item])
379
+ else:
380
+ self._insert([item])
381
+
382
+ def _onresponse(self, data: dict[str, Any]) -> None:
383
+ payload = data.get("data")
384
+
385
+ if isinstance(payload, dict):
386
+ orders = payload.get("dataList") or payload.get("orderList") or []
387
+ else:
388
+ orders = payload or []
389
+
390
+ if not isinstance(orders, list):
391
+ orders = [orders]
392
+
393
+ items = [self._format(order) for order in orders]
394
+ items = [item for item in items if item]
395
+
396
+ self._clear()
397
+ if items:
398
+ self._insert(items)
399
+
400
+ @staticmethod
401
+ def _normalize_order_id(value: Any) -> str | None:
402
+ if value is None:
403
+ return None
404
+ return str(value)
405
+
406
+ @staticmethod
407
+ def _normalize_side(value: Any) -> str | None:
408
+ if value is None:
409
+ return None
410
+ if isinstance(value, str):
411
+ return value.lower()
412
+ return str(value)
413
+
414
+ @staticmethod
415
+ def _normalize_status(value: Any) -> str | None:
416
+ if value is None:
417
+ return None
418
+ return str(value).upper()
419
+
420
+ @staticmethod
421
+ def _stringify(value: Any) -> Any:
422
+ if value is None:
423
+ return None
424
+ if isinstance(value, (bool, dict, list)):
425
+ return value
426
+ return str(value)
427
+
428
+ def _format(self, order: dict[str, Any] | None) -> dict[str, Any] | None:
429
+ if not order:
430
+ return None
431
+
432
+ order_id = (
433
+ order.get("orderId")
434
+ or order.get("id")
435
+ or order.get("order_id")
436
+ or order.get("orderID")
437
+ )
438
+
439
+ normalized_id = self._normalize_order_id(order_id)
440
+ if normalized_id is None:
441
+ return None
442
+
443
+ item: dict[str, Any] = {"orderId": normalized_id, "id": normalized_id}
444
+
445
+ side = self._normalize_side(order.get("side"))
446
+ if side is not None:
447
+ item["side"] = side
448
+
449
+ status = self._normalize_status(order.get("status"))
450
+ if status is not None:
451
+ item["status"] = status
452
+
453
+ contract_name = order.get("contractName")
454
+ if contract_name:
455
+ symbol = self._stringify(contract_name)
456
+ item["contractName"] = symbol
457
+ item.setdefault("symbol", symbol)
458
+
459
+ for field in self._KEEP_FIELDS:
460
+ if field in ("side", "status"):
461
+ continue
462
+ value = order.get(field)
463
+ if value is None:
464
+ continue
465
+ if field in self._BOOL_FIELDS:
466
+ item[field] = bool(value)
467
+ else:
468
+ item[field] = self._stringify(value)
469
+
470
+ return item
471
+
472
+
473
+ class Balance(DataStore):
474
+ """Account balance snapshot retaining only the trading-critical fields."""
475
+
476
+ _KEYS = ["accountId", "coinId"]
477
+
478
+
479
+ def _onresponse(self, data: dict[str, Any]) -> None:
480
+ data = data.get('data', {})
481
+ collateral_assets = data.get('collateralAssetModelList') or []
482
+ if collateral_assets:
483
+ self._update(collateral_assets)
484
+
485
+ def _on_message(self, msg: dict[str, Any]) -> None:
486
+ pass
487
+
488
+
489
+ class Position(DataStore):
490
+ """
491
+ Stores per-account open positions in a simplified camelCase schema.
492
+ Only the current open position fields are retained: positionId, contractId, accountId,
493
+ userId, coinId, side, size, value, fee, fundingFee.
494
+ """
495
+
496
+ _KEYS = ["positionId"]
497
+
498
+ @staticmethod
499
+ def _stringify(value: Any) -> Any:
500
+ if value is None:
501
+ return None
502
+ if isinstance(value, (bool, dict, list)):
503
+ return value
504
+ return str(value)
505
+
506
+ def _onresponse(self, data: dict[str, Any]) -> None:
507
+ """
508
+ Handle REST response for getAccountAsset (open positions snapshot).
509
+ Expects data from getAccountAsset (REST), which returns a snapshot of **current open positions**,
510
+ as a list in data["positionList"].
511
+ Each entry is normalized to camelCase schema, only including essential fields for the current open position.
512
+ """
513
+ data = data.get("data", {}) or {}
514
+ positions = data.get("positionList") or []
515
+ if not isinstance(positions, list):
516
+ positions = [positions]
517
+ items = [self._normalize_position(pos) for pos in positions]
518
+ self._clear()
519
+ if items:
520
+ self._update(items)
521
+
522
+ def _on_message(self, msg: dict[str, Any]) -> None:
523
+ data = msg.get("content", {}).get("data", {})
524
+ if not data:
525
+ return
526
+ positions = data.get("position")
527
+ if not positions:
528
+ return
529
+ items = [self._normalize_position(pos) for pos in positions]
530
+ self._clear()
531
+ if items:
532
+ self._update(items)
533
+
534
+ def _normalize_position(self, pos: dict[str, Any]) -> dict[str, Any]:
535
+ # Only keep essential fields for the current open position
536
+ def get(key, *alts):
537
+ for k in (key,) + alts:
538
+ if k in pos and pos[k] is not None:
539
+ return pos[k]
540
+ return None
541
+
542
+ open_size = get("openSize")
543
+ open_value = get("openValue")
544
+ open_fee = get("openFee")
545
+ funding_fee = get("fundingFee")
546
+
547
+ # side: "long" if openSize > 0, "short" if openSize < 0, None if 0
548
+ side = None
549
+ try:
550
+ if open_size is not None:
551
+ fsize = float(open_size)
552
+ if fsize > 0:
553
+ side = "long"
554
+ elif fsize < 0:
555
+ side = "short"
556
+ except Exception:
557
+ side = None
558
+
559
+ size = None
560
+ if open_size is not None:
561
+ try:
562
+ size = str(abs(float(open_size)))
563
+ except Exception:
564
+ size = str(open_size)
565
+ value = None
566
+ if open_value is not None:
567
+ try:
568
+ value = str(abs(float(open_value)))
569
+ except Exception:
570
+ value = str(open_value)
571
+
572
+ item = {
573
+ "positionId": self._stringify(get("positionId", "position_id")),
574
+ "contractId": self._stringify(get("contractId")),
575
+ "accountId": self._stringify(get("accountId")),
576
+ "userId": self._stringify(get("userId")),
577
+ "coinId": self._stringify(get("coinId")),
578
+ "side": side,
579
+ "size": size,
580
+ "value": value,
581
+ "fee": self._stringify(open_fee),
582
+ "fundingFee": self._stringify(funding_fee),
583
+ }
584
+ return item
585
+
586
+
282
587
  class CoinMeta(DataStore):
283
588
  """Coin metadata (precision, StarkEx info, etc.)."""
284
589
 
@@ -310,7 +615,7 @@ class CoinMeta(DataStore):
310
615
  class ContractMeta(DataStore):
311
616
  """Per-contract trading parameters from the metadata endpoint."""
312
617
 
313
- _KEYS = ["contractId"]
618
+ _KEYS = ["contractName"]
314
619
 
315
620
  _FIELDS = (
316
621
  "contractName",
@@ -342,7 +647,9 @@ class ContractMeta(DataStore):
342
647
  payload = {"contractId": str(contract_id)}
343
648
  for key in self._FIELDS:
344
649
  payload[key] = contract.get(key)
345
- payload["riskTierList"] = self._simplify_risk_tiers(contract.get("riskTierList"))
650
+ payload["riskTierList"] = self._simplify_risk_tiers(
651
+ contract.get("riskTierList")
652
+ )
346
653
 
347
654
  items.append(payload)
348
655
 
@@ -366,14 +673,57 @@ class ContractMeta(DataStore):
366
673
  )
367
674
  return items
368
675
 
676
+
677
+ class AppMeta(DataStore):
678
+ """Global metadata (appName, env, fee account, etc.)."""
679
+
680
+ _KEYS = ["appName"]
681
+
682
+ def _onresponse(self, data: dict[str, Any]) -> None:
683
+ appdata = (data.get("data") or {}).get("global") or {}
684
+ if not appdata:
685
+ self._clear()
686
+ return
687
+ # Convert all values to str where appropriate, but preserve fields as-is (for bool/int etc).
688
+ item = {}
689
+ for k, v in appdata.items():
690
+ if k == "starkExCollateralCoin" and isinstance(v, dict):
691
+ # Flatten the dict into top-level fields with prefix
692
+ for subk, subv in v.items():
693
+ # Compose the flattened key
694
+ prefix = "starkExCollateral"
695
+ # Capitalize first letter of subkey
696
+ if subk and subk[0].islower():
697
+ flatkey = prefix + subk[0].upper() + subk[1:]
698
+ else:
699
+ flatkey = prefix + subk
700
+ item[flatkey] = subv if subv is None or isinstance(subv, (bool, int, float)) else str(subv)
701
+ continue
702
+ # Convert to str except for None; preserve bool/int/float as-is
703
+ if v is None:
704
+ item[k] = v
705
+ elif isinstance(v, (bool, int, float)):
706
+ item[k] = v
707
+ else:
708
+ item[k] = str(v)
709
+ self._clear()
710
+ if item:
711
+ self._insert([item])
712
+
713
+
369
714
  class EdgexDataStore(DataStoreCollection):
370
715
  """Edgex DataStore collection exposing the order book feed."""
371
716
 
372
717
  def _init(self) -> None:
373
718
  self._create("book", datastore_class=Book)
374
719
  self._create("ticker", datastore_class=Ticker)
720
+ self._create("orders", datastore_class=Order)
721
+ self._create("balance", datastore_class=Balance)
722
+ # Position store holds per-account open positions in simplified camelCase form
723
+ self._create("position", datastore_class=Position)
375
724
  self._create("meta_coin", datastore_class=CoinMeta)
376
725
  self._create("detail", datastore_class=ContractMeta)
726
+ self._create("app", datastore_class=AppMeta)
377
727
 
378
728
  @property
379
729
  def book(self) -> Book:
@@ -394,8 +744,121 @@ class EdgexDataStore(DataStoreCollection):
394
744
  """
395
745
  return self._get("book")
396
746
 
747
+ @property
748
+ def orders(self) -> Order:
749
+ """
750
+ 账户订单数据流(REST 快照 + 私有 WS 增量)。
751
+
752
+ 存储为**精简 schema**,仅保留实操必需字段。终态订单(FILLED / CANCELED / CANCELLED / REJECTED / EXPIRED)
753
+ 会在写入一次后从本地缓存删除,只保留进行中的订单(OPEN / PARTIALLY_FILLED / PENDING / CREATED / ACKNOWLEDGED)。
754
+
755
+
756
+ 存储示例(本地条目)
757
+ -------------------
758
+ REST 快照:
759
+
760
+ .. code:: json
761
+
762
+ [
763
+ {
764
+ "orderId": "564815695875932430",
765
+ "id": "564815695875932430",
766
+ "contractId": "10000001",
767
+ "contractName": "BTCUSD",
768
+ "symbol": "BTCUSD",
769
+ "side": "buy",
770
+ "status": "OPEN",
771
+ "type": "LIMIT",
772
+ "timeInForce": "GOOD_TIL_CANCEL",
773
+ "reduceOnly": false,
774
+ "price": "97444.5",
775
+ "size": "0.010",
776
+ "cumFillSize": "0.000",
777
+ "cumFillValue": "0",
778
+ "clientOrderId": "553364074986685",
779
+ "createdTime": "1734662555665",
780
+ "updatedTime": "1734662555665"
781
+ }
782
+ ]
783
+
784
+
785
+ """
786
+ return self._get("orders")
787
+
788
+ @property
789
+ def balance(self) -> Balance:
790
+ """
791
+ 获取账户资产余额(REST 快照 + 私有 WS 增量)。
397
792
 
793
+ .. code:: json
794
+
795
+ [
796
+ {
797
+ userId: "663528067892773124",
798
+ accountId: "663528067938910372",
799
+ coinId: "1000",
800
+ totalEquity: "22.721859",
801
+ totalPositionValueAbs: "0",
802
+ initialMarginRequirement: "0",
803
+ starkExRiskValue: "0",
804
+ pendingWithdrawAmount: "0",
805
+ pendingTransferOutAmount: "0",
806
+ orderFrozenAmount: "3.001126965030794963240623474121093750",
807
+ availableAmount: "19.720732",
808
+ },
809
+ ]
398
810
 
811
+ """
812
+ return self._get("balance")
813
+
814
+ @property
815
+ def position(self) -> "Position":
816
+ """
817
+ 获取账户当前未平仓持仓(open positions,来自 getAccountAsset)。
818
+
819
+ 本属性提供**当前未平仓持仓**的快照(由 REST ``getAccountAsset`` 提供),每条数据为当前账户的一个持仓(多/空/逐仓/全仓等)。
820
+ 字段为 snake_case,包含持仓数量、均价、强平价、杠杆、保证金率等信息,适合用于持仓管理与风险监控。
821
+
822
+ 数据示例:
823
+
824
+ .. code:: python
825
+
826
+ [
827
+ {
828
+ orderId: "665307878751470244",
829
+ id: "665307878751470244",
830
+ side: "buy",
831
+ status: "OPEN",
832
+ userId: "663528067892773124",
833
+ accountId: "663528067938910372",
834
+ coinId: "1000",
835
+ contractId: "10000003",
836
+ clientOrderId: "32570392453812747",
837
+ type: "LIMIT",
838
+ timeInForce: "GOOD_TIL_CANCEL",
839
+ reduceOnly: False,
840
+ price: "210.00",
841
+ size: "0.3",
842
+ cumFillSize: "0",
843
+ cumFillValue: "0",
844
+ cumMatchSize: "0",
845
+ cumMatchValue: "0",
846
+ cumMatchFee: "0",
847
+ triggerPrice: "0",
848
+ triggerPriceType: "UNKNOWN_PRICE_TYPE",
849
+ cancelReason: "UNKNOWN_ORDER_CANCEL_REASON",
850
+ createdTime: "1758621759117",
851
+ updatedTime: "1758621759122",
852
+ matchSequenceId: "784278904",
853
+ },
854
+ ];
855
+
856
+
857
+ 本属性仅包含**当前持有的未平仓持仓**(由 REST ``getAccountAsset`` 提供)。
858
+ 若需获取**历史已平仓持仓周期**,请调用 ``getPositionTermPage``。
859
+ """
860
+ return self._get("position")
861
+
399
862
  @property
400
863
  def coins(self) -> CoinMeta:
401
864
  """
@@ -425,7 +888,7 @@ class EdgexDataStore(DataStoreCollection):
425
888
  [
426
889
  {
427
890
  "contractId": "10000001",
428
- "contractName": "BTCUSDT",
891
+ "contractName": "BTCUSD",
429
892
  "baseCoinId": "1001",
430
893
  "quoteCoinId": "1000",
431
894
  "tickSize": "0.1",
@@ -494,10 +957,18 @@ class EdgexDataStore(DataStoreCollection):
494
957
  for fut in asyncio.as_completed(aws):
495
958
  res = await fut
496
959
  data = await res.json()
960
+ if data['code'] != 'SUCCESS':
961
+ raise ValueError(f"Unexpected response code: {data}")
497
962
  if res.url.path == "/api/v1/public/meta/getMetaData":
498
963
  self._apply_metadata(data)
964
+ elif res.url.path == "/api/v1/private/account/getAccountAsset":
965
+ self.balance._onresponse(data)
966
+ self.position._onresponse(data)
967
+ elif res.url.path == "/api/v1/private/order/getActiveOrderPage":
968
+ self.orders._onresponse(data)
499
969
 
500
970
  def onmessage(self, msg: Item, ws: ClientWebSocketResponse | None = None) -> None:
971
+ # print(msg)
501
972
  channel = (msg.get("channel") or "").lower()
502
973
  msg_type = (msg.get("type") or "").lower()
503
974
 
@@ -506,13 +977,59 @@ class EdgexDataStore(DataStoreCollection):
506
977
  asyncio.create_task(ws.send_json(payload))
507
978
  return
508
979
 
980
+ if msg_type in {"trade-event", "trade_event", "order-event", "order_event"}:
981
+ self.orders._on_message(msg)
982
+ self.position._on_message(msg)
983
+
509
984
  if "depth" in channel and msg_type in {"quote-event", "payload"}:
510
985
  self.book._on_message(msg)
511
986
 
512
987
  if channel.startswith("ticker") and msg_type in {"payload", "quote-event"}:
513
988
  self.ticker._on_message(msg)
514
989
 
515
-
516
990
  def _apply_metadata(self, data: dict[str, Any]) -> None:
991
+ self.app._onresponse(data)
517
992
  self.coins._onresponse(data)
518
993
  self.detail._onresponse(data)
994
+
995
+
996
+ @property
997
+ def app(self) -> AppMeta:
998
+ """
999
+ 获取全局元数据,如 appName、环境、fee 账户等。
1000
+
1001
+ .. code:: python
1002
+
1003
+
1004
+ [
1005
+ {
1006
+ "appName": "edgeX",
1007
+ "appEnv": "mainnet",
1008
+ "appOnlySignOn": "https://pro.edgex.exchange",
1009
+ "feeAccountId": "256105",
1010
+ "feeAccountL2Key": "0x70092acf49d535fbb64d99883abda95dcf9a4fc60f494437a3d76f27db0a0f5",
1011
+ "poolAccountId": "508126509156794507",
1012
+ "poolAccountL2Key": "0x7f2e1e8a572c847086ee93c9b5bbce8b96320aaa69147df1cfca91d5e90bc60",
1013
+ "fastWithdrawAccountId": "508126509156794507",
1014
+ "fastWithdrawAccountL2Key": "0x7f2e1e8a572c847086ee93c9b5bbce8b96320aaa69147df1cfca91d5e90bc60",
1015
+ "fastWithdrawMaxAmount": "100000",
1016
+ "fastWithdrawRegistryAddress": "0xBE9a129909EbCb954bC065536D2bfAfBd170d27A",
1017
+ "starkExChainId": "0x1",
1018
+ "starkExContractAddress": "0xfAaE2946e846133af314d1Df13684c89fA7d83DD",
1019
+ "starkExCollateralCoinId": "1000",
1020
+ "starkExCollateralCoinName": "USD",
1021
+ "starkExCollateralStepSize": "0.000001",
1022
+ "starkExCollateralShowStepSize": "0.0001",
1023
+ "starkExCollateralIconUrl": "https://static.edgex.exchange/icons/coin/USDT.svg",
1024
+ "starkExCollateralStarkExAssetId": "0x2ce625e94458d39dd0bf3b45a843544dd4a14b8169045a3a3d15aa564b936c5",
1025
+ "starkExCollateralStarkExResolution": "0xf4240",
1026
+ "starkExMaxFundingRate": 12000,
1027
+ "starkExOrdersTreeHeight": 64,
1028
+ "starkExPositionsTreeHeight": 64,
1029
+ "starkExFundingValidityPeriod": 86400,
1030
+ "starkExPriceValidityPeriod": 86400,
1031
+ "maintenanceReason": "",
1032
+ }
1033
+ ]
1034
+ """
1035
+ return self._get("app")
hyperquant/broker/ws.py CHANGED
@@ -1,9 +1,12 @@
1
1
  import asyncio
2
+ import base64
2
3
  import time
4
+ from typing import Any
3
5
 
4
6
  import pybotters
5
7
  from pybotters.ws import ClientWebSocketResponse, logger
6
8
  from pybotters.auth import Hosts
9
+ import urllib
7
10
  import yarl
8
11
 
9
12
 
@@ -59,7 +62,5 @@ class WssAuth:
59
62
  break
60
63
  else:
61
64
  logger.warning(f"WebSocket login failed: {data}")
62
-
63
-
64
-
65
+
65
66
  pybotters.ws.AuthHosts.items['futures.ourbit.com'] = pybotters.auth.Item("ourbit", WssAuth.ourbit)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperquant
3
- Version: 0.64
3
+ Version: 0.66
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
@@ -4,15 +4,17 @@ hyperquant/db.py,sha256=i2TjkCbmH4Uxo7UTDvOYBfy973gLcGexdzuT_YcSeIE,6678
4
4
  hyperquant/draw.py,sha256=up_lQ3pHeVLoNOyh9vPjgNwjD0M-6_IetSGviQUgjhY,54624
5
5
  hyperquant/logkit.py,sha256=nUo7nx5eONvK39GOhWwS41zNRL756P2J7-5xGzwXnTY,8462
6
6
  hyperquant/notikit.py,sha256=x5yAZ_tAvLQRXcRbcg-VabCaN45LUhvlTZnUqkIqfAA,3596
7
- hyperquant/broker/auth.py,sha256=oA9Yw1I59-u0Tnoj2e4wUup5q8V5T2qpga5RKbiAiZI,2614
8
- hyperquant/broker/edgex.py,sha256=qQtc8jZqB5ZODoGGVcG_aIVUlrJX_pRF9EyO927LiVM,6646
7
+ hyperquant/broker/auth.py,sha256=PgWw6eFGQtVbbA_JcJkK71L4JckinO8h2B0FrEV5G-U,6516
8
+ hyperquant/broker/edgex.py,sha256=7oUY3HJUR87eSnkRFMEh1ttZCZkeAB_CkQF4Rodoevs,17645
9
9
  hyperquant/broker/hyperliquid.py,sha256=7MxbI9OyIBcImDelPJu-8Nd53WXjxPB5TwE6gsjHbto,23252
10
- hyperquant/broker/lbank.py,sha256=9waMiBfjsogewTwTOcaG5_5bJHLjXSrv56oqjEptgh4,3107
10
+ hyperquant/broker/lbank.py,sha256=kuxRfZylGZK3LRMzQJcB3w_nOXWM9-si65EwDsj0DnY,3325
11
11
  hyperquant/broker/ourbit.py,sha256=NUcDSIttf-HGWzoW1uBTrGLPHlkuemMjYCm91MigTno,18228
12
- hyperquant/broker/ws.py,sha256=4Igi0zuwGHmU46BSz24sFURkYalrE5Z68qkZEFBfbJE,2147
12
+ hyperquant/broker/ws.py,sha256=9Zu5JSLj-ylYEVmFmRwvZDDnVYKwb37cLHfZzA0AZGc,2200
13
+ hyperquant/broker/lib/edgex_sign.py,sha256=lLUCmY8HHRLfLKyGrlTJYaBlSHPsIMWg3EZnQJKcmyk,95785
13
14
  hyperquant/broker/lib/hpstore.py,sha256=LnLK2zmnwVvhEbLzYI-jz_SfYpO1Dv2u2cJaRAb84D8,8296
14
15
  hyperquant/broker/lib/hyper_types.py,sha256=HqjjzjUekldjEeVn6hxiWA8nevAViC2xHADOzDz9qyw,991
15
- hyperquant/broker/models/edgex.py,sha256=texNBwz_9r9CTl7dRNjvSm_toxV_og0TWnap3dqUk2s,15795
16
+ hyperquant/broker/lib/util.py,sha256=u02kGb-7LMCi32UNLeKoPaZBZ2LBEjx72KRkaKX0yQg,275
17
+ hyperquant/broker/models/edgex.py,sha256=ba9ogBprp3uGPgYprjBJoVcVWUBbmZ_l2hYCIGQCRpA,33449
16
18
  hyperquant/broker/models/hyperliquid.py,sha256=c4r5739ibZfnk69RxPjQl902AVuUOwT8RNvKsMtwXBY,9459
17
19
  hyperquant/broker/models/lbank.py,sha256=ArYBHHF9p66rNXs9fn41W2asa5mK-mqgplajCHr51YA,7106
18
20
  hyperquant/broker/models/ourbit.py,sha256=xMcbuCEXd3XOpPBq0RYF2zpTFNnxPtuNJZCexMZVZ1k,41965
@@ -20,6 +22,6 @@ hyperquant/datavison/_util.py,sha256=92qk4vO856RqycO0YqEIHJlEg-W9XKapDVqAMxe6rbw
20
22
  hyperquant/datavison/binance.py,sha256=3yNKTqvt_vUQcxzeX4ocMsI5k6Q6gLZrvgXxAEad6Kc,5001
21
23
  hyperquant/datavison/coinglass.py,sha256=PEjdjISP9QUKD_xzXNzhJ9WFDTlkBrRQlVL-5pxD5mo,10482
22
24
  hyperquant/datavison/okx.py,sha256=yg8WrdQ7wgWHNAInIgsWPM47N3Wkfr253169IPAycAY,6898
23
- hyperquant-0.64.dist-info/METADATA,sha256=8O2BgrL-YzkxoAf0oqBhE9-hLdcwpvbBL6e_gpnOlAk,4317
24
- hyperquant-0.64.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
25
- hyperquant-0.64.dist-info/RECORD,,
25
+ hyperquant-0.66.dist-info/METADATA,sha256=GVJWSwmMpQU_6dpHiOreOSExsvq4e3Pg34_QUHh_Y9U,4317
26
+ hyperquant-0.66.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
27
+ hyperquant-0.66.dist-info/RECORD,,