๐ŸŽ“ Tutorials

Hyperliquid Python SDK Tutorial: Build a Bot (2026)

โš ๏ธ Disclosure: Some links on this page are affiliate links. If you sign up through them, I may earn a commission โ€” at no extra cost to you. I only review tools I actually use.
# Hyperliquid Python SDK Tutorial: Build a Bot (2026)

> About this guide: I'm Lawrence, the writer behind supa.is. Between February and May 2026 I've published 150+ articles on supa.is across crypto and brokerage tooling โ€” including 30+ Hyperliquid-specific guides (recent examples: Hyperliquid getting started, Cross vs isolated margin on Hyperliquid, Hyperliquid zero-fee assets). The most-repeated reader question across that Hyperliquid archive is exactly how to wire the official Python SDK to a working perp bot without losing keys or getting rate-limited, which is why I'm publishing this standardized guide instead of answering one-off.

> Note: Code patterns below are reconstructed from the official Hyperliquid Python SDK (github.com/hyperliquid-dex/hyperliquid-python-sdk) and the Hyperliquid developer docs (hyperliquid.gitbook.io/hyperliquid-docs) as of 2026-04. SDK method names and request shapes change between releases โ€” pin your dependency, read the upstream CHANGELOG.md, and verify every snippet against the current SDK before pointing it at real funds.

Why use the Python SDK at all

You can talk to Hyperliquid in three ways: the official Python SDK, raw HTTPS POSTs against the documented /info and /exchange endpoints, or the WebSocket feed. The SDK is a thin wrapper that handles three things you genuinely don't want to write yourself:

1. EIP-712 message signing. Every order, cancel, and transfer on Hyperliquid is a signed action โ€” not just an authenticated REST call. Getting the typed-data structure, chain ID, and signing primitive wrong silently rejects orders with cryptic "User or API Wallet ... does not exist" errors.

2. Tick/lot rounding. Each perp has a pxDecimals and szDecimals constraint enforced by the matching engine. Submitting 0.1234567 when the symbol allows three decimals returns a generic error. The SDK's meta() payload tells you the precision per symbol โ€” verify against the current Hyperliquid developer docs (hyperliquid.gitbook.io/hyperliquid-docs) before relying on cached values. 3. Nonce and signature replay protection. The SDK auto-increments the nonce per signing wallet so you don't accidentally reuse one and get an order silently dropped.

If you're building a discretionary alert bot, raw HTTP works. If you're placing thousands of orders a day or running a market-maker, the SDK saves a week of debugging. The rest of this article assumes the SDK route.

Installation and project layout

The SDK is on PyPI as hyperliquid-python-sdk (PyPI page):

pip install hyperliquid-python-sdk

Pin the version in requirements.txt or pyproject.toml rather than tracking latest โ€” the SDK occasionally renames symbols between minor versions, and a silent upgrade in CI can break a live bot at 3 a.m.

Top-level modules you'll touch most:

ModulePurpose
hyperliquid.infoRead-only market data, user state, fills history
hyperliquid.exchangePlace/cancel orders, transfer USDC, update leverage
hyperliquid.utils.constantsMAINNET_API_URL, TESTNET_API_URL
hyperliquid.utils.signingLower-level signing helpers (rarely needed directly)
hyperliquid.websocket_managerStreaming subscriptions to L2 books, trades, user events
A minimal bot typically has one Info client (for polling), one Exchange client (for sending orders), and one WebsocketManager (for live state).

The API wallet model โ€” read this before generating any keys

This section is where most first-time bot developers lose money. Hyperliquid uses an API wallet (also called an agent wallet) abstraction โ€” search for "API wallets" or "agents" in the Hyperliquid docs to find the canonical reference. The mechanism is also encoded directly in the SDK's examples/ folder in the SDK repo.

Mental model:

This split is the difference between "a server compromise costs you whatever's in your perp account" and "a server compromise costs you everything in your wallet, on every chain."

In code, the pattern looks like this:

import eth_account
from hyperliquid.exchange import Exchange
from hyperliquid.info import Info
from hyperliquid.utils import constants

main_wallet_address = "0xYourMainWalletAddress"
api_wallet_secret   = "0xPrivateKeyOfTheAGENTWalletYouAuthorized"

agent = eth_account.Account.from_key(api_wallet_secret)

info = Info(constants.MAINNET_API_URL, skip_ws=True)
exchange = Exchange(
    wallet=agent,
    base_url=constants.MAINNET_API_URL,
    account_address=main_wallet_address,
)

Three things to verify before you run this:

1. The address derived from api_wallet_secret is not the same as main_wallet_address. If you accidentally put your main key into api_wallet_secret, the SDK will happily sign with it and you've negated the entire safety story.

2. The agent wallet has been authorized in the Hyperliquid UI under the API tab. Unauthorized agents return "User or API Wallet ... does not exist". 3. Your account_address (the main wallet) matches the wallet you authorized the agent for. The signing wallet and the funded wallet are different โ€” the SDK separates them via account_address.

