hyperquant 1.42__tar.gz → 1.43__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.
Files changed (44) hide show
  1. {hyperquant-1.42 → hyperquant-1.43}/PKG-INFO +1 -1
  2. {hyperquant-1.42 → hyperquant-1.43}/pyproject.toml +1 -1
  3. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/polymarket.py +392 -6
  4. {hyperquant-1.42 → hyperquant-1.43}/uv.lock +1 -1
  5. {hyperquant-1.42 → hyperquant-1.43}/.gitignore +0 -0
  6. {hyperquant-1.42 → hyperquant-1.43}/README.md +0 -0
  7. {hyperquant-1.42 → hyperquant-1.43}/requirements-dev.lock +0 -0
  8. {hyperquant-1.42 → hyperquant-1.43}/requirements.lock +0 -0
  9. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/__init__.py +0 -0
  10. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/auth.py +0 -0
  11. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/bitget.py +0 -0
  12. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/bitmart.py +0 -0
  13. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/coinw.py +0 -0
  14. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/deepcoin.py +0 -0
  15. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/edgex.py +0 -0
  16. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/hyperliquid.py +0 -0
  17. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/lbank.py +0 -0
  18. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/lib/edgex_sign.py +0 -0
  19. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/lib/hpstore.py +0 -0
  20. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/lib/hyper_types.py +0 -0
  21. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/lib/util.py +0 -0
  22. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/lighter.py +0 -0
  23. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/models/apexpro.py +0 -0
  24. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/models/bitget.py +0 -0
  25. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/models/bitmart.py +0 -0
  26. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/models/coinw.py +0 -0
  27. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/models/deepcoin.py +0 -0
  28. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/models/edgex.py +0 -0
  29. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/models/hyperliquid.py +0 -0
  30. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/models/lbank.py +0 -0
  31. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/models/lighter.py +0 -0
  32. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/models/ourbit.py +0 -0
  33. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/models/polymarket.py +0 -0
  34. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/ourbit.py +0 -0
  35. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/broker/ws.py +0 -0
  36. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/core.py +0 -0
  37. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/datavison/_util.py +0 -0
  38. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/datavison/binance.py +0 -0
  39. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/datavison/coinglass.py +0 -0
  40. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/datavison/okx.py +0 -0
  41. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/db.py +0 -0
  42. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/draw.py +0 -0
  43. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/logkit.py +0 -0
  44. {hyperquant-1.42 → hyperquant-1.43}/src/hyperquant/notikit.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperquant
3
- Version: 1.42
3
+ Version: 1.43
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "hyperquant"
3
- version = "1.42"
3
+ version = "1.43"
4
4
  description = "A minimal yet hyper-efficient backtesting framework for quantitative trading"
