Skip to content

Commit f779142

Browse files
committed
Support grouping in exchange.order
1 parent dfa299b commit f779142

File tree

2 files changed

+131
-31
lines changed

2 files changed

+131
-31
lines changed

hyperliquid/exchange.py

Lines changed: 81 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from hyperliquid.utils.signing import (
1212
CancelByCloidRequest,
1313
CancelRequest,
14+
Grouping,
1415
ModifyRequest,
1516
OidOrCloid,
1617
OrderRequest,
@@ -31,7 +32,16 @@
3132
sign_usd_transfer_action,
3233
sign_withdraw_from_bridge_action,
3334
)
34-
from hyperliquid.utils.types import Any, BuilderInfo, Cloid, List, Meta, Optional, SpotMeta, Tuple
35+
from hyperliquid.utils.types import (
36+
Any,
37+
BuilderInfo,
38+
Cloid,
39+
List,
40+
Meta,
41+
Optional,
42+
SpotMeta,
43+
Tuple,
44+
)
3545

3646

3747
class Exchange(API):
@@ -58,7 +68,9 @@ def _post_action(self, action, signature, nonce):
5868
"action": action,
5969
"nonce": nonce,
6070
"signature": signature,
61-
"vaultAddress": self.vault_address if action["type"] != "usdClassTransfer" else None,
71+
"vaultAddress": self.vault_address
72+
if action["type"] != "usdClassTransfer"
73+
else None,
6274
}
6375
logging.debug(payload)
6476
return self.post("/exchange", payload)
@@ -93,6 +105,7 @@ def order(
93105
reduce_only: bool = False,
94106
cloid: Optional[Cloid] = None,
95107
builder: Optional[BuilderInfo] = None,
108+
grouping: Grouping = "na",
96109
) -> Any:
97110
order: OrderRequest = {
98111
"coin": name,
@@ -104,17 +117,23 @@ def order(
104117
}
105118
if cloid:
106119
order["cloid"] = cloid
107-
return self.bulk_orders([order], builder)
120+
return self.bulk_orders([order], builder, grouping)
108121

109-
def bulk_orders(self, order_requests: List[OrderRequest], builder: Optional[BuilderInfo] = None) -> Any:
122+
def bulk_orders(
123+
self,
124+
order_requests: List[OrderRequest],
125+
builder: Optional[BuilderInfo] = None,
126+
grouping: Grouping = "na",
127+
) -> Any:
110128
order_wires: List[OrderWire] = [
111-
order_request_to_order_wire(order, self.info.name_to_asset(order["coin"])) for order in order_requests
129+
order_request_to_order_wire(order, self.info.name_to_asset(order["coin"]))
130+
for order in order_requests
112131
]
113132
timestamp = get_timestamp_ms()
114133

115134
if builder:
116135
builder["b"] = builder["b"].lower()
117-
order_action = order_wires_to_order_action(order_wires, builder)
136+
order_action = order_wires_to_order_action(order_wires, builder, grouping)
118137

119138
signature = sign_l1_action(
120139
self.wallet,
@@ -159,8 +178,12 @@ def bulk_modify_orders_new(self, modify_requests: List[ModifyRequest]) -> Any:
159178
timestamp = get_timestamp_ms()
160179
modify_wires = [
161180
{
162-
"oid": modify["oid"].to_raw() if isinstance(modify["oid"], Cloid) else modify["oid"],
163-
"order": order_request_to_order_wire(modify["order"], self.info.name_to_asset(modify["order"]["coin"])),
181+
"oid": modify["oid"].to_raw()
182+
if isinstance(modify["oid"], Cloid)
183+
else modify["oid"],
184+
"order": order_request_to_order_wire(
185+
modify["order"], self.info.name_to_asset(modify["order"]["coin"])
186+
),
164187
}
165188
for modify in modify_requests
166189
]
@@ -198,7 +221,14 @@ def market_open(
198221
px = self._slippage_price(name, is_buy, slippage, px)
199222
# Market Order is an aggressive Limit Order IoC
200223
return self.order(
201-
name, is_buy, sz, px, order_type={"limit": {"tif": "Ioc"}}, reduce_only=False, cloid=cloid, builder=builder
224+
name,
225+
is_buy,
226+
sz,
227+
px,
228+
order_type={"limit": {"tif": "Ioc"}},
229+
reduce_only=False,
230+
cloid=cloid,
231+
builder=builder,
202232
)
203233

204234
def market_close(
@@ -417,14 +447,18 @@ def usd_class_transfer(self, amount: float, to_perp: bool) -> Any:
417447
"toPerp": to_perp,
418448
"nonce": timestamp,
419449
}
420-
signature = sign_usd_class_transfer_action(self.wallet, action, self.base_url == MAINNET_API_URL)
450+
signature = sign_usd_class_transfer_action(
451+
self.wallet, action, self.base_url == MAINNET_API_URL
452+
)
421453
return self._post_action(
422454
action,
423455
signature,
424456
timestamp,
425457
)
426458

427-
def sub_account_transfer(self, sub_account_user: str, is_deposit: bool, usd: int) -> Any:
459+
def sub_account_transfer(
460+
self, sub_account_user: str, is_deposit: bool, usd: int
461+
) -> Any:
428462
timestamp = get_timestamp_ms()
429463
sub_account_transfer_action = {
430464
"type": "subAccountTransfer",
@@ -445,7 +479,9 @@ def sub_account_transfer(self, sub_account_user: str, is_deposit: bool, usd: int
445479
timestamp,
446480
)
447481

448-
def sub_account_spot_transfer(self, sub_account_user: str, is_deposit: bool, token: str, amount: float) -> Any:
482+
def sub_account_spot_transfer(
483+
self, sub_account_user: str, is_deposit: bool, token: str, amount: float
484+
) -> Any:
449485
timestamp = get_timestamp_ms()
450486
sub_account_transfer_action = {
451487
"type": "subAccountSpotTransfer",
@@ -476,7 +512,9 @@ def vault_usd_transfer(self, vault_address: str, is_deposit: bool, usd: int) ->
476512
"usd": usd,
477513
}
478514
is_mainnet = self.base_url == MAINNET_API_URL
479-
signature = sign_l1_action(self.wallet, vault_transfer_action, None, timestamp, is_mainnet)
515+
signature = sign_l1_action(
516+
self.wallet, vault_transfer_action, None, timestamp, is_mainnet
517+
)
480518
return self._post_action(
481519
vault_transfer_action,
482520
signature,
@@ -485,7 +523,12 @@ def vault_usd_transfer(self, vault_address: str, is_deposit: bool, usd: int) ->
485523

486524
def usd_transfer(self, amount: float, destination: str) -> Any:
487525
timestamp = get_timestamp_ms()
488-
action = {"destination": destination, "amount": str(amount), "time": timestamp, "type": "usdSend"}
526+
action = {
527+
"destination": destination,
528+
"amount": str(amount),
529+
"time": timestamp,
530+
"type": "usdSend",
531+
}
489532
is_mainnet = self.base_url == MAINNET_API_URL
490533
signature = sign_usd_transfer_action(self.wallet, action, is_mainnet)
491534
return self._post_action(
@@ -513,7 +556,12 @@ def spot_transfer(self, amount: float, destination: str, token: str) -> Any:
513556

514557
def withdraw_from_bridge(self, amount: float, destination: str) -> Any:
515558
timestamp = get_timestamp_ms()
516-
action = {"destination": destination, "amount": str(amount), "time": timestamp, "type": "withdraw3"}
559+
action = {
560+
"destination": destination,
561+
"amount": str(amount),
562+
"time": timestamp,
563+
"type": "withdraw3",
564+
}
517565
is_mainnet = self.base_url == MAINNET_API_URL
518566
signature = sign_withdraw_from_bridge_action(self.wallet, action, is_mainnet)
519567
return self._post_action(
@@ -549,11 +597,20 @@ def approve_agent(self, name: Optional[str] = None) -> Tuple[Any, str]:
549597
def approve_builder_fee(self, builder: str, max_fee_rate: str) -> Any:
550598
timestamp = get_timestamp_ms()
551599

552-
action = {"maxFeeRate": max_fee_rate, "builder": builder, "nonce": timestamp, "type": "approveBuilderFee"}
553-
signature = sign_approve_builder_fee(self.wallet, action, self.base_url == MAINNET_API_URL)
600+
action = {
601+
"maxFeeRate": max_fee_rate,
602+
"builder": builder,
603+
"nonce": timestamp,
604+
"type": "approveBuilderFee",
605+
}
606+
signature = sign_approve_builder_fee(
607+
self.wallet, action, self.base_url == MAINNET_API_URL
608+
)
554609
return self._post_action(action, signature, timestamp)
555610

556-
def convert_to_multi_sig_user(self, authorized_users: List[str], threshold: int) -> Any:
611+
def convert_to_multi_sig_user(
612+
self, authorized_users: List[str], threshold: int
613+
) -> Any:
557614
timestamp = get_timestamp_ms()
558615
authorized_users = sorted(authorized_users)
559616
signers = {
@@ -565,14 +622,18 @@ def convert_to_multi_sig_user(self, authorized_users: List[str], threshold: int)
565622
"signers": json.dumps(signers),
566623
"nonce": timestamp,
567624
}
568-
signature = sign_convert_to_multi_sig_user_action(self.wallet, action, self.base_url == MAINNET_API_URL)
625+
signature = sign_convert_to_multi_sig_user_action(
626+
self.wallet, action, self.base_url == MAINNET_API_URL
627+
)
569628
return self._post_action(
570629
action,
571630
signature,
572631
timestamp,
573632
)
574633

575-
def multi_sig(self, multi_sig_user, inner_action, signatures, nonce, vault_address=None):
634+
def multi_sig(
635+
self, multi_sig_user, inner_action, signatures, nonce, vault_address=None
636+
):
576637
multi_sig_user = multi_sig_user.lower()
577638
multi_sig_action = {
578639
"type": "multiSig",

hyperliquid/utils/signing.py

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,32 @@
55
from eth_account.messages import encode_typed_data
66
from eth_utils import keccak, to_hex
77

8-
from hyperliquid.utils.types import Cloid, Literal, NotRequired, Optional, TypedDict, Union
8+
from hyperliquid.utils.types import (
9+
Cloid,
10+
Literal,
11+
NotRequired,
12+
Optional,
13+
TypedDict,
14+
Union,
15+
)
916

1017
Tif = Union[Literal["Alo"], Literal["Ioc"], Literal["Gtc"]]
1118
Tpsl = Union[Literal["tp"], Literal["sl"]]
1219
LimitOrderType = TypedDict("LimitOrderType", {"tif": Tif})
13-
TriggerOrderType = TypedDict("TriggerOrderType", {"triggerPx": float, "isMarket": bool, "tpsl": Tpsl})
14-
TriggerOrderTypeWire = TypedDict("TriggerOrderTypeWire", {"triggerPx": str, "isMarket": bool, "tpsl": Tpsl})
15-
OrderType = TypedDict("OrderType", {"limit": LimitOrderType, "trigger": TriggerOrderType}, total=False)
16-
OrderTypeWire = TypedDict("OrderTypeWire", {"limit": LimitOrderType, "trigger": TriggerOrderTypeWire}, total=False)
20+
TriggerOrderType = TypedDict(
21+
"TriggerOrderType", {"triggerPx": float, "isMarket": bool, "tpsl": Tpsl}
22+
)
23+
TriggerOrderTypeWire = TypedDict(
24+
"TriggerOrderTypeWire", {"triggerPx": str, "isMarket": bool, "tpsl": Tpsl}
25+
)
26+
OrderType = TypedDict(
27+
"OrderType", {"limit": LimitOrderType, "trigger": TriggerOrderType}, total=False
28+
)
29+
OrderTypeWire = TypedDict(
30+
"OrderTypeWire",
31+
{"limit": LimitOrderType, "trigger": TriggerOrderTypeWire},
32+
total=False,
33+
)
1734
OrderRequest = TypedDict(
1835
"OrderRequest",
1936
{
@@ -41,7 +58,15 @@
4158

4259
Grouping = Union[Literal["na"], Literal["normalTpsl"], Literal["positionTpsl"]]
4360
Order = TypedDict(
44-
"Order", {"asset": int, "isBuy": bool, "limitPx": float, "sz": float, "reduceOnly": bool, "cloid": Optional[Cloid]}
61+
"Order",
62+
{
63+
"asset": int,
64+
"isBuy": bool,
65+
"limitPx": float,
66+
"sz": float,
67+
"reduceOnly": bool,
68+
"cloid": Optional[Cloid],
69+
},
4570
)
4671

4772

@@ -222,7 +247,9 @@ def add_multi_sig_types(sign_types):
222247
}
223248
)
224249
if not enriched:
225-
print('"hyperliquidChain" missing from sign_types. sign_types was not enriched with multi-sig signing types')
250+
print(
251+
'"hyperliquidChain" missing from sign_types. sign_types was not enriched with multi-sig signing types'
252+
)
226253
return enriched_sign_types
227254

228255

@@ -234,7 +261,13 @@ def add_multi_sig_fields(action, payload_multi_sig_user, outer_signer):
234261

235262

236263
def sign_multi_sig_user_signed_action_payload(
237-
wallet, action, is_mainnet, sign_types, tx_type, payload_multi_sig_user, outer_signer
264+
wallet,
265+
action,
266+
is_mainnet,
267+
sign_types,
268+
tx_type,
269+
payload_multi_sig_user,
270+
outer_signer,
238271
):
239272
envelope = add_multi_sig_fields(action, payload_multi_sig_user, outer_signer)
240273
sign_types = add_multi_sig_types(sign_types)
@@ -248,7 +281,13 @@ def sign_multi_sig_user_signed_action_payload(
248281

249282

250283
def sign_multi_sig_l1_action_payload(
251-
wallet, action, is_mainnet, vault_address, timestamp, payload_multi_sig_user, outer_signer
284+
wallet,
285+
action,
286+
is_mainnet,
287+
vault_address,
288+
timestamp,
289+
payload_multi_sig_user,
290+
outer_signer,
252291
):
253292
envelope = [payload_multi_sig_user.lower(), outer_signer.lower(), action]
254293
return sign_l1_action(
@@ -407,11 +446,11 @@ def order_request_to_order_wire(order: OrderRequest, asset: int) -> OrderWire:
407446
return order_wire
408447

409448

410-
def order_wires_to_order_action(order_wires, builder=None):
449+
def order_wires_to_order_action(order_wires, builder=None, grouping: Grouping = "na"):
411450
action = {
412451
"type": "order",
413452
"orders": order_wires,
414-
"grouping": "na",
453+
"grouping": grouping,
415454
}
416455
if builder:
417456
action["builder"] = builder

0 commit comments

Comments
 (0)