For a refresher on the underlying account model and how isolated margin behaves under the same main wallet, the margin-mode comparison explains why you might want one agent per sub-strategy.

Reading market data with Info

The Info client wraps the public read endpoints described in the Hyperliquid developer docs. Common calls during a bot's hot path:

meta = info.meta()                       # all perp metadata: szDecimals, maxLeverage, etc.
all_mids = info.all_mids()               # latest mid prices keyed by symbol
user_state = info.user_state(main_wallet_address)
open_orders = info.open_orders(main_wallet_address)
fills = info.user_fills(main_wallet_address)

meta() is the one you care about at startup. Each entry has szDecimals (size precision) and maxLeverage, and you should cache it. Submitting an order whose size doesn't conform to szDecimals is a silent rejection in many SDK versions โ€” the matching engine returns an error string the SDK passes through, and rookie bots log it as "weird API blip" and retry forever.

user_state returns the canonical view of your account: margin summary, asset positions, withdrawable USDC. Use this โ€” not your bot's internal accounting โ€” as the source of truth after every fill.

For historical data, info.candles_snapshot(coin, interval, start_ms, end_ms) returns OHLCV bars. The interval set is fixed (1m, 3m, 5m, 15m, 1h, 4h, 1d, 1w as documented in the SDK source) โ€” you can't request 7-minute bars; resample yourself.

Placing orders with Exchange

The Exchange client wraps the signed write endpoints. The single most common call:

result = exchange.order(
    name="ETH",
    is_buy=True,
    sz=0.1,
    limit_px=2500.0,
    order_type={"limit": {"tif": "Gtc"}},
    reduce_only=False,
)

๐Ÿ’ก Hyperliquid

Like what you're reading? Try it yourself โ€” this link supports ChartedTrader at no cost to you.

Open a Hyperliquid account (4% fee discount on first $25M of volume) โ†’
๐ŸŽ You receive: 4% fee discount on first $25M volume ยท per account, lifetime

A few things that aren't obvious from the signature:

The result dict needs to be parsed carefully. A successful submission returns:

{"status": "ok", "response": {"type": "order", "data": {"statuses": [{"resting": {"oid": 12345678}}]}}}

But a partially filled order looks like:

{"status": "ok", "response": {"type": "order", "data": {"statuses": [{"filled": {"oid": ..., "totalSz": "0.05", "avgPx": "2500.1"}}]}}}

And a rejection looks like:

{"status": "ok", "response": {"type": "order", "data": {"statuses": [{"error": "Insufficient margin"}]}}}

Note that the outer status is still "ok" even when the inner status is error. This is the single most common silent-bug source in beginner Hyperliquid bots: code checks result["status"] == "ok" and assumes the order made it. Always inspect result["response"]["data"]["statuses"][i].

Managing positions, leverage, and transfers

Setting leverage before a trade:

exchange.update_leverage(leverage=3, name="ETH", is_cross=True)

Closing a position is just an opposite-side reduce_only=True order. There is no dedicated "close" method โ€” reduce_only is the contract.

USDC transfers between perp and spot wallets, and between cross/isolated margin sub-accounts, also live on Exchange:

exchange.usd_transfer(amount=100.0, destination=main_wallet_address)

Note that the agent wallet cannot withdraw to a different address โ€” that operation requires a signature from the main wallet. This is the safety guarantee from the previous section made concrete.

If you plan to scale up volume, the Hyperliquid 4% fee discount math covers how the per-account $25M referral cap interacts with HYPE-staking discounts โ€” both apply automatically as long as your main wallet was registered through a referral link, no SDK setting required.

WebSocket subscriptions for live state

For anything beyond a slow polling loop, use the WebSocket feed:

from hyperliquid.websocket_manager import WebsocketManager

ws = WebsocketManager(constants.MAINNET_API_URL)
ws.start()

def on_l2(msg):
    print(msg["data"]["levels"])

ws.subscribe({"type": "l2Book", "coin": "ETH"}, on_l2)
ws.subscribe({"type": "userEvents", "user": main_wallet_address}, lambda m: print(m))

Useful subscription types:

ChannelWhat you get
l2BookOrder book snapshots and updates per coin
tradesPublic trade prints
userEventsYour fills, funding payments, liquidations
userFillsJust fills (lighter than userEvents)
candleOHLC bars, useful for low-latency strategy ticks
Two practical notes: WebSockets disconnect โ€” wrap your WebsocketManager in a supervisor that reconnects and re-subscribes on close. And reconcile your in-memory state against info.user_state() periodically; missed messages do happen, especially during spikes.

Rate limits, error handling, and idempotency

Search the Hyperliquid developer docs for the current rate-limit numbers and verify before sizing your strategy โ€” they have changed across releases. Three patterns from production hold across versions:

1. Batch where possible. exchange.bulk_orders([...]) submits multiple orders in one signed action and counts as a single rate-limit unit. A market-maker placing 20 quotes per second should never call order() 20 times.

