Prerequisites
- Python 3.8 or higher
hyperliquid-python-sdkinstalled (pip install hyperliquid-python-sdk)- Reliable Hyperliquid RPC endpoint (sign up for free)
Understanding Hyperliquid’s WebSocket architecture
Hyperliquid provides two essential WebSocket channels for monitoring trading activity. These channels serve different purposes:orderUpdates delivers WsOrder[] events containing order status changes—when orders are placed, modified, or canceled. This is your primary signal for mirroring trading decisions.
userEvents provides WsUserEvent data including fills, funding payments, and liquidations. For this tutorial, the most important part is that the channel provides TWAP order updates not available in orderUpdates.
Together, these channels give you a complete picture of a trader’s activity:
How spot markets work on Hyperliquid
Before diving into implementation, you need to understand how Hyperliquid distinguishes spot from perpetual assets. Thecoin field format tells you the market type:
Perpetual contracts use simple asset names returned from the meta endpoint:
BTC— Bitcoin perpetualETH— Ethereum perpetualSOL— Solana perpetual
@{index}— numeric spot pair index (for example,@0for BTC/USDC,@107for HYPE/USDC){TOKEN}/USDC— human-readable pair names (for example,PURR/USDC)
@index format? It’s Hyperliquid’s internal representation—more efficient for the order book engine. When you receive WebSocket events, the coin field typically contains the @index format for spot trades.
This matters for copy trading because:
- You receive
@123in WebSocket events - You need to query metadata using that index
- You place orders using the same
@indexformat
spotMeta endpoint, which provides crucial information like price precision and size decimals.
Detecting spot vs perpetual orders
Your bot monitors a trader who trades both spot and perps. Spot orders are cash trades (you own the asset), perps involve leverage and funding payments. For simplicity, you might want to mirror only spot trades initially. Thecoin field in WebSocket events tells you the market type:
@ or contains /, it’s a spot market. Otherwise, it’s a perpetual contract.
Filter to spot-only mirroring:
Dynamic order sizing for spot assets
A leader might trade $10,000 of BTC, but your bot has a $1,000 budget. You need proportional sizing based on your capital allocation. But it’s not just about scaling down—Hyperliquid enforces strict precision rules. According to the official documentation: Size precision — Round to the asset’sszDecimals (found in meta response):
szDecimals = 3:1.001valid,1.0001invalidszDecimals = 1:0.1valid,0.01invalid
MAX_DECIMALS - szDecimals decimal places (spot: MAX_DECIMALS = 8, perps: MAX_DECIMALS = 6):
szDecimals = 0:0.0001234valid (8 decimals)szDecimals = 2:0.0001234invalid (exceeds 8-2=6 decimals)1234.5valid,1234.56invalid (too many sig figs)
szDecimals = 5 → 0.00023076923... rounds to 0.00023.
Understanding order lifecycle and state transitions
Orders on Hyperliquid go through a lifecycle with specific state transitions. When you subscribe toorderUpdates, you receive events for each state change.
Order state events explained
open status — A new order has been placed on the book by the leader.
canceled status — Order removed from the book, either by:
- Trader manually canceling
- Part of a modification (old order canceled, new order created with different ID)
- System cancellation (insufficient balance, delisting, etc.)
filled status — Order fully executed. You’ll also see detailed fill information in the userEvents channel.
How order modifications work
When a trader modifies an order on Hyperliquid (changes price or size), the exchange handles this atomically as:- Cancel the existing order (you receive
"canceled"event) - Create a new order with the new parameters (you receive
"open"event with new order ID)
order_mappings dictionary tracks active orders by mapping each leader order ID to your corresponding follower order ID. This allows you to cancel the correct follower order when the leader cancels
Placing orders with the Hyperliquid SDK
The hyperliquid-python-sdk provides theexchange.order() method for placing trades. Let’s break down each parameter and why it matters:
resting and filled? If you place a limit buy at $100 and the best ask is $99, your order fills immediately. You still need the order ID for tracking fills and state management.
Order successfully placed and order ID received for tracking
Testing with same wallet (development only)
This section describes a development shortcut for testing. In production, you’ll use separate leader and follower wallets, and this infinite loop problem won’t exist.
1
Leader places order
The leader wallet (your test wallet) initiates a new order
2
Bot mirrors it as follower
Your bot detects the order and places a mirror order using the same wallet
3
Bot sees its own follower order
WebSocket receives the follower order as a “new leader order” (because you’re watching the same wallet)
4
Bot tries to mirror again
Bot attempts to mirror the follower order, creating another order
5
Infinite loop
Process repeats indefinitely, placing unlimited orders
{leader_order_id: follower_order_id}. Later, when that follower order appears in the WebSocket feed (because you’re watching your own wallet), you check: “Is this order ID in my follower list?” If yes, ignore it.
Important: In production with separate wallets, leader and follower order IDs never overlap—you don’t need this check. This is purely for development convenience.
Sequential processing (simplified for testing)
This section describes a simplified architecture for testing. In production with high-frequency trading, you’d process events in parallel with proper concurrency controls.
- Process multiple order events simultaneously
- Requires locks/semaphores to prevent race conditions
- Optimal for high-frequency traders placing hundreds of orders per minute
- More complex to implement and debug
- Process one order event at a time
- No race conditions by design
- Simple to implement and reason about
- Sufficient for mirroring human traders (10-100 orders per hour)
Summary
Copy trading on Hyperliquid requires tracking order state through WebSocket subscriptions, mapping spot assets via@index format, and calculating properly rounded order sizes using metadata. Order modifications are handled as cancel + create events, eliminating the need for special modification logic. For production, use separate leader and follower wallets with concurrent event processing.
Complete implementation: See the Chainstack Hyperliquid trading bot repository for the full working code.
Related resources
- Authentication guide — Authenticate with Hyperliquid exchange API
- L1 action signing — Understand L1 action signing for trading operations
- API reference — Explore the complete Hyperliquid API reference
- Node configuration — Configure your Hyperliquid node endpoint