Skip to content

Hyperliquid Python SDK

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)
from eth_account import Account
from hyperliquid.exchange import Exchange
from 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 printed
info = 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 format

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).

ArgumentValueNote
walletan eth_account account made from the Guard client keynot your API wallet key
base_urlGuard’s URLused for /exchange and, through Info, for /info
account_addressyour Hyperliquid accountthe account the client key trades for
vault_addressleave unsetvaults are not supported by Guard yet
  • 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_agent in signing.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) without skip_ws=True opens a WebSocket at Guard’s URL. Guard is planned to pass market-data subscriptions through. Until that is verified, use skip_ws=True, or open the WebSocket to Hyperliquid directly: market data needs no key.
  • Builder argument. order() and bulk_orders() take an optional builder. Leave it unset; Guard adds its own.