5
5
  authors = [
6
6
  { name = "MissinA", email = "1421329142@qq.com" }
@@ -35,11 +35,86 @@ ERC20_BALANCE_OF_ABI = (
35
35
  "\"name\":\"balanceOf\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],"
36
36
  "\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}]"
37
37
  )
38
+ CONDITIONAL_TOKENS_ABI = [
39
+ {
40
+ "inputs": [
41
+ {
42
+ "internalType": "contract IERC20",
43
+ "name": "collateralToken",
44
+ "type": "address",
45
+ },
46
+ {
47
+ "internalType": "bytes32",
48
+ "name": "parentCollectionId",
49
+ "type": "bytes32",
50
+ },
51
+ {
52
+ "internalType": "bytes32",
53
+ "name": "conditionId",
54
+ "type": "bytes32",
55
+ },
56
+ {
57
+ "internalType": "uint256[]",
58
+ "name": "indexSets",
59
+ "type": "uint256[]",
60
+ },
61
+ ],
62
+ "name": "redeemPositions",
63
+ "outputs": [],
64
+ "stateMutability": "nonpayable",
65
+ "type": "function",
66
+ }
67
+ ]
38
68
  DEFAULT_POLYGON_RPCS = (
39
69
  "https://polygon.llamarpc.com",
40
70
  "https://polygon-rpc.com",
41
71
  "https://rpc.ankr.com/polygon",
42
72
  )
73
+ SAFE_ABI = [
74
+ {
75
+ "inputs": [],
76
+ "name": "nonce",
77
+ "outputs": [{"internalType": "uint256", "name": "nonce", "type": "uint256"}],
78
+ "stateMutability": "view",
79
+ "type": "function",
80
+ },
81
+ {
82
+ "inputs": [
83
+ {"internalType": "address", "name": "to", "type": "address"},
84
+ {"internalType": "uint256", "name": "value", "type": "uint256"},
85
+ {"internalType": "bytes", "name": "data", "type": "bytes"},
86
+ {"internalType": "uint8", "name": "operation", "type": "uint8"},
87
+ {"internalType": "uint256", "name": "safeTxGas", "type": "uint256"},
88
+ {"internalType": "uint256", "name": "baseGas", "type": "uint256"},
89
+ {"internalType": "uint256", "name": "gasPrice", "type": "uint256"},
90
+ {"internalType": "address", "name": "gasToken", "type": "address"},
91
+ {"internalType": "address", "name": "refundReceiver", "type": "address"},
92
+ {"internalType": "uint256", "name": "_nonce", "type": "uint256"},
93
+ ],
94
+ "name": "getTransactionHash",
95
+ "outputs": [{"internalType": "bytes32", "name": "txHash", "type": "bytes32"}],
96
+ "stateMutability": "view",
97
+ "type": "function",
98
+ },
99
+ {
100
+ "inputs": [
101
+ {"internalType": "address", "name": "to", "type": "address"},
102
+ {"internalType": "uint256", "name": "value", "type": "uint256"},
103
+ {"internalType": "bytes", "name": "data", "type": "bytes"},
104
+ {"internalType": "uint8", "name": "operation", "type": "uint8"},
105
+ {"internalType": "uint256", "name": "safeTxGas", "type": "uint256"},
106
+ {"internalType": "uint256", "name": "baseGas", "type": "uint256"},
107
+ {"internalType": "uint256", "name": "gasPrice", "type": "uint256"},
108
+ {"internalType": "address", "name": "gasToken", "type": "address"},
109
+ {"internalType": "address", "name": "refundReceiver", "type": "address"},
110
+ {"internalType": "bytes", "name": "signatures", "type": "bytes"},
111
+ ],
112
+ "name": "execTransaction",
113
+ "outputs": [{"internalType": "bool", "name": "success", "type": "bool"}],
114
+ "stateMutability": "payable",
115
+ "type": "function",
116
+ },
117
+ ]
43
118
  _EASTERN_TZ = pytz.timezone("US/Eastern")
44
119
 
45
120
  def parse_field(value):
@@ -1246,6 +1321,112 @@ class Polymarket:
1246
1321
  position = position / 1e6
1247
1322
  return position
1248
1323
 
1324
+ async def claim_positions(
1325
+ self,
1326
+ *,
1327
+ user: str | None = None,
1328
+ dry_run: bool = False,
1329
+ rpc_url: str | None = None,
1330
+ rpc_urls: Sequence[str] | None = None,
1331
+ gas: int = 300000,
1332
+ verbose: bool = False,
1333
+ limit: int = 500,
1334
+ include_receipt: bool = False,
1335
+ ) -> list[dict[str, Any]]:
1336
+ """自动拉取 data-api 的 redeemable 头寸并逐个 claim。
1337
+
1338
+ 只对满足 redeemable==True 且 curPrice==1 且 size>0 的仓位执行,index_set=1<<outcomeIndex。
1339
+ 始终使用 Safe 方式执行 redeemPositions(owner 私钥签名)。
1340
+ """
1341
+ # 默认用代理钱包/资金钱包
1342
+ if user is None:
1343
+ entry = self._api_entry()
1344
+ user = entry[2] if entry and len(entry) > 2 else None
1345
+ if not user:
1346
+ raise RuntimeError("Polymarket claim_positions 需要提供 user (proxy wallet)")
1347
+ if not self.funder:
1348
+ self.funder = user
1349
+
1350
+ # 构造候选 RPC 列表 (单个 rpc_url 优先, 其次用户传入 rpc_urls, 最后内置默认)
1351
+ candidates: list[str] = []
1352
+ if rpc_url:
1353
+ candidates.append(rpc_url)
1354
+ for u in (rpc_urls or []):
1355
+ if u and u not in candidates:
1356
+ candidates.append(u)
1357
+ for u in DEFAULT_POLYGON_RPCS:
1358
+ if u not in candidates:
1359
+ candidates.append(u)
1360
+
1361
+ params = {"user": user, "limit": limit}
1362
+ positions = await self._rest(
1363
+ "GET",
1364
+ "/positions",
1365
+ params=params,
1366
+ host=DEFAULT_DATA_ENDPOINT,
1367
+ )
1368
+
1369
+ claimable: list[dict[str, Any]] = []
1370
+ for pos in positions or []:
1371
+ try:
1372
+ size = float(pos.get("size", 0) or 0)
1373
+ except Exception:
1374
+ size = 0.0
1375
+ redeemable = bool(pos.get("redeemable"))
1376
+ try:
1377
+ cur_price = float(pos.get("curPrice", 0) or 0)
1378
+ except Exception:
1379
+ cur_price = 0.0
1380
+
1381
+ condition_id = pos.get("conditionId")
1382
+ outcome_idx = pos.get("outcomeIndex") or pos.get("outcome_index") or 0
1383
+ if (
1384
+ not condition_id
1385
+ or not redeemable
1386
+ or size <= 0
1387
+ or cur_price != 1
1388
+ ):
1389
+ continue
1390
+ try:
1391
+ idx_set = 1 << int(outcome_idx)
1392
+ except Exception:
1393
+ idx_set = 1
1394
+ claimable.append(
1395
+ {
1396
+ "condition_id": condition_id,
1397
+ "index_sets": [idx_set],
1398
+ "size": size,
1399
+ "outcome": pos.get("outcome"),
1400
+ "title": pos.get("title"),
1401
+ }
1402
+ )
1403
+
1404
+ results: list[dict[str, Any]] = []
1405
+ for item in claimable:
1406
+ if dry_run:
1407
+ results.append({**item, "tx": None, "dry_run": True})
1408
+ continue
1409
+ tx_hash = await asyncio.to_thread(
1410
+ self._claim_via_safe_sync,
1411
+ candidates,
1412
+ item["condition_id"],
1413
+ item["index_sets"],
1414
+ gas,
1415
+ verbose,
1416
+ )
1417
+ result_row = {**item, "tx": tx_hash, "dry_run": False}
1418
+ if include_receipt:
1419
+ try:
1420
+ receipt_info = await self.decode_claim_receipt(
1421
+ tx_hash,
1422
+ rpc_url=rpc_url or (rpc_urls[0] if rpc_urls else None),
1423
+ )
1424
+ result_row.update({"receipt": receipt_info})
1425
+ except Exception as exc: # pragma: no cover - 辅助信息获取失败
1426
+ result_row.update({"receipt_error": str(exc)})
1427
+ results.append(result_row)
1428
+ return results
1429
+
1249
1430
  async def get_usdc_web3(
1250
1431
  self,
1251
1432
  wallet: str = None,
@@ -1286,6 +1467,189 @@ class Polymarket:
1286
1467
  # ------------------------------------------------------------------
1287
1468
  # Internal utilities
1288
1469
 
1470
+ async def decode_claim_receipt(
1471
+ self,
1472
+ tx_hash: str,
1473
+ *,
1474
+ rpc_url: str | None = None,
1475
+ ) -> dict[str, Any]:
1476
+ if not tx_hash:
1477
+ raise ValueError("tx_hash is required")
1478
+ url = rpc_url or DEFAULT_POLYGON_RPCS[0]
1479
+ return await asyncio.to_thread(self._decode_payout_receipt_sync, tx_hash, url)
1480
+
1481
+ def _decode_payout_receipt_sync(self, tx_hash: str, rpc_url: str) -> dict[str, Any]:
1482
+ w3 = _get_web3(rpc_url)
1483
+ receipt = w3.eth.get_transaction_receipt(tx_hash)
1484
+ contract_cfg = self._contracts(self.chain_id, False)
1485
+ ctf_addr = w3.to_checksum_address(contract_cfg["conditional_tokens"])
1486
+ ctf = w3.eth.contract(address=ctf_addr, abi=CONDITIONAL_TOKENS_ABI)
1487
+
1488
+ decoded = []
1489
+ try:
1490
+ decoded = ctf.events.PayoutRedemption().process_receipt(receipt)
1491
+ except Exception:
1492
+ decoded = []
1493
+
1494
+ if decoded:
1495
+ ev = decoded[0]["args"]
1496
+ index_sets = [int(x) for x in ev.get("indexSets", [])]
1497
+ payout = int(ev.get("payout", 0))
1498
+ return {
1499
+ "status": receipt.status,
1500
+ "gasUsed": receipt.gasUsed,
1501
+ "indexSets": index_sets,
1502
+ "payout": payout,
1503
+ "redeemer": ev.get("redeemer"),
1504
+ "collateralToken": ev.get("collateralToken"),
1505
+ "conditionId": ev.get("conditionId").hex()
1506
+ if hasattr(ev.get("conditionId"), "hex")
1507
+ else ev.get("conditionId"),
1508
+ }
1509
+
1510
+ return {"status": receipt.status, "gasUsed": receipt.gasUsed}
1511
+
1512
+ def _claim_via_safe_sync(
1513
+ self,
1514
+ rpc_urls: Sequence[str],
1515
+ condition_id: str,
1516
+ index_sets: list[int],
1517
+ gas: int,
1518
+ verbose: bool = False,
1519
+ ) -> str:
1520
+ from eth_account import Account as _A
1521
+ from time import sleep
1522
+
1523
+ private_key, _, signer_addr = self._get_signing_context()
1524
+ safe_addr = self.funder
1525
+ if not safe_addr:
1526
+ raise RuntimeError("Safe/proxy wallet address未知, 请在 apis['polymarket'][2] 或构造函数 funder 设置")
1527
+
1528
+ w3 = None
1529
+ last_error: Exception | None = None
1530
+ for url in rpc_urls:
1531
+ try:
1532
+ w3 = _get_web3(url)
1533
+ break
1534
+ except Exception as exc:
1535
+ last_error = exc
1536
+ continue
1537
+ if w3 is None:
1538
+ raise RuntimeError(f"All RPC endpoints failed: {rpc_urls}") from last_error
1539
+
1540
+ ctf_addr = self._contracts(self.chain_id, False)["conditional_tokens"]
1541
+ ctf = w3.eth.contract(address=w3.to_checksum_address(ctf_addr), abi=CONDITIONAL_TOKENS_ABI)
1542
+ safe = w3.eth.contract(address=w3.to_checksum_address(safe_addr), abi=SAFE_ABI)
1543
+
1544
+ cond_bytes = bytes.fromhex(condition_id.replace("0x", ""))
1545
+ if len(cond_bytes) != 32:
1546
+ raise ValueError("condition_id must be 32-byte hex string")
1547
+
1548
+ redeem_calldata = ctf.encode_abi(
1549
+ "redeemPositions",
1550
+ args=[
1551
+ w3.to_checksum_address(USDC_CONTRACT),
1552
+ bytes(32),
1553
+ cond_bytes,
1554
+ index_sets,
1555
+ ],
1556
+ )
1557
+
1558
+ safe_tx_gas = 0
1559
+ base_gas = 0
1560
+ gas_price = 0
1561
+ gas_token = ZERO_ADDRESS
1562
+ refund_receiver = ZERO_ADDRESS
1563
+ value = 0
1564
+ operation = 0 # CALL
1565
+
1566
+ try:
1567
+ safe_nonce = safe.functions.nonce().call()
1568
+ except Exception as exc:
1569
+ raise RuntimeError("无法获取 Safe nonce, 请确认 funder 地址为有效 Safe") from exc
1570
+
1571
+ try:
1572
+ safe_tx_hash = safe.functions.getTransactionHash(
1573
+ w3.to_checksum_address(ctf_addr),
1574
+ value,
1575
+ redeem_calldata,
1576
+ operation,
1577
+ safe_tx_gas,
1578
+ base_gas,
1579
+ gas_price,
1580
+ w3.to_checksum_address(gas_token),
1581
+ w3.to_checksum_address(refund_receiver),
1582
+ safe_nonce,
1583
+ ).call()
1584
+ except Exception as exc:
1585
+ raise RuntimeError("Safe getTransactionHash 调用失败") from exc
1586
+
1587
+ signed = _A._sign_hash(safe_tx_hash, private_key) # eth_sign 风格
1588
+ sig_bytes = (
1589
+ int(signed.r).to_bytes(32, "big")
1590
+ + int(signed.s).to_bytes(32, "big")
1591
+ + bytes([signed.v])
1592
+ )
1593
+
1594
+ try:
1595
+ acct = _A.from_key(private_key)
1596
+ sender = acct.address
1597
+ nonce = w3.eth.get_transaction_count(sender)
1598
+ gas_price_chain = w3.eth.gas_price
1599
+ except Exception as exc:
1600
+ raise RuntimeError("获取 sender nonce/gas_price 失败") from exc
1601
+
1602
+ tx = safe.functions.execTransaction(
1603
+ w3.to_checksum_address(ctf_addr),
1604
+ value,
1605
+ redeem_calldata,
1606
+ operation,
1607
+ safe_tx_gas,
1608
+ base_gas,
1609
+ gas_price,
1610
+ w3.to_checksum_address(gas_token),
1611
+ w3.to_checksum_address(refund_receiver),
1612
+ sig_bytes,
1613
+ ).build_transaction(
1614
+ {
1615
+ "from": sender,
1616
+ "nonce": nonce,
1617
+ "gas": gas,
1618
+ "gasPrice": gas_price_chain,
1619
+ }
1620
+ )
1621
+
1622
+ signed_tx = w3.eth.account.sign_transaction(tx, private_key)
1623
+ send_errors: list[str] = []
1624
+ for attempt in range(3):
1625
+ try:
1626
+ raw_tx = getattr(signed_tx, "rawTransaction", None) or getattr(signed_tx, "raw_transaction", None)
1627
+ if raw_tx is None: # pragma: no cover
1628
+ raise AttributeError("Signed transaction missing rawTransaction/raw_transaction")
1629
+ tx_hash = w3.eth.send_raw_transaction(raw_tx)
1630
+ receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
1631
+ if receipt.get("status") != 1:
1632
+ raise RuntimeError(f"Safe redeemPositions failed status!=1: {tx_hash.hex()}")
1633
+ if verbose:
1634
+ print(
1635
+ {
1636
+ "tx": tx_hash.hex(),
1637
+ "safe_nonce": safe_nonce,
1638
+ "wallet": sender,
1639
+ "gasPrice": gas_price_chain,
1640
+ "gas": gas,
1641
+ "rpc_used": getattr(w3.provider, "endpoint_uri", "unknown"),
1642
+ }
1643
+ )
1644
+ return tx_hash.hex()
1645
+ except Exception as exc:
1646
+ send_errors.append(str(exc))
1647
+ if verbose:
1648
+ print(f"Safe redeem attempt {attempt+1} failed: {exc}")
1649
+ sleep(0.5)
1650
+ continue
1651
+ raise RuntimeError(f"Safe redeem all attempts failed: {' | '.join(send_errors)}")
1652
+
1289
1653
  async def _fetch_event(self, slug: str) -> dict | None:
1290
1654
  resp = await self.client.get(GAMMA_EVENTS_API, params={"slug": slug})
1291
1655
  payload = await resp.json()
@@ -1570,11 +1934,33 @@ class Polymarket:
1570
1934
  return [pk, "", (api_key, api_secret, passphrase, chain_id, wallet_address)]
1571
1935
 
1572
1936
  @lru_cache(maxsize=8)
1573
- def _get_web3(rpc_url: str):
1937
+ def _get_web3(rpc_url: str | None):
1938
+ """创建 web3 对象, 带多 RPC 备用与重试.
1939
+
1940
+ 逻辑:
1941
+ 1. 优先使用传入 rpc_url (如果提供)
1942
+ 2. 失败则按 DEFAULT_POLYGON_RPCS 顺序依次尝试
1943
+ 3. 任一连接成功立即返回, 全部失败抛出统一异常
1944
+ """
1574
1945
  from web3 import Web3
1575
1946
 
1576
- provider = Web3.HTTPProvider(rpc_url, request_kwargs={"timeout": 10})
1577
- w3 = Web3(provider)
1578
- if not w3.is_connected():
1579
- raise RuntimeError(f"Failed to connect Polygon RPC: {rpc_url}")
1580
- return w3
1947
+ candidates: list[str] = []
1948
+ if rpc_url:
1949
+ candidates.append(rpc_url)
1950
+ for u in DEFAULT_POLYGON_RPCS:
1951
+ if u not in candidates:
1952
+ candidates.append(u)
1953
+
1954
+ last_error: Exception | None = None
1955
+ for url in candidates:
1956
+ try:
1957
+ provider = Web3.HTTPProvider(url, request_kwargs={"timeout": 7})
1958
+ w3 = Web3(provider)
1959
+ if w3.is_connected():
1960
+ return w3
1961
+ last_error = RuntimeError(f"RPC not connected: {url}")
1962
+ except Exception as exc: # pragma: no cover - 网络异常
1963
+ last_error = exc
1964
+ continue
1965
+
1966
+ raise RuntimeError(f"Failed to connect Polygon RPCs: {candidates}") from last_error
@@ -945,7 +945,7 @@ wheels = [
945
945
 
946
946
  [[package]]
947
947
  name = "hyperquant"
948
- version = "1.41"
948
+ version = "1.42"
949
949
  source = { editable = "." }
950
950
  dependencies = [
951
951
  { name = "aiohttp" },
File without changes
File without changes
File without changes