async-hyperliquid 0.3.10__tar.gz → 0.4.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-0.3.10 → async_hyperliquid-0.4.1}/PKG-INFO +1 -1
- {async_hyperliquid-0.3.10 → async_hyperliquid-0.4.1}/pyproject.toml +1 -1
- {async_hyperliquid-0.3.10 → async_hyperliquid-0.4.1}/src/async_hyperliquid/async_hyperliquid.py +113 -32
- {async_hyperliquid-0.3.10 → async_hyperliquid-0.4.1}/src/async_hyperliquid/info.py +2 -1
- {async_hyperliquid-0.3.10 → async_hyperliquid-0.4.1}/src/async_hyperliquid/utils/signing.py +8 -4
- {async_hyperliquid-0.3.10 → async_hyperliquid-0.4.1}/src/async_hyperliquid/utils/types.py +42 -2
- {async_hyperliquid-0.3.10 → async_hyperliquid-0.4.1}/LICENSE +0 -0
- {async_hyperliquid-0.3.10 → async_hyperliquid-0.4.1}/README.md +0 -0
- {async_hyperliquid-0.3.10 → async_hyperliquid-0.4.1}/src/async_hyperliquid/__init__.py +0 -0
- {async_hyperliquid-0.3.10 → async_hyperliquid-0.4.1}/src/async_hyperliquid/async_api.py +0 -0
- {async_hyperliquid-0.3.10 → async_hyperliquid-0.4.1}/src/async_hyperliquid/exchange.py +0 -0
- {async_hyperliquid-0.3.10 → async_hyperliquid-0.4.1}/src/async_hyperliquid/utils/__init__.py +0 -0
- {async_hyperliquid-0.3.10 → async_hyperliquid-0.4.1}/src/async_hyperliquid/utils/constants.py +0 -0
- {async_hyperliquid-0.3.10 → async_hyperliquid-0.4.1}/src/async_hyperliquid/utils/decorators.py +0 -0
- {async_hyperliquid-0.3.10 → async_hyperliquid-0.4.1}/src/async_hyperliquid/utils/miscs.py +0 -0
{async_hyperliquid-0.3.10 → async_hyperliquid-0.4.1}/src/async_hyperliquid/async_hyperliquid.py
RENAMED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import re
|
|
1
2
|
import math
|
|
2
3
|
import asyncio
|
|
4
|
+
import warnings
|
|
3
5
|
from typing import Literal
|
|
4
6
|
|
|
5
7
|
from aiohttp import ClientSession, ClientTimeout
|
|
@@ -22,12 +24,12 @@ from async_hyperliquid.utils.miscs import (
|
|
|
22
24
|
from async_hyperliquid.utils.types import (
|
|
23
25
|
Cloid,
|
|
24
26
|
Metas,
|
|
27
|
+
LimitTif,
|
|
25
28
|
PerpMeta,
|
|
26
29
|
Position,
|
|
27
30
|
SpotMeta,
|
|
28
31
|
OrderType,
|
|
29
32
|
Portfolio,
|
|
30
|
-
LimitOrder,
|
|
31
33
|
Abstraction,
|
|
32
34
|
UserDeposit,
|
|
33
35
|
AccountState,
|
|
@@ -38,12 +40,15 @@ from async_hyperliquid.utils.types import (
|
|
|
38
40
|
SpotTokenMeta,
|
|
39
41
|
UserOpenOrders,
|
|
40
42
|
OrderWithStatus,
|
|
43
|
+
AgentAbstraction,
|
|
41
44
|
PlaceOrderRequest,
|
|
42
45
|
BatchCancelRequest,
|
|
43
46
|
ClearinghouseState,
|
|
47
|
+
UserSetAbstraction,
|
|
44
48
|
UserNonFundingDelta,
|
|
45
49
|
BatchPlaceOrderRequest,
|
|
46
50
|
SpotClearinghouseState,
|
|
51
|
+
limit_order_type,
|
|
47
52
|
)
|
|
48
53
|
from async_hyperliquid.utils.signing import (
|
|
49
54
|
encode_order,
|
|
@@ -163,6 +168,7 @@ class AsyncHyperliquid(AsyncAPI):
|
|
|
163
168
|
self.asset_sz_decimals[asset] = info["szDecimals"]
|
|
164
169
|
|
|
165
170
|
def _init_spot_meta(self, meta: SpotMeta) -> None:
|
|
171
|
+
total_tokens = len(meta["tokens"])
|
|
166
172
|
for info in meta["universe"]:
|
|
167
173
|
asset = info["index"] + SPOT_OFFSET
|
|
168
174
|
asset_name = info["name"]
|
|
@@ -172,6 +178,10 @@ class AsyncHyperliquid(AsyncAPI):
|
|
|
172
178
|
self.coin_names[asset_name] = asset_name
|
|
173
179
|
# For token pairs
|
|
174
180
|
base, quote = info["tokens"]
|
|
181
|
+
if base >= total_tokens or quote >= total_tokens:
|
|
182
|
+
print("Unreconized token index for: ", info)
|
|
183
|
+
continue
|
|
184
|
+
|
|
175
185
|
base_info = meta["tokens"][base]
|
|
176
186
|
base_name = base_info["name"]
|
|
177
187
|
quote_name = meta["tokens"][quote]["name"]
|
|
@@ -501,17 +511,12 @@ class AsyncHyperliquid(AsyncAPI):
|
|
|
501
511
|
positions.extend(result)
|
|
502
512
|
return positions
|
|
503
513
|
|
|
504
|
-
async def
|
|
505
|
-
if not address:
|
|
506
|
-
address = self.address
|
|
507
|
-
return await self.info.get_user_dex_abstraction(address)
|
|
508
|
-
|
|
509
|
-
async def get_user_abstraction_state(
|
|
514
|
+
async def get_user_abstraction(
|
|
510
515
|
self, address: str | None = None
|
|
511
|
-
) ->
|
|
516
|
+
) -> Abstraction:
|
|
512
517
|
if not address:
|
|
513
518
|
address = self.address
|
|
514
|
-
return await self.info.
|
|
519
|
+
return await self.info.get_user_abstraction(address)
|
|
515
520
|
|
|
516
521
|
# Exchange API
|
|
517
522
|
async def _round_sz_px(self, coin: str, sz: float, px: float):
|
|
@@ -521,26 +526,46 @@ class AsyncHyperliquid(AsyncAPI):
|
|
|
521
526
|
px_decimals = (6 if not is_spot else 8) - sz_decimals
|
|
522
527
|
return asset, round_float(sz, sz_decimals), round_px(px, px_decimals)
|
|
523
528
|
|
|
524
|
-
async def
|
|
529
|
+
async def place_market_order(
|
|
525
530
|
self,
|
|
526
531
|
coin: str,
|
|
527
532
|
is_buy: bool,
|
|
528
533
|
sz: float,
|
|
529
|
-
px: float,
|
|
530
|
-
is_market: bool = True,
|
|
531
534
|
*,
|
|
532
535
|
ro: bool = False,
|
|
533
|
-
order_type: OrderType = LimitOrder.IOC.value, # type: ignore
|
|
534
536
|
cloid: Cloid | None = None,
|
|
535
537
|
slippage: float = 0.05, # Default slippage is 5%
|
|
536
538
|
builder: OrderBuilder | None = None,
|
|
537
539
|
):
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
540
|
+
mid_px = await self.get_mid_price(coin)
|
|
541
|
+
slippage_factor = (1 + slippage) if is_buy else (1 - slippage)
|
|
542
|
+
px = mid_px * slippage_factor
|
|
543
|
+
# Market order is an aggressive Limit Order IoC
|
|
544
|
+
return await self.place_typed_order(
|
|
545
|
+
coin=coin,
|
|
546
|
+
is_buy=is_buy,
|
|
547
|
+
sz=sz,
|
|
548
|
+
px=px,
|
|
549
|
+
ro=ro,
|
|
550
|
+
order_type=limit_order_type(LimitTif.IOC),
|
|
551
|
+
cloid=cloid,
|
|
552
|
+
builder=builder,
|
|
553
|
+
)
|
|
554
|
+
|
|
555
|
+
async def place_typed_order(
|
|
556
|
+
self,
|
|
557
|
+
coin: str,
|
|
558
|
+
is_buy: bool,
|
|
559
|
+
sz: float,
|
|
560
|
+
px: float,
|
|
561
|
+
*,
|
|
562
|
+
ro: bool = False,
|
|
563
|
+
order_type: OrderType | None = None,
|
|
564
|
+
cloid: Cloid | None = None,
|
|
565
|
+
builder: OrderBuilder | None = None,
|
|
566
|
+
):
|
|
567
|
+
if order_type is None:
|
|
568
|
+
order_type = limit_order_type(LimitTif.IOC)
|
|
544
569
|
|
|
545
570
|
asset, sz, px = await self._round_sz_px(coin, sz, px)
|
|
546
571
|
|
|
@@ -556,6 +581,42 @@ class AsyncHyperliquid(AsyncAPI):
|
|
|
556
581
|
|
|
557
582
|
return await self.place_orders([order_req], builder=builder)
|
|
558
583
|
|
|
584
|
+
async def place_order(
|
|
585
|
+
self,
|
|
586
|
+
coin: str,
|
|
587
|
+
is_buy: bool,
|
|
588
|
+
sz: float,
|
|
589
|
+
px: float,
|
|
590
|
+
is_market: bool = True,
|
|
591
|
+
*,
|
|
592
|
+
ro: bool = False,
|
|
593
|
+
order_type: OrderType | None = None,
|
|
594
|
+
cloid: Cloid | None = None,
|
|
595
|
+
slippage: float = 0.05, # Default slippage is 5%
|
|
596
|
+
builder: OrderBuilder | None = None,
|
|
597
|
+
):
|
|
598
|
+
if is_market:
|
|
599
|
+
return await self.place_market_order(
|
|
600
|
+
coin=coin,
|
|
601
|
+
is_buy=is_buy,
|
|
602
|
+
sz=sz,
|
|
603
|
+
ro=ro,
|
|
604
|
+
cloid=cloid,
|
|
605
|
+
slippage=slippage,
|
|
606
|
+
builder=builder,
|
|
607
|
+
)
|
|
608
|
+
|
|
609
|
+
return await self.place_typed_order(
|
|
610
|
+
coin=coin,
|
|
611
|
+
is_buy=is_buy,
|
|
612
|
+
sz=sz,
|
|
613
|
+
px=px,
|
|
614
|
+
ro=ro,
|
|
615
|
+
order_type=order_type,
|
|
616
|
+
cloid=cloid,
|
|
617
|
+
builder=builder,
|
|
618
|
+
)
|
|
619
|
+
|
|
559
620
|
async def place_orders(
|
|
560
621
|
self,
|
|
561
622
|
orders: list[PlaceOrderRequest],
|
|
@@ -603,7 +664,7 @@ class AsyncHyperliquid(AsyncAPI):
|
|
|
603
664
|
reqs = []
|
|
604
665
|
dexs = list(set(get_coin_dex(o["coin"]) for o in orders))
|
|
605
666
|
all_mids = await self.get_dexs_mids(dexs)
|
|
606
|
-
order_type =
|
|
667
|
+
order_type = limit_order_type(LimitTif.IOC)
|
|
607
668
|
for o in orders:
|
|
608
669
|
coin = o["coin"]
|
|
609
670
|
market_price = all_mids[coin]
|
|
@@ -1014,6 +1075,12 @@ class AsyncHyperliquid(AsyncAPI):
|
|
|
1014
1075
|
async def user_dex_abstraction(
|
|
1015
1076
|
self, user: str | None = None, enabled: bool = True
|
|
1016
1077
|
):
|
|
1078
|
+
warnings.warn(
|
|
1079
|
+
"user_dex_abstraction is deprecated and may be removed in a "
|
|
1080
|
+
"future release.",
|
|
1081
|
+
DeprecationWarning,
|
|
1082
|
+
stacklevel=2,
|
|
1083
|
+
)
|
|
1017
1084
|
nonce = get_timestamp_ms()
|
|
1018
1085
|
if user is None:
|
|
1019
1086
|
user = self.address
|
|
@@ -1028,30 +1095,44 @@ class AsyncHyperliquid(AsyncAPI):
|
|
|
1028
1095
|
)
|
|
1029
1096
|
return await self.exchange.post_action_with_sig(action, sig, nonce)
|
|
1030
1097
|
|
|
1031
|
-
async def agent_enable_dex_abstraction(self):
|
|
1032
|
-
action = {"type": "agentEnableDexAbstraction"}
|
|
1033
|
-
return await self.exchange.post_action(
|
|
1034
|
-
action, vault=self.vault, expires=self.expires
|
|
1035
|
-
)
|
|
1036
|
-
|
|
1037
1098
|
async def user_set_abstraction(
|
|
1038
|
-
self, abstraction:
|
|
1099
|
+
self, abstraction: UserSetAbstraction, user: str | None = None
|
|
1039
1100
|
):
|
|
1040
|
-
if address is None:
|
|
1041
|
-
address = self.address
|
|
1042
|
-
|
|
1043
1101
|
nonce = get_timestamp_ms()
|
|
1102
|
+
if user is None:
|
|
1103
|
+
user = self.address
|
|
1104
|
+
if re.fullmatch(r"0x[a-fA-F0-9]{40}", user) is None:
|
|
1105
|
+
raise ValueError(
|
|
1106
|
+
f"user must be a 42-char hex address, got: {user!r}"
|
|
1107
|
+
)
|
|
1044
1108
|
action = {
|
|
1045
1109
|
"type": "userSetAbstraction",
|
|
1046
|
-
"user":
|
|
1110
|
+
"user": user.lower(),
|
|
1047
1111
|
"abstraction": abstraction,
|
|
1048
1112
|
"nonce": nonce,
|
|
1049
1113
|
}
|
|
1050
1114
|
sig = sign_user_set_abstraction_action(
|
|
1051
1115
|
self.account, action, self.is_mainnet
|
|
1052
1116
|
)
|
|
1053
|
-
|
|
1054
1117
|
return await self.exchange.post_action_with_sig(action, sig, nonce)
|
|
1055
1118
|
|
|
1119
|
+
async def agent_enable_dex_abstraction(self):
|
|
1120
|
+
warnings.warn(
|
|
1121
|
+
"agent_enable_dex_abstraction is deprecated and may be removed "
|
|
1122
|
+
"in a future release.",
|
|
1123
|
+
DeprecationWarning,
|
|
1124
|
+
stacklevel=2,
|
|
1125
|
+
)
|
|
1126
|
+
action = {"type": "agentEnableDexAbstraction"}
|
|
1127
|
+
return await self.exchange.post_action(
|
|
1128
|
+
action, vault=self.vault, expires=self.expires
|
|
1129
|
+
)
|
|
1130
|
+
|
|
1131
|
+
async def agent_set_abstraction(self, abstraction: AgentAbstraction):
|
|
1132
|
+
action = {"type": "agentSetAbstraction", "abstraction": abstraction}
|
|
1133
|
+
return await self.exchange.post_action(
|
|
1134
|
+
action, vault=self.vault, expires=self.expires
|
|
1135
|
+
)
|
|
1136
|
+
|
|
1056
1137
|
|
|
1057
1138
|
AsyncHyper = AsyncHyperliquid
|
|
@@ -4,6 +4,7 @@ from aiohttp import ClientSession
|
|
|
4
4
|
|
|
5
5
|
from async_hyperliquid.async_api import AsyncAPI
|
|
6
6
|
from async_hyperliquid.utils.types import (
|
|
7
|
+
Abstraction,
|
|
7
8
|
Depth,
|
|
8
9
|
Candles,
|
|
9
10
|
Endpoint,
|
|
@@ -183,7 +184,7 @@ class InfoAPI(AsyncAPI):
|
|
|
183
184
|
payload = {"type": "userDexAbstraction", "user": address}
|
|
184
185
|
return await self.post(payload)
|
|
185
186
|
|
|
186
|
-
async def
|
|
187
|
+
async def get_user_abstraction(self, address: str) -> Abstraction:
|
|
187
188
|
payload = {"type": "userAbstraction", "user": address}
|
|
188
189
|
return await self.post(payload)
|
|
189
190
|
|
|
@@ -8,6 +8,7 @@ from eth_utils.conversions import to_hex
|
|
|
8
8
|
from eth_account.signers.local import LocalAccount
|
|
9
9
|
|
|
10
10
|
from async_hyperliquid.utils.types import (
|
|
11
|
+
LimitTif,
|
|
11
12
|
OrderType,
|
|
12
13
|
OrderAction,
|
|
13
14
|
EncodedOrder,
|
|
@@ -15,6 +16,9 @@ from async_hyperliquid.utils.types import (
|
|
|
15
16
|
OrderBuilder,
|
|
16
17
|
SignedAction,
|
|
17
18
|
PlaceOrderRequest,
|
|
19
|
+
is_limit_order_type,
|
|
20
|
+
is_trigger_order_type,
|
|
21
|
+
limit_order_type,
|
|
18
22
|
)
|
|
19
23
|
from async_hyperliquid.utils.constants import (
|
|
20
24
|
SIGNATURE_CHAIN_ID,
|
|
@@ -27,9 +31,9 @@ from async_hyperliquid.utils.constants import (
|
|
|
27
31
|
APPROVE_BUILDER_FEE_TYPES,
|
|
28
32
|
STAKING_TRANSFER_SIGN_TYPES,
|
|
29
33
|
MULTI_SIG_ENVELOPE_SIGN_TYPES,
|
|
34
|
+
USER_SET_ABSTRACTION_SIGN_TYPES,
|
|
30
35
|
USD_CLASS_TRANSFER_SIGN_TYPES,
|
|
31
36
|
USER_DEX_ABSTRACTION_SIGN_TYPES,
|
|
32
|
-
USER_SET_ABSTRACTION_SIGN_TYPES,
|
|
33
37
|
CONVERT_TO_MULTI_SIG_USER_SIGN_TYPES,
|
|
34
38
|
)
|
|
35
39
|
|
|
@@ -114,9 +118,9 @@ def round_float(x: float) -> str:
|
|
|
114
118
|
|
|
115
119
|
|
|
116
120
|
def ensure_order_type(order_type: OrderType) -> OrderType:
|
|
117
|
-
if
|
|
118
|
-
return
|
|
119
|
-
|
|
121
|
+
if is_limit_order_type(order_type):
|
|
122
|
+
return limit_order_type(LimitTif(order_type["limit"]["tif"]))
|
|
123
|
+
if is_trigger_order_type(order_type):
|
|
120
124
|
return {
|
|
121
125
|
"trigger": {
|
|
122
126
|
"isMarket": order_type["trigger"]["isMarket"],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
|
-
from typing import Any, Literal, TypedDict
|
|
2
|
+
from typing import Any, Literal, TypeGuard, TypedDict
|
|
3
3
|
|
|
4
4
|
from typing_extensions import NotRequired
|
|
5
5
|
|
|
@@ -47,12 +47,22 @@ class LimitOrderType(TypedDict):
|
|
|
47
47
|
limit: LimitOrderOptions
|
|
48
48
|
|
|
49
49
|
|
|
50
|
+
class LimitTif(str, Enum):
|
|
51
|
+
ALO = "Alo"
|
|
52
|
+
IOC = "Ioc"
|
|
53
|
+
GTC = "Gtc"
|
|
54
|
+
|
|
55
|
+
|
|
50
56
|
class LimitOrder(Enum):
|
|
51
57
|
ALO = {"limit": {"tif": "Alo"}}
|
|
52
58
|
IOC = {"limit": {"tif": "Ioc"}}
|
|
53
59
|
GTC = {"limit": {"tif": "Gtc"}}
|
|
54
60
|
|
|
55
61
|
|
|
62
|
+
def limit_order_type(tif: LimitTif) -> LimitOrderType:
|
|
63
|
+
return {"limit": {"tif": tif.value}}
|
|
64
|
+
|
|
65
|
+
|
|
56
66
|
class TriggerOrderOptions(TypedDict):
|
|
57
67
|
isMarket: bool
|
|
58
68
|
triggerPx: str
|
|
@@ -63,9 +73,39 @@ class TriggerOrderType(TypedDict):
|
|
|
63
73
|
trigger: TriggerOrderOptions
|
|
64
74
|
|
|
65
75
|
|
|
76
|
+
class TriggerTpsl(str, Enum):
|
|
77
|
+
TP = "tp"
|
|
78
|
+
SL = "sl"
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def trigger_order_type(
|
|
82
|
+
*, is_market: bool, trigger_px: float | str, tpsl: TriggerTpsl
|
|
83
|
+
) -> TriggerOrderType:
|
|
84
|
+
return {
|
|
85
|
+
"trigger": {
|
|
86
|
+
"isMarket": is_market,
|
|
87
|
+
"triggerPx": str(trigger_px),
|
|
88
|
+
"tpsl": tpsl.value,
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
66
93
|
OrderType = LimitOrderType | TriggerOrderType
|
|
67
94
|
|
|
68
95
|
GroupOptions = Literal["na", "normalTpsl", "positionTpsl"]
|
|
96
|
+
Abstraction = Literal[
|
|
97
|
+
"unifiedAccount", "portfolioMargin", "disabled", "default", "dexAbstraction"
|
|
98
|
+
]
|
|
99
|
+
UserSetAbstraction = Literal["disabled", "unifiedAccount", "portfolioMargin"]
|
|
100
|
+
AgentAbstraction = Literal["i", "u", "p"]
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def is_limit_order_type(order_type: OrderType) -> TypeGuard[LimitOrderType]:
|
|
104
|
+
return "limit" in order_type and "trigger" not in order_type
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def is_trigger_order_type(order_type: OrderType) -> TypeGuard[TriggerOrderType]:
|
|
108
|
+
return "trigger" in order_type and "limit" not in order_type
|
|
69
109
|
|
|
70
110
|
|
|
71
111
|
class BasicPlaceOrderRequest(TypedDict):
|
|
@@ -113,7 +153,7 @@ class EncodedOrder(TypedDict):
|
|
|
113
153
|
|
|
114
154
|
class OrderBuilder(TypedDict):
|
|
115
155
|
b: str # builder address
|
|
116
|
-
f:
|
|
156
|
+
f: int
|
|
117
157
|
|
|
118
158
|
|
|
119
159
|
class OrderAction(TypedDict):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{async_hyperliquid-0.3.10 → async_hyperliquid-0.4.1}/src/async_hyperliquid/utils/__init__.py
RENAMED
|
File without changes
|
{async_hyperliquid-0.3.10 → async_hyperliquid-0.4.1}/src/async_hyperliquid/utils/constants.py
RENAMED
|
File without changes
|
{async_hyperliquid-0.3.10 → async_hyperliquid-0.4.1}/src/async_hyperliquid/utils/decorators.py
RENAMED
|
File without changes
|
|
File without changes
|