-
Notifications
You must be signed in to change notification settings - Fork 154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add docs to exchange API functions #58
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,34 +1,34 @@ | ||||||
import eth_account | ||||||
import logging | ||||||
import secrets | ||||||
|
||||||
import eth_account | ||||||
from eth_account.signers.local import LocalAccount | ||||||
|
||||||
from hyperliquid.api import API | ||||||
from hyperliquid.info import Info | ||||||
from hyperliquid.utils.constants import MAINNET_API_URL | ||||||
from hyperliquid.utils.signing import ( | ||||||
CancelRequest, | ||||||
CancelByCloidRequest, | ||||||
CancelRequest, | ||||||
ModifyRequest, | ||||||
OidOrCloid, | ||||||
OrderRequest, | ||||||
OrderType, | ||||||
OrderWire, | ||||||
OidOrCloid, | ||||||
ScheduleCancelAction, | ||||||
float_to_usd_int, | ||||||
get_timestamp_ms, | ||||||
order_request_to_order_wire, | ||||||
order_wires_to_order_action, | ||||||
sign_agent, | ||||||
sign_approve_builder_fee, | ||||||
sign_l1_action, | ||||||
sign_spot_transfer_action, | ||||||
sign_usd_class_transfer_action, | ||||||
sign_usd_transfer_action, | ||||||
sign_spot_transfer_action, | ||||||
sign_withdraw_from_bridge_action, | ||||||
sign_agent, | ||||||
) | ||||||
from hyperliquid.utils.types import Any, List, Meta, SpotMeta, Optional, Tuple, Cloid, BuilderInfo | ||||||
from hyperliquid.utils.types import Any, BuilderInfo, Cloid, List, Meta, Optional, SpotMeta, Tuple | ||||||
|
||||||
|
||||||
class Exchange(API): | ||||||
|
@@ -91,6 +91,19 @@ def order( | |||||
cloid: Optional[Cloid] = None, | ||||||
builder: Optional[BuilderInfo] = None, | ||||||
) -> Any: | ||||||
""" | ||||||
Places a single order. | ||||||
|
||||||
Args: | ||||||
name (str): The name of the asset to trade (not the asset ID). | ||||||
is_buy (bool): True for a buy order, False for a sell order. | ||||||
sz (float): The size of the order. | ||||||
limit_px (float): The limit price for the order. | ||||||
order_type (OrderType): The type of order (e.g., limit, market) along with the trigger. | ||||||
reduce_only (bool, optional): If True, the order will only reduce an existing position. Defaults to False. | ||||||
cloid (Optional[Cloid], optional): Client order ID. Defaults to None. | ||||||
builder (Optional[BuilderInfo], optional): Information about the builder. Defaults to None. | ||||||
""" | ||||||
order: OrderRequest = { | ||||||
"coin": name, | ||||||
"is_buy": is_buy, | ||||||
|
@@ -104,6 +117,16 @@ def order( | |||||
return self.bulk_orders([order], builder) | ||||||
|
||||||
def bulk_orders(self, order_requests: List[OrderRequest], builder: Optional[BuilderInfo] = None) -> Any: | ||||||
""" | ||||||
Place multiple orders in a single transaction. | ||||||
|
||||||
Args: | ||||||
order_requests (List[OrderRequest]): A list of order requests to be placed. | ||||||
builder (Optional[BuilderInfo], optional): Information about the builder. Defaults to None. | ||||||
|
||||||
Note: | ||||||
This function allows for more efficient placement of multiple orders compared to individual order calls. | ||||||
""" | ||||||
order_wires: List[OrderWire] = [ | ||||||
order_request_to_order_wire(order, self.info.name_to_asset(order["coin"])) for order in order_requests | ||||||
] | ||||||
|
@@ -136,6 +159,22 @@ def modify_order( | |||||
reduce_only: bool = False, | ||||||
cloid: Optional[Cloid] = None, | ||||||
) -> Any: | ||||||
""" | ||||||
Modify an existing order. | ||||||
|
||||||
Args: | ||||||
oid (OidOrCloid): The order ID or client order ID of the order to modify. | ||||||
name (str): The name of the asset being traded. | ||||||
is_buy (bool): True for a buy order, False for a sell order. | ||||||
sz (float): The new size of the order. | ||||||
limit_px (float): The new limit price for the order. | ||||||
order_type (OrderType): The new type of order (e.g., limit, market). | ||||||
reduce_only (bool, optional): If True, the order will only reduce an existing position. Defaults to False. | ||||||
cloid (Optional[Cloid], optional): New client order ID. Defaults to None. | ||||||
|
||||||
Note: | ||||||
This function is a wrapper around bulk_modify_orders_new for modifying a single order. | ||||||
""" | ||||||
modify: ModifyRequest = { | ||||||
"oid": oid, | ||||||
"order": { | ||||||
|
@@ -151,6 +190,15 @@ def modify_order( | |||||
return self.bulk_modify_orders_new([modify]) | ||||||
|
||||||
def bulk_modify_orders_new(self, modify_requests: List[ModifyRequest]) -> Any: | ||||||
""" | ||||||
Modify multiple existing orders in a single transaction. | ||||||
|
||||||
Args: | ||||||
modify_requests (List[ModifyRequest]): A list of modification requests for existing orders. | ||||||
|
||||||
Note: | ||||||
This function allows for more efficient modification of multiple orders compared to individual modify calls. | ||||||
""" | ||||||
timestamp = get_timestamp_ms() | ||||||
modify_wires = [ | ||||||
{ | ||||||
|
@@ -234,12 +282,43 @@ def market_close( | |||||
) | ||||||
|
||||||
def cancel(self, name: str, oid: int) -> Any: | ||||||
""" | ||||||
Cancel a single order. | ||||||
|
||||||
Args: | ||||||
name (str): The name of the asset for which the order was placed. | ||||||
oid (int): The order ID of the order to be cancelled. | ||||||
|
||||||
Note: | ||||||
This function is a wrapper around bulk_cancel for cancelling a single order. | ||||||
""" | ||||||
return self.bulk_cancel([{"coin": name, "oid": oid}]) | ||||||
|
||||||
def cancel_by_cloid(self, name: str, cloid: Cloid) -> Any: | ||||||
""" | ||||||
Cancel a single order using the client order ID. | ||||||
|
||||||
Args: | ||||||
name (str): The name of the asset for which the order was placed. | ||||||
cloid (Cloid): The client order ID of the order to be cancelled. | ||||||
|
||||||
Note: | ||||||
This function is a wrapper around bulk_cancel_by_cloid for cancelling a single order. | ||||||
""" | ||||||
return self.bulk_cancel_by_cloid([{"coin": name, "cloid": cloid}]) | ||||||
|
||||||
def bulk_cancel(self, cancel_requests: List[CancelRequest]) -> Any: | ||||||
""" | ||||||
Cancel multiple orders in a single transaction. | ||||||
|
||||||
Args: | ||||||
cancel_requests (List[CancelRequest]): A list of cancellation requests, each containing | ||||||
the asset name and order ID to be cancelled. | ||||||
|
||||||
Note: | ||||||
This function allows for more efficient cancellation of multiple orders compared to | ||||||
individual cancel calls. | ||||||
""" | ||||||
timestamp = get_timestamp_ms() | ||||||
cancel_action = { | ||||||
"type": "cancel", | ||||||
|
@@ -266,6 +345,18 @@ def bulk_cancel(self, cancel_requests: List[CancelRequest]) -> Any: | |||||
) | ||||||
|
||||||
def bulk_cancel_by_cloid(self, cancel_requests: List[CancelByCloidRequest]) -> Any: | ||||||
""" | ||||||
Cancel multiple orders using client order IDs in a single transaction. | ||||||
|
||||||
Args: | ||||||
cancel_requests (List[CancelByCloidRequest]): A list of cancellation requests, each containing | ||||||
the asset name and client order ID to be cancelled. | ||||||
|
||||||
|
||||||
Note: | ||||||
This function allows for more efficient cancellation of multiple orders using client order IDs | ||||||
compared to individual cancel calls. | ||||||
""" | ||||||
timestamp = get_timestamp_ms() | ||||||
|
||||||
cancel_action = { | ||||||
|
@@ -293,12 +384,19 @@ def bulk_cancel_by_cloid(self, cancel_requests: List[CancelByCloidRequest]) -> A | |||||
) | ||||||
|
||||||
def schedule_cancel(self, time: Optional[int]) -> Any: | ||||||
"""Schedules a time (in UTC millis) to cancel all open orders. The time must be at least 5 seconds after the current time. | ||||||
Once the time comes, all open orders will be canceled and a trigger count will be incremented. The max number of triggers | ||||||
per day is 10. This trigger count is reset at 00:00 UTC. | ||||||
""" | ||||||
Schedules a time (in UTC millis) to cancel all open orders. | ||||||
|
||||||
Args: | ||||||
time (int): if time is not None, then set the cancel time in the future. If None, then unsets any cancel time in the future. | ||||||
time (Optional[int]): If provided, sets the cancel time in the future (UTC milliseconds). | ||||||
If None, unsets any previously scheduled cancel time. | ||||||
|
||||||
Note: | ||||||
- The scheduled time must be at least 5 seconds after the current time. | ||||||
- Once the scheduled time arrives, all open orders will be canceled. | ||||||
- A trigger count is incremented each time this action is executed. | ||||||
- The maximum number of triggers per day is 10. | ||||||
- The trigger count is reset at 00:00 UTC daily. | ||||||
""" | ||||||
timestamp = get_timestamp_ms() | ||||||
schedule_cancel_action: ScheduleCancelAction = { | ||||||
|
@@ -421,12 +519,12 @@ def usd_class_transfer(self, amount: float, to_perp: bool) -> Any: | |||||
|
||||||
# Deprecated in favor of usd_class_transfer | ||||||
def user_spot_transfer(self, usdc: float, to_perp: bool) -> Any: | ||||||
usdc = int(round(usdc, 2) * 1e6) | ||||||
usdc_rounded_micros = int(round(usdc, 2) * 1e6) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer not making this rename. usdc has 6 decimals so this is the actual amount of usdc and is not rounded. Perhaps the input should have been usd instead of usdc, but renaming it now would be a breaking change |
||||||
timestamp = get_timestamp_ms() | ||||||
spot_user_action = { | ||||||
"type": "spotUser", | ||||||
"classTransfer": { | ||||||
"usdc": usdc, | ||||||
"usdc": usdc_rounded_micros, | ||||||
"toPerp": to_perp, | ||||||
}, | ||||||
} | ||||||
|
@@ -481,6 +579,18 @@ def vault_usd_transfer(self, vault_address: str, is_deposit: bool, usd: int) -> | |||||
) | ||||||
|
||||||
def usd_transfer(self, amount: float, destination: str) -> Any: | ||||||
""" | ||||||
Initiate a USD transfer to a specified destination address. | ||||||
|
||||||
This function creates and signs a USD transfer action, then sends it for processing. | ||||||
|
||||||
Args: | ||||||
amount (float): The amount of USD to transfer. | ||||||
destination (str): The destination address (EVM compatible) for the transfer. | ||||||
|
||||||
Returns: | ||||||
{'status': 'ok', 'response': {'type': 'default'}} | ||||||
""" | ||||||
timestamp = get_timestamp_ms() | ||||||
action = {"destination": destination, "amount": str(amount), "time": timestamp, "type": "usdSend"} | ||||||
is_mainnet = self.base_url == MAINNET_API_URL | ||||||
|
@@ -492,6 +602,20 @@ def usd_transfer(self, amount: float, destination: str) -> Any: | |||||
) | ||||||
|
||||||
def spot_transfer(self, amount: float, destination: str, token: str) -> Any: | ||||||
""" | ||||||
Initiate a spot transfer of a specific token to a specified destination address. | ||||||
|
||||||
This function creates and signs a spot transfer action for a given token, then sends it | ||||||
for processing. | ||||||
|
||||||
Args: | ||||||
amount (float): The amount of the token to transfer. | ||||||
destination (str): The destination address (EVM compatible) for the transfer. | ||||||
token (str): The identifier of the token to be transferred (e.g., "BTC", "ETH"). | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These example tokens are not spot tokens. Also the token identifier is a different format
Suggested change
|
||||||
|
||||||
Returns: | ||||||
{'status': 'ok', 'response': {'type': 'default'}} | ||||||
""" | ||||||
timestamp = get_timestamp_ms() | ||||||
action = { | ||||||
"destination": destination, | ||||||
|
@@ -509,6 +633,18 @@ def spot_transfer(self, amount: float, destination: str, token: str) -> Any: | |||||
) | ||||||
|
||||||
def withdraw_from_bridge(self, amount: float, destination: str) -> Any: | ||||||
""" | ||||||
Initiate a withdrawal from the Hyperliquid bridge to a specified destination. | ||||||
|
||||||
Args: | ||||||
amount (float): The amount to withdraw. This should be in the base unit of the asset | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I found this confusing. All withdrawals are in USDC
Suggested change
|
||||||
(e.g., USDC for USD-based withdrawals). | ||||||
destination (str): The destination address for the withdrawal. This should be a valid | ||||||
EVM address. | ||||||
|
||||||
Returns: | ||||||
{'status': 'ok', 'response': {'type': 'default'}} | ||||||
""" | ||||||
timestamp = get_timestamp_ms() | ||||||
action = {"destination": destination, "amount": str(amount), "time": timestamp, "type": "withdraw3"} | ||||||
is_mainnet = self.base_url == MAINNET_API_URL | ||||||
|
@@ -520,6 +656,24 @@ def withdraw_from_bridge(self, amount: float, destination: str) -> Any: | |||||
) | ||||||
|
||||||
def approve_agent(self, name: Optional[str] = None) -> Tuple[Any, str]: | ||||||
"""Approve a new agent for the user's account and generate a new agent key. | ||||||
|
||||||
Creates a new agent with a randomly generated key, approves it for use with | ||||||
the user's account, and returns both the approval response and the new agent's private key. | ||||||
|
||||||
Args: | ||||||
name (Optional[str], optional): A name for the agent. If not provided, an empty string will be used. | ||||||
|
||||||
Returns: | ||||||
Tuple[Any, str]: A tuple containing two elements: | ||||||
- Any: {'status': 'ok', 'response': {'type': 'default'}} | ||||||
- str: The newly generated agent's private key as a hexadecimal string. | ||||||
|
||||||
Note: | ||||||
- The generated agent key is a 32-byte random value, represented as a 64-character hexadecimal string. | ||||||
- The agent's Ethereum address is derived from this key and included in the approval action. | ||||||
- If no name is provided, the 'agentName' field will be omitted from the approval action. | ||||||
""" | ||||||
agent_key = "0x" + secrets.token_hex(32) | ||||||
account = eth_account.Account.from_key(agent_key) | ||||||
timestamp = get_timestamp_ms() | ||||||
|
@@ -544,6 +698,12 @@ def approve_agent(self, name: Optional[str] = None) -> Tuple[Any, str]: | |||||
) | ||||||
|
||||||
def approve_builder_fee(self, builder: str, max_fee_rate: str) -> Any: | ||||||
"""Approve a maximum fee rate for a builder. | ||||||
|
||||||
Args: | ||||||
builder (str): address in 42-character hexadecimal format | ||||||
max_fee_rate (str): the maximum allowed builder fee rate as a percent string; e.g. "0.001%" | ||||||
""" | ||||||
timestamp = get_timestamp_ms() | ||||||
|
||||||
action = {"maxFeeRate": max_fee_rate, "builder": builder, "nonce": timestamp, "type": "approveBuilderFee"} | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found having a separate bullet is confusing. The trigger count is incremented when the scheduled time arrives, not when this action is sent.