Market making on Hyperliquid
Market making on Hyperliquid is post-only quoting on an on-chain book with no special terms, where repricing, reconciliation, nonces and shutdown decide survival.
Market making here means quoting both sides of an on-chain book on the same terms as everyone else. You earn the spread and any rebate, and you carry the inventory. Every quote and cancel is a consensus-ordered transaction, and the docs state there is no designated market maker programme, no special rebates or fees and no latency advantages.
Say you fill 10M USDC of maker volume at tier 0. You pay 0.015 per cent, 1,500 USDC; at the top rebate tier you’d receive 0.003 per cent, 300 USDC. The rest is spread, minus what informed flow takes.
Ordering is the edge every maker gets
Section titled “Ordering is the edge every maker gets”The docs say ordering protects makers from toxic flow and keeps spreads tight in volatile markets:
- Cancels and post-only orders sent at time
talmost always execute beforeIocandGtcsent att, across several blocks. - Within a consensus bundle, post-only orders and cancels run first.
What this means for you: a taker’s Ioc that arrives with your cancel usually meets the cancel first.
Quote post-only, in batches of their own
Section titled “Quote post-only, in batches of their own”Quote with Alo, the API’s post-only (order types): it never executes on arrival, so every fill is a maker fill. Validators prioritise all-post-only batches, so keep them apart from Ioc and Gtc; the docs suggest batching orders and cancels about every 0.1 s per process. A batch of n orders costs 1 IP request and n address requests; cancels get a higher ceiling, min(limit + 100000, limit * 2), so a rate-limited maker can still pull quotes.
Reprice in place with modify
Section titled “Reprice in place with modify”Use modify, not cancel then place: it’s one signed action, so the quote never leaves the book. A replacement that would cross is refused with Price would cross book.
a (always_place) |
The replacement |
|---|---|
| omitted | must be a non-trigger Alo, or a Gtc that would not execute, treated as Alo |
true |
is placed even if the cancel failed, say because the original filled: the maker holds the fill plus a fresh quote |
false, sent explicitly |
never lands: an action hashed with a: false is rejected |
The web interface’s chase order does this from the browser tab that created it: post-only, one tick inside the best bid or ask, up to 5 at once.
Track quotes by client order id
Section titled “Track quotes by client order id”modify returns a new order id, so track quotes by cloid, a 128-bit hex string: modify and batchModify accept it in place of the order id, and cancelByCloid cancels by it. Treat a timeout, 5xx or 429 as an unknown outcome and reconcile before resending: a blind retry can double a quote.
Every fill is inventory racing the price
Section titled “Every fill is inventory racing the price”Skew each fill away or hedge it elsewhere. Geography sets the floor, the hedge path the rest (latency).
| Measured by one production process in Europe | Value |
|---|---|
| Hyperliquid fill, by exchange timestamp, to completed hedge on an external venue | 350 to 500 ms |
| of which transit from Tokyo, where Hyperliquid’s API servers run | about 110 ms |
| the rest | four serialised HTTPS round trips to the hedge venue |
| after removing three of them in software | estimated 170 to 190 ms |
| a hedger handling one fill at a time, at 335 ms per hedge | saturates at 3 fills a second |
Pull every quote when you stop
Section titled “Pull every quote when you stop”Cancel everything on shutdown, or resting quotes fill while nothing hedges. Crashes skip shutdown code, so also arm scheduleCancel: it cancels every open order at time; renew it on a heartbeat, clear it by sending it without time. Send cancels with f: true: today it only refuses to cancel trigger orders, but the docs say a future upgrade will prioritise cancels in the mempool only when it is set, at no disadvantage.
One API wallet per process
Section titled “One API wallet per process”Nonces are per signing key, so processes sharing an API wallet, or one wallet across sub-accounts, collide on millisecond nonces. The docs’ fix is one API wallet per process and per sub-account, each with an atomic counter that can be fast-forwarded to the current millisecond. Never reuse an old API wallet address: once deregistered its nonce set can be pruned and its old signed actions replayed (nonces and agents).
The numbers
Section titled “The numbers”| Parameter | Value | Source |
|---|---|---|
| Perps maker fee, tier 0 to tier 3 | 0.015%, 0.012%, 0.008%, 0.004% | docs |
| Perps maker fee, tier 4 and above (over 500M USD 14-day weighted volume) | 0.000% | docs |
| Maker rebate, share of 14-day weighted maker volume over 0.5%, 1.5%, 3.0% | -0.001%, -0.002%, -0.003% | docs |
| 14-day weighted volume | perps volume + 2 x spot volume | docs |
| Rebate payment | continuously, on each trade, to the trading wallet | docs |
| Outcome markets | no rebates; accounts that would earn one pay zero on maker orders | docs |
| Chase reprice interval | at most once every 1,200 ms per order | production bot |
| Address rate limit | 1 request per 1 USDC traded, initial buffer 10,000; 1 request every 10 s once limited | docs |
| Open order limit | 1,000, plus 1 per 5 million USDC of volume, up to 5,000 | docs |
| Congestion limit | 2 x the previous day’s maker share of block space | docs |
scheduleCancel |
at least 5 s ahead; at most 10 triggers a day, counted from 00:00 UTC | docs |
| Nonce window | 100 highest per signer; a new nonce must exceed the smallest, be unused, and lie within 2 days behind, 1 day ahead of block time | docs |
| Post-only priority fee window | the tail of orders under 400 ms old at a level is sorted by fee | docs |
| Fill to external hedge, from Europe | 350 to 500 ms measured; about 110 ms of it transit | production bot |
Rebates are small and hard to reach
Section titled “Rebates are small and hard to reach”Below the rebate thresholds a maker pays a fee, reduced by volume tier and staking discount (fees).
| Market | Maker rebate |
|---|---|
| pairs between two spot quote assets | 80% less |
| HIP-3 markets in growth mode | at least 90% less |
| aligned quote assets | 50% better |
| outcome markets | none; Yes and No share one book (outcome markets) |
Your own orders never fill each other: the resting one is cancelled, with no fee and nothing in the trade feed (self-trade prevention).
A quoting loop that survives
Section titled “A quoting loop that survives”A chase step by cloid. Signed key order is type, oid, order, and a, b, p, s, r, t, c inside the order; prices and sizes are strings, trailing zeros stripped.
{ "type": "modify", "oid": "0x1234567890abcdef1234567890abcdef", "order": { "a": 0, "b": true, "p": "100.5", "s": "2", "r": false, "t": { "limit": { "tif": "Alo" } }, "c": "0x1234567890abcdef1234567890abcdef" }}- One API wallet and atomic nonce counter per process.
scheduleCancelarmed at start, renewed every heartbeat.Aloin post-only-only batches.modifybycloid, at most every 1,200 ms per order.- Fills from WebSocket
userFills, deduplicated on trade id. Its first frame is a snapshot: treated as new fills, it re-hedges. - Reconcile by
cloidafter any uncertain response. - On shutdown, cancel all with
f: true, then clear the schedule.
Keep market data on the WebSocket. One process polled /info into the per-IP limit and blocked its own order placement, which queried /info first; streaming the book cut it to about 0.15 requests a second. No Retry-After header is sent (rate limits).
Limits that bind a busy maker
Section titled “Limits that bind a busy maker”- Post-only priority fees are charged at placement, from undelegated staking balance on resting notional, filled or not.
- Congestion caps block space in high traffic, so resending cancels whose results already came back wastes the allowance.
- Use Standard mode, as the docs recommend for market makers (account modes): unified and portfolio margin allow 50k user actions a day, fewer than one every 1.7 seconds.
- Sub-accounts are separate users for address rate limits but share the master’s fee tier (sub-accounts).
For every order field used here, see Orders; for buying queue position, see Priority fees and the activation fee.