BlogDeveloper

Hyperliquid Tick Size and Lot Size: Round Prices and Sizes

Hyperliquid tick size and lot size rules: 5 significant figures, szDecimals, the $10 perp minimum, and a Python function that rounds orders correctly.

HydromancerTeam
Hyperliquid Tick Size and Lot Size: Round Prices and Sizes banner

"Order has invalid price." If your bot gets this back from Hyperliquid, or "Price must be divisible by tick size", nothing is wrong with your strategy.

The price or size just wasn't rounded the way Hyperliquid expects, and the fix is a few lines of code.

Hyperliquid tick size: rules, not a fixed tick

On most centralized exchanges (CEXs), each market has a fixed tick size you look up once. Hyperliquid uses rules instead:

Tick size on Hyperliquid Tick size on a typical CEX
Price stepSet by a rule: at most 5
significant figures, plus a
decimals cap
A fixed step per market
When it changesAutomatically, as the price
moves
When the exchange updates
the market
Whole-number pricesAlways validDepends on the market
Minimum order$10 on perps, 10 of the
quote token on spot
Varies by market

So you can't store one tick per market. You store the rule and apply it to every order.

The fix takes three steps:

  1. Read szDecimals, the number that sets each market's limits.
  2. Round prices and sizes before you send them.
  3. Read the errors the exchange returns when an order breaks a rule.

Market values are a snapshot from when we tested.

The rules

Perps Spot
Significant figures in a priceAt most 5At most 5
Decimal places in a priceAt most 6 − szDecimalsAt most 8 − szDecimals
Whole-number pricesAlways validAlways valid
Decimal places in a sizeAt most szDecimalsAt most the base token's
szDecimals
Minimum order value$1010 of the quote token

The rules come from Hyperliquid's tick and lot size docs. Their own examples:

  • 1234.5 is valid; 1234.56 isn't (six significant figures).
  • 0.001234 is valid on a perp; 0.0012345 isn't (seven decimals, more than 6 − 0).
  • 123456 is valid even though 12345.6 isn't, because whole numbers skip the significant-figure limit.

So what is the tick size?

Because of the 5-significant-figure rule, the price step depends on the price. Before the decimals cap, it's:

Price Step from 5 significant figures
10,000 and above1
1,000 up to 10,0000.1
100 up to 1,0000.01
10 up to 1000.001
Below 10Smaller, until the decimals
cap stops it

The decimals cap can make the step coarser. BTC, with szDecimals 5, can never go finer than 0.1. At low prices, the cap usually wins. kPEPE, at about $0.0044 with szDecimals 0, can only use 6 decimals, so its step is 0.000001. Don't store one tick per market; store the rule.

Lot size is the size step: 1 ÷ 10^szDecimals. BTC has szDecimals 5, so sizes move in steps of 0.00001 BTC. The $10 minimum usually binds first.

About the snippets: like our docs, they're excerpts. They assume Python with requests installed and imported, with the SDK's exchange client for the order example.

Step 1: Read szDecimals for each market

Every rule above depends on one number per market: szDecimals, the number of decimal places a size may have. It also sets the price decimals cap. Perps keep it in meta. Spot keeps it per token in spotMeta, and the one that counts is the base token's:

code
meta = requests.post(INFO, json={"type": "meta"}).json()
mids = requests.post(INFO, json={"type": "allMids"}).json()
for a in meta["universe"]:
    n = a["name"]
    if n in ("BTC", "ETH", "HYPE", "kPEPE"):
        print(f"{n:6} szDecimals={a['szDecimals']}  mid={mids[n]}")
code
BTC    szDecimals=5  mid=80606.5
ETH    szDecimals=4  mid=2340.45
kPEPE  szDecimals=0  mid=0.004392
HYPE   szDecimals=2  mid=77.1165

INFO is Hyperliquid's info endpoint, https://api.hyperliquid.xyz/info. For HIP-3 markets, add the DEX name: {"type": "meta", "dex": "xyz"}. Load this at startup, and refresh it as new markets list.

Step 2: Round prices and sizes before you send

With szDecimals in hand, round every price and size right before the order goes out. This function applies both price rules, keeping whichever allows fewer decimals (never fewer than zero, so whole numbers always pass), and rounds sizes down. It uses Decimal so floating-point errors can't add stray digits:

code
from decimal import Decimal, ROUND_HALF_UP, ROUND_DOWN

