async-hyperliquid 1.2.0__tar.gz → 1.2.1__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.
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/CHANGELOG.md +16 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/PKG-INFO +2 -2
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/README.md +1 -1
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/coin-name-mapping.md +7 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/howto/markets.rst +2 -1
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/coin-name-mapping.po +13 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/howto/markets.po +4 -2
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/pyproject.toml +1 -1
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/_internal/encoding.py +7 -3
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/_internal/metadata.py +9 -1
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/client.py +4 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/info.py +29 -7
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/LICENSE +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/benchmarks/README.md +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/benchmarks/__init__.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/benchmarks/fast_cancel.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/benchmarks/hotpath.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/benchmarks/live/__init__.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/benchmarks/live/models.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/benchmarks/live/pacing.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/benchmarks/live/preflight.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/benchmarks/live/providers.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/benchmarks/live/reporting.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/benchmarks/live/results.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/benchmarks/live/runner.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/benchmarks/live/workload.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/benchmarks/live_exchange.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/benchmarks/results/20260805T192621Z/cancel-id-latency.png +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/benchmarks/results/20260805T192621Z/cancel-id-latency.svg +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/benchmarks/results/20260805T192621Z/report.json +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/benchmarks/results/20260805T192621Z/samples.csv +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/benchmarks/signing.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/_static/language-switcher.css +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/_templates/sidebar/language-switcher.html +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/conf.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/howto/index.rst +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/howto/info-queries.rst +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/howto/lifecycle-reconciliation.rst +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/howto/orders.rst +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/howto/routing.rst +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/howto/transfers-administration.rst +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/index.rst +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/introduction/index.rst +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/introduction/installation.rst +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/introduction/quickstart.rst +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/howto/index.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/howto/info-queries.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/howto/lifecycle-reconciliation.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/howto/orders.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/howto/routing.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/howto/transfers-administration.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/index.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/introduction/index.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/introduction/installation.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/introduction/quickstart.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/migration-0.5-to-1.0.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/project/about.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/project/benchmarks.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/project/index.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/project/license.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/reference/async-hyperliquid.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/reference/errors.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/reference/exchange-client.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/reference/index.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/reference/info-client.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/reference/response-types.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/reference/types.po +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/migration-0.5-to-1.0.md +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/project/about.rst +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/project/benchmarks.md +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/project/index.rst +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/project/license.rst +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/reference/async-hyperliquid.rst +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/reference/errors.rst +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/reference/exchange-client.rst +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/reference/index.rst +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/reference/info-client.rst +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/reference/response-types.rst +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/reference/types.rst +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/__init__.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/_internal/__init__.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/_internal/exchange.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/_internal/http.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/_internal/info.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/_internal/signing.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/constants.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/errors.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/exchange.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/py.typed +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/types/__init__.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/types/common.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/types/exchange.py +0 -0
- {async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/types/info.py +0 -0
|
@@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.2.1] - 2026-11-03
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Accept `sz=0` in order and modify requests; it is encoded as `"0"` and left to
|
|
13
|
+
the exchange to validate. Negative sizes are still rejected, and `place_twap()`
|
|
14
|
+
still requires a positive size.
|
|
15
|
+
- Reload metadata once when a lookup misses the cached snapshot, so markets
|
|
16
|
+
listed after the first load resolve without `refresh_metadata()`. A failed
|
|
17
|
+
reload keeps the last snapshot and the lookup still raises `ValueError`.
|
|
18
|
+
- Reject non-finite or non-positive order prices with
|
|
19
|
+
`price must be finite and greater than zero`; a positive price that rounds to
|
|
20
|
+
zero now reports `order price is below market precision`.
|
|
21
|
+
- Market orders raise `ProtocolError` when the mid price is not finite and
|
|
22
|
+
positive, instead of reporting an invalid order price.
|
|
23
|
+
|
|
8
24
|
## [1.2.0] - 2026-11-03
|
|
9
25
|
|
|
10
26
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: async-hyperliquid
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.1
|
|
4
4
|
Summary: Async Hyperliquid client using aiohttp
|
|
5
5
|
Keywords: dex,hyperliquid,async,aiohttp,trading,cryptocurrency,defi
|
|
6
6
|
Author: Yuki
|
|
@@ -36,7 +36,7 @@ Description-Content-Type: text/markdown
|
|
|
36
36
|
|
|
37
37
|
[](https://github.com/owlyfi/async-hyperliquid/actions/workflows/ci.yml)
|
|
38
38
|
[](https://async-hyperliquid.readthedocs.io/en/latest/)
|
|
39
|
-
[](https://pypi.org/project/async-hyperliquid/)
|
|
40
40
|
|
|
41
41
|
`async-hyperliquid` is a typed, asynchronous Python client for the Hyperliquid
|
|
42
42
|
REST API. It provides credential-free market and account queries through
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/owlyfi/async-hyperliquid/actions/workflows/ci.yml)
|
|
4
4
|
[](https://async-hyperliquid.readthedocs.io/en/latest/)
|
|
5
|
-
[](https://pypi.org/project/async-hyperliquid/)
|
|
6
6
|
|
|
7
7
|
`async-hyperliquid` is a typed, asynchronous Python client for the Hyperliquid
|
|
8
8
|
REST API. It provides credential-free market and account queries through
|
|
@@ -13,6 +13,13 @@ The first lookup loads metadata. Concurrent cold lookups share one load;
|
|
|
13
13
|
`refresh_metadata()` explicitly replaces the last complete snapshot. A partial
|
|
14
14
|
or inconsistent response is rejected without publishing partial state.
|
|
15
15
|
|
|
16
|
+
A lookup for a coin missing from the cached snapshot reloads metadata once
|
|
17
|
+
before raising, so markets listed after the first load resolve without an
|
|
18
|
+
explicit refresh. If that reload fails, the last snapshot stays in place and the
|
|
19
|
+
lookup still raises `ValueError`. Misses are not cached: every lookup of an
|
|
20
|
+
unknown coin repeats the reload, so validate user input before it reaches a hot
|
|
21
|
+
path.
|
|
22
|
+
|
|
16
23
|
## Asset spaces
|
|
17
24
|
|
|
18
25
|
| Market | Asset ID |
|
|
@@ -17,7 +17,8 @@ helpers instead of deriving protocol offsets in application code.
|
|
|
17
17
|
The first metadata lookup loads one immutable snapshot. Concurrent cold
|
|
18
18
|
lookups share that load. ``refresh_metadata()`` atomically replaces the last
|
|
19
19
|
complete snapshot; malformed or inconsistent metadata is rejected before it is
|
|
20
|
-
published.
|
|
20
|
+
published. A lookup for a coin missing from the cached snapshot reloads
|
|
21
|
+
metadata once before raising ``ValueError``.
|
|
21
22
|
|
|
22
23
|
Coin forms
|
|
23
24
|
----------
|
|
@@ -63,6 +63,19 @@ msgstr ""
|
|
|
63
63
|
"首次查询会加载元数据。并发冷查询共享同一次加载;`refresh_metadata()` 会显式替换最近一次完整快照。"
|
|
64
64
|
"不完整或不一致的响应会被拒绝,且不会发布部分状态。"
|
|
65
65
|
|
|
66
|
+
#: ../../coin-name-mapping.md:16
|
|
67
|
+
msgid ""
|
|
68
|
+
"A lookup for a coin missing from the cached snapshot reloads metadata "
|
|
69
|
+
"once before raising, so markets listed after the first load resolve "
|
|
70
|
+
"without an explicit refresh. If that reload fails, the last snapshot stays "
|
|
71
|
+
"in place and the lookup still raises `ValueError`. Misses are not cached: "
|
|
72
|
+
"every lookup of an unknown coin repeats the reload, so validate user input "
|
|
73
|
+
"before it reaches a hot path."
|
|
74
|
+
msgstr ""
|
|
75
|
+
"若查询的 coin 不在缓存快照中,会先重新加载一次元数据再抛出错误,因此首次加载之后新上线的市场无需显式刷新即可解析。"
|
|
76
|
+
"如果这次重新加载失败,会保留上一次的快照,查询仍然抛出 `ValueError`。未命中的结果不会被缓存:"
|
|
77
|
+
"每次查询未知 coin 都会重新加载一次,因此请在用户输入进入热路径之前先做校验。"
|
|
78
|
+
|
|
66
79
|
#: ../../coin-name-mapping.md:16 667c70e0123949059329339edf3f8ca6
|
|
67
80
|
msgid "Asset spaces"
|
|
68
81
|
msgstr "资产编号空间"
|
{async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/howto/markets.po
RENAMED
|
@@ -34,10 +34,12 @@ msgid ""
|
|
|
34
34
|
"The first metadata lookup loads one immutable snapshot. Concurrent cold "
|
|
35
35
|
"lookups share that load. ``refresh_metadata()`` atomically replaces the "
|
|
36
36
|
"last complete snapshot; malformed or inconsistent metadata is rejected "
|
|
37
|
-
"before it is published."
|
|
37
|
+
"before it is published. A lookup for a coin missing from the cached "
|
|
38
|
+
"snapshot reloads metadata once before raising ``ValueError``."
|
|
38
39
|
msgstr ""
|
|
39
40
|
"首次元数据查询会加载一个不可变快照。并发的冷查询会共享该加载。``refresh_metadata()`` 会原子地替换最后一个完整快照;"
|
|
40
|
-
"
|
|
41
|
+
"格式错误或不一致的元数据会在发布前被拒绝。若查询的 coin 不在缓存快照中,会先重新加载一次元数据,"
|
|
42
|
+
"仍未命中才抛出 ``ValueError``。"
|
|
41
43
|
|
|
42
44
|
#: ../../howto/markets.rst:23 a74ae47aabbf4ba5817d21a500d064ae
|
|
43
45
|
msgid "Coin forms"
|
{async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/_internal/encoding.py
RENAMED
|
@@ -19,8 +19,10 @@ def _round_size(value: float, size_decimals: int) -> float | int:
|
|
|
19
19
|
|
|
20
20
|
def _normalize_size(value: float, size_decimals: int) -> float | int:
|
|
21
21
|
size = float(value)
|
|
22
|
-
if not math.isfinite(size) or size
|
|
23
|
-
raise ValueError("size must be finite and
|
|
22
|
+
if not math.isfinite(size) or size < 0:
|
|
23
|
+
raise ValueError("size must be finite and non-negative")
|
|
24
|
+
if size == 0:
|
|
25
|
+
return 0
|
|
24
26
|
rounded = _round_size(size, size_decimals)
|
|
25
27
|
if rounded <= 0:
|
|
26
28
|
raise ValueError("order size is below market precision")
|
|
@@ -49,13 +51,15 @@ def _normalize_price(
|
|
|
49
51
|
value: float | str, *, max_decimals: int, is_outcome: bool
|
|
50
52
|
) -> float | int:
|
|
51
53
|
price = float(value)
|
|
54
|
+
if not math.isfinite(price) or price <= 0:
|
|
55
|
+
raise ValueError("price must be finite and greater than zero")
|
|
52
56
|
if is_outcome and not OUTCOME_MIN_PRICE <= price <= OUTCOME_MAX_PRICE:
|
|
53
57
|
raise ValueError("outcome price must be between 0.00001 and 0.99999 USDC")
|
|
54
58
|
rounded = _round_price(
|
|
55
59
|
price, OUTCOME_PRICE_DECIMALS if is_outcome else max_decimals
|
|
56
60
|
)
|
|
57
61
|
if rounded <= 0:
|
|
58
|
-
raise ValueError("order
|
|
62
|
+
raise ValueError("order price is below market precision")
|
|
59
63
|
return rounded
|
|
60
64
|
|
|
61
65
|
|
{async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/_internal/metadata.py
RENAMED
|
@@ -251,8 +251,16 @@ def _build_metadata(
|
|
|
251
251
|
)
|
|
252
252
|
|
|
253
253
|
|
|
254
|
+
def _is_outcome_coin(coin: str) -> bool:
|
|
255
|
+
return coin.startswith(("#", "+"))
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def _is_known_coin(snapshot: _MetadataSnapshot, coin: str) -> bool:
|
|
259
|
+
return _is_outcome_coin(coin) or coin in snapshot.coin_by_alias
|
|
260
|
+
|
|
261
|
+
|
|
254
262
|
def _outcome_market_info(coin: str) -> _MarketInfo | None:
|
|
255
|
-
if not coin
|
|
263
|
+
if not _is_outcome_coin(coin):
|
|
256
264
|
return None
|
|
257
265
|
raw_encoding = coin[1:]
|
|
258
266
|
if not raw_encoding.isascii() or not raw_encoding.isdecimal():
|
|
@@ -57,6 +57,8 @@ def _coin_dex(coin: str) -> str:
|
|
|
57
57
|
def _market_price(
|
|
58
58
|
mid: float, *, is_buy: bool, slippage: float, is_outcome: bool
|
|
59
59
|
) -> float:
|
|
60
|
+
if not math.isfinite(mid) or mid <= 0:
|
|
61
|
+
raise ProtocolError("mid price must be finite and greater than zero")
|
|
60
62
|
price = mid * (1 + slippage if is_buy else 1 - slippage)
|
|
61
63
|
if not is_outcome:
|
|
62
64
|
return price
|
|
@@ -484,6 +486,8 @@ class AsyncHyperliquid:
|
|
|
484
486
|
if market.is_spot and reduce_only:
|
|
485
487
|
raise ValueError("spot orders cannot be reduce-only")
|
|
486
488
|
rounded_size = _normalize_size(size, market.size_decimals)
|
|
489
|
+
if rounded_size == 0:
|
|
490
|
+
raise ValueError("TWAP size must be greater than zero")
|
|
487
491
|
details: EncodedTwapDetails | None = None
|
|
488
492
|
if trigger_px is not None or stop_px is not None:
|
|
489
493
|
encoded_trigger_px = (
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
+
import logging
|
|
2
3
|
from collections.abc import Sequence
|
|
3
4
|
from types import TracebackType
|
|
4
5
|
from typing import Literal, Self, cast, overload
|
|
@@ -23,9 +24,10 @@ from ._internal.metadata import (
|
|
|
23
24
|
_MarketInfo,
|
|
24
25
|
_MetadataSnapshot,
|
|
25
26
|
_build_metadata,
|
|
27
|
+
_is_known_coin,
|
|
26
28
|
_market_info,
|
|
27
29
|
)
|
|
28
|
-
from .errors import ProtocolError
|
|
30
|
+
from .errors import HyperliquidError, ProtocolError
|
|
29
31
|
from .types import CandleInterval, JsonObject, JsonValue, Network
|
|
30
32
|
from .types.info import (
|
|
31
33
|
AccountState,
|
|
@@ -73,6 +75,9 @@ from .types.info import (
|
|
|
73
75
|
)
|
|
74
76
|
|
|
75
77
|
|
|
78
|
+
logger = logging.getLogger(__name__)
|
|
79
|
+
|
|
80
|
+
|
|
76
81
|
class InfoClient:
|
|
77
82
|
"""Asynchronous, credential-free client for Hyperliquid Info endpoints."""
|
|
78
83
|
|
|
@@ -506,15 +511,32 @@ class InfoClient:
|
|
|
506
511
|
snapshot = await self._load_metadata()
|
|
507
512
|
self._metadata = snapshot
|
|
508
513
|
|
|
509
|
-
async def
|
|
514
|
+
async def _metadata_for(self, *coins: str) -> _MetadataSnapshot:
|
|
515
|
+
cold = self._metadata is None
|
|
510
516
|
snapshot = await self._ensure_metadata()
|
|
517
|
+
if cold or all(_is_known_coin(snapshot, coin) for coin in coins):
|
|
518
|
+
return snapshot
|
|
519
|
+
async with self._get_metadata_lock():
|
|
520
|
+
# Concurrent misses on the same stale snapshot share one reload.
|
|
521
|
+
if self._metadata is snapshot:
|
|
522
|
+
try:
|
|
523
|
+
self._metadata = await self._load_metadata()
|
|
524
|
+
except (HyperliquidError, TimeoutError):
|
|
525
|
+
# Keep the miss a ValueError raised by the caller's lookup.
|
|
526
|
+
logger.debug("metadata refresh after a miss failed", exc_info=True)
|
|
527
|
+
return snapshot
|
|
528
|
+
# Refreshes only replace a published snapshot, never clear it.
|
|
529
|
+
return cast(_MetadataSnapshot, self._metadata)
|
|
530
|
+
|
|
531
|
+
async def coin_name(self, coin: str) -> str:
|
|
532
|
+
snapshot = await self._metadata_for(coin)
|
|
511
533
|
name = snapshot.coin_by_alias.get(coin)
|
|
512
534
|
if name is None:
|
|
513
535
|
raise ValueError(f"unknown coin: {coin}")
|
|
514
536
|
return name
|
|
515
537
|
|
|
516
538
|
async def coin_symbol(self, coin: str) -> str:
|
|
517
|
-
snapshot = await self.
|
|
539
|
+
snapshot = await self._metadata_for(coin)
|
|
518
540
|
name = snapshot.coin_by_alias.get(coin)
|
|
519
541
|
if name is None:
|
|
520
542
|
raise ValueError(f"unknown coin: {coin}")
|
|
@@ -530,14 +552,14 @@ class InfoClient:
|
|
|
530
552
|
return (await self._market_info(coin)).size_decimals
|
|
531
553
|
|
|
532
554
|
async def _market_info(self, coin: str) -> _MarketInfo:
|
|
533
|
-
return _market_info(await self.
|
|
555
|
+
return _market_info(await self._metadata_for(coin), coin)
|
|
534
556
|
|
|
535
557
|
async def _market_infos(self, coins: Sequence[str]) -> tuple[_MarketInfo, ...]:
|
|
536
|
-
snapshot = await self.
|
|
558
|
+
snapshot = await self._metadata_for(*coins)
|
|
537
559
|
return tuple(_market_info(snapshot, coin) for coin in coins)
|
|
538
560
|
|
|
539
561
|
async def spot_token_metadata(self, coin: str) -> SpotToken:
|
|
540
|
-
snapshot = await self.
|
|
562
|
+
snapshot = await self._metadata_for(coin)
|
|
541
563
|
name = snapshot.coin_by_alias.get(coin)
|
|
542
564
|
token = None if name is None else snapshot.spot_token_by_coin.get(name)
|
|
543
565
|
if token is None:
|
|
@@ -548,7 +570,7 @@ class InfoClient:
|
|
|
548
570
|
return (await self.spot_token_metadata(coin))["tokenId"]
|
|
549
571
|
|
|
550
572
|
async def mark_price(self, coin: str) -> float:
|
|
551
|
-
snapshot = await self.
|
|
573
|
+
snapshot = await self._metadata_for(coin)
|
|
552
574
|
name = snapshot.coin_by_alias.get(coin)
|
|
553
575
|
if name is None:
|
|
554
576
|
raise ValueError(f"unknown coin: {coin}")
|
|
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
|
{async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/benchmarks/results/20260805T192621Z/report.json
RENAMED
|
File without changes
|
{async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/benchmarks/results/20260805T192621Z/samples.csv
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/_templates/sidebar/language-switcher.html
RENAMED
|
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
|
{async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/howto/index.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/howto/orders.po
RENAMED
|
File without changes
|
{async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/howto/routing.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/project/about.po
RENAMED
|
File without changes
|
|
File without changes
|
{async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/project/index.po
RENAMED
|
File without changes
|
{async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/project/license.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/reference/index.po
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/docs/locale/zh_CN/LC_MESSAGES/reference/types.po
RENAMED
|
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
|
{async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/_internal/__init__.py
RENAMED
|
File without changes
|
{async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/_internal/exchange.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{async_hyperliquid-1.2.0 → async_hyperliquid-1.2.1}/src/async_hyperliquid/_internal/signing.py
RENAMED
|
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
|