Hyperliquid Python SDK
Put Guard in front of the official Hyperliquid Python SDK with base_url. The exact arguments.
The change
Section titled “The change”Exchange takes a base_url argument (Exchange.__init__(wallet, base_url=None, meta=None, vault_address=None, account_address=None, spot_meta=None, perp_dexs=None, timeout=None)). It also builds its own Info client from the same URL.
exchange = Exchange(api_wallet, constants.MAINNET_API_URL, account_address=ACCOUNT)exchange = Exchange(guard_client_key, "http://127.0.0.1:8547", account_address=ACCOUNT)Full example
Section titled “Full example”from eth_account import Accountfrom hyperliquid.exchange import Exchangefrom hyperliquid.info import Info
GUARD = "http://127.0.0.1:8547"ACCOUNT = "0xYourAccountAddress" # your main account
client_key = Account.from_key("0x...") # the client key Guard printedinfo = Info(GUARD, skip_ws=True)exchange = Exchange(client_key, GUARD, account_address=ACCOUNT)
# The entry and its stop in one request, grouping "normalTpsl".entry = {"coin": "ETH", "is_buy": True, "sz": 2.0, "limit_px": 2500.0, "order_type": {"limit": {"tif": "Gtc"}}, "reduce_only": False}stop = {"coin": "ETH", "is_buy": False, "sz": 2.0, "limit_px": 2300.0, "order_type": {"trigger": {"triggerPx": 2400.0, "isMarket": True, "tpsl": "sl"}}, "reduce_only": True}result = exchange.bulk_orders([entry, stop], grouping="normalTpsl")print(result) # Guard's decision comes back in Hyperliquid's formatfilled in from your settings ·
Guard sizes the entry from the stop at 2,400. If it resizes the entry, it resizes the stop with it. Without a stop the entry is refused under the default rules (why).
The arguments
Section titled “The arguments”| Argument | Value | Note |
|---|---|---|
wallet | an eth_account account made from the Guard client key | not your API wallet key |
base_url | Guard’s URL | used for /exchange and, through Info, for /info |
account_address | your Hyperliquid account | the account the client key trades for |
vault_address | leave unset | vaults are not supported by Guard yet |
Things to know
Section titled “Things to know”- Network in the signature. The SDK signs as mainnet only when
base_url == MAINNET_API_URL("https://api.hyperliquid.xyz"); for any other URL it signs with the testnet source"b"(construct_phantom_agentinsigning.py). Pointed at Guard, it always signs as testnet. Guard is planned to accept that and to sign the real order for the network Guard is set to (why it is safe). - WebSocket.
Info(GUARD)withoutskip_ws=Trueopens a WebSocket at Guard’s URL. Guard is planned to pass market-data subscriptions through. Until that is verified, useskip_ws=True, or open the WebSocket to Hyperliquid directly: market data needs no key. - Builder argument.
order()andbulk_orders()take an optionalbuilder. Leave it unset; Guard adds its own.
This page as plain Markdown, for people and LLMs: /docs/integrations/python-sdk.md