hyperliquid-orders
Installation
SKILL.md
Hyperliquid orders
Everything here ends in a signed request to /exchange. On this desk only the Execution Trader runs it, only on a ticket with a Risk PASS and the user's approval by id, and only once per approval (desk-execution-protocol). Reads used for reconciliation are in hyperliquid-account.
Concepts you must get right
- Asset index, not symbol. Perps use the index of the coin in
meta.universe(BTC is 0 on mainnet, but never hardcode: readmeta). Spot uses10000 + indexinspotMeta.universe. The Python SDK'sExchangeaccepts the coin name and resolves the index; the TS SDK wants the number. - Price rounding. At most 5 significant figures, and at most
6 - szDecimalsdecimal places for perps (8 - szDecimalsfor spot). Integer prices are always valid. Wrong precision is rejected by the exchange. - Size rounding. Round down to the market's
szDecimals. Never round up. - Minimum order value is 10 USD notional.
- Time in force:
Gtcrests until filled or cancelled;Iocfills what it can immediately and cancels the rest;Alo(add liquidity only) rests or is rejected if it would take. - There is no market order. A market-style order is an
Ioclimit at a price bounded by your slippage tolerance (buy: above mid; sell: below mid). - reduceOnly orders can only reduce an existing position; use it for exits, stops and take-profits.
- cloid (client order id) is
0x+ 32 hex characters (16 bytes). Unique per order. It lets you query and cancel an order even if the response was lost. - Trigger orders (
tp/sl):triggerPxis the mark price that arms the order;isMarket: trueexecutes market-style once triggered,falseplaces a limit atp.pis always required and acts as the worst-acceptable price after the trigger, so for market triggers set it beyond the trigger: a sell trigger'spbelowtriggerPx, a buy trigger'spabove it. A stop whosepequals its trigger can rest unfilled through a gap, so the desk defaults to a 5% bound for stop-losses (filling matters more than slippage) and 1% for take-profits; the app uses 10% for both. The ticket may override. - Grouping:
na(independent orders);normalTpsl(entry plus TP/SL as one-cancels-other tied to that entry: children are sized to the entry, placed only when it fills, cancelled if it is cancelled, and when one child fills the sibling is cancelled);positionTpsl(TP/SL tied to the position rather than to an order, shown as the position's own TP/SL,isPositionTpsl: true). Every TP/SL with an explicit size is fixed-size once placed; it does not resize when the position changes. The app's "entire position" TP/SL is a reduce-only trigger sent with size0underpositionTpslgrouping (such orders show up live infrontendOpenOrdersassz: "0.0",isPositionTpsl: true); rehearse it on testnet before the desk relies on it. - Responses: each order in an action gets a status:
{"resting": {"oid": ...}},{"filled": {"totalSz", "avgPx", "oid"}},"waitingForTrigger","waitingForFill", or{"error": "..."}. A top-level{"status": "err", "response": "..."}means the whole action was rejected.