Hyperliquid Python SDK
Put Guard in front of the official Hyperliquid Python SDK with base_url. The exact arguments.
Before you change anything
Section titled “Before you change anything”- Read the setup journey and start Guard in paper mode.
- Keep your real account address. Give the bot a Guard client key, while the API wallet key stays inside Guard.
- Check the network and isolated-margin requirements in this guide. These integration instructions are planned and not verified against a released Guard yet.
The smallest change
Section titled “The smallest 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.
Read the response
Section titled “Read the response”The reply uses Hyperliquid’s response format. Check the returned status and order size rather than assuming the requested size was accepted. A refusal includes a readable reason and a veto code; a smaller accepted order reflects the rule that bound its size. Paper mode sends no venue order. Test this path before using testnet.
This page as plain Markdown, for people and LLMs: /docs/integrations/python-sdk.md