def round_price(px, sz_decimals, max_decimals=6):  # 6 perps, 8 spot
    px = Decimal(str(px))
    decimals = max(min(max_decimals - sz_decimals, 4 - px.adjusted()), 0)
    return px.quantize(Decimal(1).scaleb(-decimals), rounding=ROUND_HALF_UP)

def round_size(sz, sz_decimals):
    step = Decimal(1).scaleb(-sz_decimals)
    return Decimal(str(sz)).quantize(step, rounding=ROUND_DOWN)

Here's what it does to a limit buy 1% below the mid, worth $25, on real markets:

Market szDecimals Price you computed Price to send Size you computed Size to send
BTC579800.435798000.000313281…0.00031
ETH42317.14452317.10.010789141…0.0107
HYPE276.35226576.3520.327429710…0.32
kPEPE00.00434610.0043465752.28…5752
HMSTR00.000140580.000141177834.68…177834

The function doesn't check the $10 minimum, so check price × size after rounding.

Step 3: Read what the exchange says

To see the difference rounding makes, here's the same BTC order sent twice with the Python SDK: first as computed, then rounded. We sent it on testnet, so no real money was at risk:

code
sz = float(round_size(0.000301234, 5))  # BTC, about $12
for px in (40867.53, round_price(40867.53, 5)):  # as computed, then rounded
    r = exchange.order("BTC", True, sz, float(px), {"limit": {"tif": "Gtc"}})
    print(px, r["response"]["data"]["statuses"][0])
code
40867.53 {'error': 'Order has invalid price.'}
40868 {'resting': {'oid': 63656385802}}

exchange is the SDK's Exchange client, set up on testnet as in our testnet guide. The resting order was cancelled straight after.

Errors you may see, and their usual cause:

Error Usual cause Fix
Price must be divisible by tick size.More than 5 significant
figures
round_price
Order has invalid price.Too many decimal placesround_price
Order has invalid size.More decimals than
szDecimals
round_size
Order must have minimum value of $10.Order worth under $10Raise the size

Most order errors come back inside each order's status, even when the top level says "ok". Some are rejected for the whole request, so check both levels. The full list is in Hyperliquid's error docs.

How Hydromancer's API comes in

Rounding is a Hyperliquid rule, so the rounding itself doesn't change with Hydromancer. What changes is where your bot reads market data from:

What you need Without Hydromancer (Hyperliquid's API only) With Hydromancer's API
meta, spotMeta and allPerpMetasFrom Hyperliquid, sharing
1,200 weight a minute per IP
with every other read
The same requests, with a
separate per-key budget:
5,000, 20,000 or 50,000
weight a minute by plan, per
our rate limits docs
Placing the rounded orderHyperliquid's exchange APIThe same: orders always go
to Hyperliquid

If your bot already reads its data from Hydromancer, load szDecimals from there too, and keep your Hyperliquid budget for order-related reads.

What to know

  • Round mids before using them as prices. A mid can fall between two ticks.
  • Round sizes yourself. Don't rely on the exchange to round a size with too many decimals.
  • **szDecimals can differ between testnet and mainnet** for the same coin, so read it from the network you trade on.
  • HIP-3 markets follow the perp rules. Their szDecimals comes from meta with the DEX name.

FAQ

What is the tick size on Hyperliquid?

There's no fixed tick per market. Prices can have at most 5 significant figures, so the step depends on the price: $1 above $10,000, $0.1 from $1,000 up to $10,000, and so on. The decimals cap of 6 − szDecimals on perps can make it coarser.

What is szDecimals?

The number of decimal places a size may have on that market. It also sets the price decimals cap. Find it in meta for perps and spotMeta for spot.

Why do I get "Order has invalid price" with only 5 significant figures?

Because the decimals cap applies too. On a perp with szDecimals 0, 0.0022335 has 5 significant figures but 7 decimals. Round it to 0.002234.

How do I calculate the price step on Hyperliquid?

Work out the step allowed by 5 significant figures, and the step forced by the decimals cap of 6 − szDecimals places on perps (8 − szDecimals on spot). Use the larger of the two steps; whole-number prices are always allowed. For BTC at $80,000 that gives a $1 step. The round_price function above does it for any market.

Are the tick size rules the same on testnet and mainnet?

The rules are the same, but szDecimals can differ between the two networks for the same coin. Read it from the network you trade on.

What is the minimum order size on Hyperliquid?

$10 on perps, or 10 of the quote token on spot. Sizes move in steps of 1 ÷ 10^szDecimals.

Continue