2. Use cloid for idempotency. Pass a client order ID (cloid) on every order() call. If your bot crashes mid-send and you retry, the matching engine will reject the duplicate by cloid rather than placing two orders. Generate a UUID per intent and log it before sending. 3. Don't busy-poll user_state from the hot path. Many beginner bots call info.user_state() after every order to "confirm." This eats your read-budget and lags behind WebSocket userFills anyway. Confirm via WebSocket; treat user_state as a slow reconciliation tool every 30โ€“60 seconds.

Ten pitfalls that cost beginner bots money

1. Confusing main wallet and agent wallet โ€” covered above. The single highest-stakes mistake.

2. Not pinning the SDK version. A pip install --upgrade in a deploy script can silently change a method signature. 3. Treating result["status"] == "ok" as success. The inner statuses list is the real signal. 4. Submitting non-tick-aligned prices. Always round limit_px to the symbol's pxDecimals. 5. Using Gtc when you meant Alo. Gtc will cross the book and pay taker fees if your price is aggressive โ€” silently turning a maker strategy into a taker strategy. 6. Ignoring funding rate accruals. Funding is paid hourly on perps; if you carry positions overnight without modeling it, your post-fee P&L will diverge from your simulated P&L. 7. No cloid on retries. Network-flaky deploys end up with duplicate orders. 8. Hardcoding asset indexes. Indexes shift when new perps list โ€” always look up by symbol via meta(). 9. WebSocket without a watchdog. Disconnections that don't auto-reconnect leave a bot trading on stale state. 10. Testing on mainnet "just to be sure." Testnet (constants.TESTNET_API_URL) is a near-clone of mainnet for SDK behaviour. Use it.

SDK vs raw HTTP: when to drop down

ConcernSDKRaw HTTP
EIP-712 signingHandledYou implement
Symbol โ†’ asset index lookupAuto via meta()You cache and refresh
Tick rounding helpersBuilt inYou write them
Custom transports (e.g. aiohttp connection pooling)LimitedFull control
Footprint in a Lambda cold-startHeavierMinimal
Multi-language stack (e.g. Rust signing, Python orchestration)Forces Python signing pathCleaner separation
Rule of thumb: start on the SDK. Drop to raw HTTP only if profiling shows the SDK is the bottleneck (rare) or if you genuinely need a custom transport.

Production checklist before pointing it at real USDC

If you're still working through wallet setup, USDC bridging, and your first hand-placed perp before automating any of this, the Hyperliquid getting-started walkthrough and the post-signup setup checklist cover the prerequisite manual flow.

Where the affiliate fits

If you don't yet have a funded Hyperliquid main wallet, sign up via this Hyperliquid referral link. The referral fee discount is set at registration โ€” you can't backfill it onto an account that signed up without a referral. For most retail bot operators that's a real, multi-month saving on taker fees, and it stacks with the HYPE-staking fee tier when you eventually qualify. For the exact discount math against the per-account volume cap (as of 2026-04), see the Hyperliquid 4% fee discount cap explainer โ€” and always verify the current numbers in the Hyperliquid docs before sizing a strategy around them.

Build it on testnet first, keep your main key cold, and let the agent wallet do the talking.

`

๐Ÿงฎ Free Hyperliquid calculators

Fee Calculator โ†’
Hyperliquid vs centralized exchange fee comparison
PnL & Liquidation โ†’
Perp PnL + liquidation price
Position Size โ†’
Risk-aware position sizing for HL perps
Hyperliquid

Ready to get started? Use the link below โ€” it helps support ChartedTrader at no cost to you.

Open a Hyperliquid account (4% fee discount on first $25M of volume) โ†’
๐ŸŽ You receive: 4% fee discount on first $25M volume ยท per account, lifetime
๐Ÿ“ˆ

About the author

I'm a systematic trader running live strategies on IB (USDJPY momentum) and Hyperliquid (crypto perps). Every tool reviewed here is something I've used with real capital. Questions? Reach out.

๐Ÿ“š Related Articles

๐ŸŽ“ Tutorials

TradingView Paper Trading Without Real Money (2026)

Practice trading on TradingView with $100K paper money โ€” setup, realistic commissions, common beginner mistakes, when to switch to real cash.

May 5, 2026 โฑ 12 min read
๐ŸŽ“ Tutorials

How to Trade Solana (SOL) Perpetual Futures on OKX: CLI and Web Guide (2026)

Complete guide to trading SOL perpetual futures on OKX using the CLI and web interface. Covers market data, position management, trailing stops, grid bots, and DCA bots โ€” all commands tested on okx-cli v1.2.3.

March 14, 2026 โฑ 13 min read
๐ŸŽ“ Tutorials

OpenClaw + Xerolite: Set Up an AI Trading Bot for Interactive Brokers โ€” Step-by-Step (2026)

Learn how to connect OpenClaw AI to Interactive Brokers through Xerolite and place real stock trades with natural language. Full setup walkthrough with IB Gateway, API permissions, and security best practices.

March 13, 2026 โฑ 11 min read

๐Ÿ“ฌ Get weekly trading insights

Real trades, honest reviews, no fluff. One email per week.