Hyperliquid
Hyperliquid (Spot): The spot market of the Hyperliquid on-chain order book. Market data and account queries need only the wallet address; placing, canceling and amending orders are signed (EIP-712) with the API wallet (agent wallet) private key and need no on-chain gas. Perpetuals and HIP-3 / HIP-4 (Outcome) instruments are served by the Futures_Hyperliquid exchange object.
Futures_Hyperliquid (Futures): USDC-margined perpetuals on the Hyperliquid on-chain order book: perpetuals of the main dex, HIP-3 perpetuals (on builder-deployed dexes, codes carry a dex: prefix) and HIP-4 Outcome (prediction) instruments. Market data and account queries need only the wallet address; orders, cancels, amendments and leverage changes are signed (EIP-712) with the API wallet (agent wallet) private key and need no on-chain gas. Spot is served by the Hyperliquid exchange object.
See the Hyperliquid guide.
Names and Configuration
exchange.GetName() | Type | Aliases |
|---|---|---|
Hyperliquid | Spot | — |
Futures_Hyperliquid | Futures | HIP-3, HIP-4 |
✓ marks the exchange objects that have the field.
| Field | Hyperliquid | Futures_Hyperliquid | Required | Default | Description |
|---|---|---|---|---|---|
| Wallet Address | ✓ | ✓ | Yes | — | The main account wallet address (starting with 0x), used as the user of every query other than market data. |
| Wallet Private Key | ✓ | ✓ | No | — | The main account private key, optional. Used only to sign transfer actions (usdSend, withdraw3 and so on sent with exchange.IO("api", "POST", "/exchange", ...)); not needed for trading. |
| API Wallet Private Key | ✓ | Yes | — | The private key of an API wallet (agent wallet) created on the Hyperliquid "API" page, used to sign orders, cancels and amendments. Without it only market data and account queries work. | |
| Simulate (testnet) | ✓ | ✓ | No | Unchecked | Use the Hyperliquid testnet when checked; the API address becomes https://api.hyperliquid-testnet.xyz and trading and transfer actions are signed for the testnet (source is b). A configured node address is still used; the signing network follows the checkbox. |
| API Wallet Private Key | ✓ | Yes | — | The private key of an API wallet (agent wallet) created on the Hyperliquid "API" page, used to sign orders, cancels, amendments and leverage changes. Without it only market data and account queries work. |
Trading Pairs and Contract Codes
Hyperliquid (Spot)
Pair examples: HYPE_USDC, PURR_USDC
Pairs are written as COIN_QUOTE, using Hyperliquid spot token names (for example HYPE, PURR; bridged assets use the exchange's token name, such as UBTC), case-insensitive. The exchange's internal pair names such as @1 and @2 are resolved by the connector from the spot metadata and need not be used directly.
Futures_Hyperliquid (Futures)
Pair examples: BTC_USD, xyz:XYZ100_USD, BTC-above-100k---Dec_USD
Perpetual pairs are written as COIN_USD (COIN_USDC is accepted too; returned symbols always use USD), with USDC as margin, for example BTC_USD.swap. The connector restores the coin's case from the exchange's instrument list (such as kPEPE). HIP-3 pairs carry a dex prefix, kept lowercase, for example xyz:XYZ100_USD.swap.
A HIP-4 Outcome pair is the market name (spaces and / replaced by -) plus _USD, and the contract code is the name of the outcome side, for example BTC-above-100k---Dec_USD.Yes; when several markets share a name, -<market id> is appended to tell them apart (such as Recurring-1399_USD.Yes), and the bare name fails as ambiguous. exchange.GetMarkets() lists the available Outcome codes.
| Contract code | Description |
|---|---|
swap | Perpetual contract; the main dex and HIP-3 instruments are perpetual only. |
There are no delivery contracts. The contract code of an Outcome instrument is the outcome side name (such as Yes, No), not swap.
Exchange-specific IO Commands
Hyperliquid (Spot)
| Command | Arguments | Description | Returns |
|---|---|---|---|
walletAddress | address | Set the address used by read-only queries (assets, orders, order history), so another address's assets can be queried; the wallet that signs orders is unchanged. To query your own account again, pass the configured wallet address. | The address set. |
vaultAddress | address | Place, cancel and amend orders on behalf of a vault or sub-account (the address goes into the signature and the request body); an empty string clears it. Queries still use the wallet address; to query the vault's assets and orders, also set walletAddress to the vault address. | The address set. |
expiresAfter | timestamp | Set the expiresAfter carried by all subsequent signed actions (orders, cancels, amendments, ...), a Unix timestamp in milliseconds after which the exchange rejects the action; 0 clears it (the default). The value stays in effect, so every action after that time is rejected until it is set again or reset to 0. | The value set. |
source | "a" | "b" | The network used for signing: a is mainnet (the default; b when the Simulate (testnet) box is checked), b is testnet. (more below the table) | The value set. |
api | method, path[, params[, body]] | Call a Hyperliquid endpoint directly. (more below the table) | The raw exchange response. |
The rest of the longer descriptions in the table:
source: It sets thesourcefield of the Agent signature of trading actions and the chainId of the EIP-712 signature of transfer actions (usdSend,spotSend,withdraw3, ...): Arbitrum 42161 on mainnet, Arbitrum Sepolia 421614 on testnet. The API address is not changed; to connect to the testnet also switch it withexchange.IO("base", "https://api.hyperliquid-testnet.xyz").api: APOSTto/exchangetakes an action object, and the connector adds the nonce and signs it; transfer actions (usdSend,spotSend,withdraw3,usdClassTransfer,approveAgent,approveBuilderFee,userSetAbstraction) are signed with the wallet private keyWalletPrivateKey, and fields such ashyperliquidChainmust be filled in by the caller; other actions are signed with the API wallet private key. Other paths (such asPOST /info) are sent as they are, unsigned.body(a JSON object or a JSON string), when given, is the request body (the action for/exchange); otherwiseparamsis used as the body; abodyof any other type is an error.
For the common commands base and currency see exchange.IO.
Futures_Hyperliquid (Futures)
| Command | Arguments | Description | Returns |
|---|---|---|---|
cross | bool | Cross (true, the default) / isolated (false) margin. Only recorded by the connector, not per contract, and submitted together with the leverage on the next exchange.SetMarginLevel() call for any contract; the command itself sends no request. | cross or isolated. |
dex | name | Set the default HIP-3 dex name (without :, such as xyz; list the names with exchange.IO("api", "POST", "/info", {type: "perpDexs"})). (more below the table) | The dex name set (an empty string when cleared). |
walletAddress | address | Set the address used by read-only queries (account, positions, orders), so another address's positions can be queried; the wallet that signs orders is unchanged. To query your own account again, pass the configured wallet address. | The address set. |
vaultAddress | address | Place, cancel and amend orders and set leverage on behalf of a vault or sub-account (the address goes into the signature and the request body); an empty string clears it. Queries still use the wallet address; to query the vault's account and positions, also set walletAddress to the vault address. | The address set. |
expiresAfter | timestamp | Set the expiresAfter carried by all subsequent signed actions (orders, cancels, amendments, leverage changes, ...), a Unix timestamp in milliseconds after which the exchange rejects the action; 0 clears it (the default). The value stays in effect, so every action after that time is rejected until it is set again or reset to 0. | The value set. |
source | "a" | "b" | The network used for signing: a is mainnet (the default; b when the Simulate (testnet) box is checked), b is testnet. (more below the table) | The value set. |
split | symbol, amount | HIP-4 Outcome split (the splitOutcome action) of amount for the Outcome that symbol belongs to, into positions on each outcome side. (more below the table) | The raw exchange response (status is ok). |
merge | symbol[, amount] | HIP-4 Outcome merge (the mergeOutcome action) of the positions on each side of the Outcome that symbol belongs to; amount is optional, and when omitted or not above 0 the request carries no amount. | The raw exchange response (status is ok). |
mergeQuestion | symbol[, amount] | HIP-4 merge by question (the mergeQuestion action) for the question that the Outcome of symbol belongs to; amount is optional (when omitted or not above 0 the request carries no amount). Fails if the Outcome belongs to no question. | The raw exchange response (status is ok). |
negate | symbol, amount | HIP-4 negation (the negateOutcome action) of the Outcome of symbol within its question; amount must be greater than 0. Fails if the Outcome belongs to no question. | The raw exchange response (status is ok). |
api | method, path[, params[, body]] | Call a Hyperliquid endpoint directly. (more below the table) | The raw exchange response. |
The rest of the longer descriptions in the table:
dex: Once set, range queries without a symbol (GetPositions(),GetOrders(),GetConditionOrders(),GetTickers(),GetMarkets()) cover only this dex, whileGetTickers()andGetMarkets()still add all HIP-4 Outcome instruments. An empty string clears it and restores the default, where these queries gather the main dex and all HIP-3 dexes. Calls with a symbol always follow the symbol's own dex prefix. The name is not checked when set; an unknown name fails on the next range query.source: It sets thesourcefield of the Agent signature of trading actions and the chainId of the EIP-712 signature of transfer actions (usdSend,withdraw3,usdClassTransfer, ...): Arbitrum 42161 on mainnet, Arbitrum Sepolia 421614 on testnet. The API address is not changed; to connect to the testnet also switch it withexchange.IO("base", "https://api.hyperliquid-testnet.xyz"). The testnet has no HIP-3, so range queries cover the main dex only.split:symbolis an Outcome code (such asBTC-above-100k---Dec_USD.Yes), written as for market data and orders (markets sharing a name take the code with-<market id>(such asRecurring-1399_USD.Yes) and the bare name fails as ambiguous); thesymbolofmerge,mergeQuestionandnegatefollows the same rule.amountmust be greater than 0.api: APOSTto/exchangetakes an action object, and the connector adds the nonce and signs it; transfer actions (usdSend,spotSend,withdraw3,usdClassTransfer,approveAgent,approveBuilderFee,userSetAbstraction) are signed with the wallet private keyWalletPrivateKey, and fields such ashyperliquidChainmust be filled in by the caller; other actions are signed with the API wallet private key. Other paths (such asPOST /info) are sent as they are, unsigned.body(a JSON object or a JSON string), when given, is the request body (the action for/exchange); otherwiseparamsis used as the body; abodyof any other type is an error.
For the common commands base and currency see exchange.IO.
Common Usage
Query the Info endpoint with api and read another address's account
javascript
function main() {
// POST /info is unsigned; the params object is the request body
var mids = exchange.IO("api", "POST", "/info", {type: "allMids"})
Log("BTC mid:", mids["BTC"], "HYPE mid:", mids["HYPE"])
var meta = exchange.IO("api", "POST", "/info", {type: "spotMeta"})
Log("Spot tokens:", meta.tokens.length, "spot pairs:", meta.universe.length)
// Later account and order queries target this address (the HLP vault here); the wallet
// that signs orders is unchanged. Pass the configured wallet address to query your own
// account again
exchange.IO("walletAddress", "0xdfc24b077bc1425ad1dea75bcb6f8158e10df303")
Log("Account of that address:", exchange.GetAccount())
Log("Open orders of that address:", exchange.GetOrders())
}
Trade on behalf of a vault or sub-account
javascript
function main() {
var vault = "0x..." // replace with the vault or sub-account address
// Later orders, cancels and amendments are signed and sent on behalf of the vault
exchange.IO("vaultAddress", vault)
// Queries still use the wallet address; set it as well to query the vault
exchange.IO("walletAddress", vault)
Log("Vault account:", exchange.GetAccount())
var orders = exchange.GetOrders()
for (var i = 0; i < orders.length; i++) {
exchange.CancelOrder(orders[i].Id)
}
// An empty string clears it; later actions are the wallet's own again
exchange.IO("vaultAddress", "")
}
Give signed actions an expiry time
javascript
function main() {
// Later signed actions (orders, cancels, amendments, ...) expire in 10 seconds; the
// exchange rejects actions that arrive after that time
exchange.IO("expiresAfter", Date.now() + 10 * 1000)
var orders = exchange.GetOrders()
for (var i = 0; i < orders.length; i++) {
if (!exchange.CancelOrder(orders[i].Id)) {
Log("Cancel failed:", GetLastError())
}
}
// The value stays in effect; reset it to 0, or every later action is rejected
exchange.IO("expiresAfter", 0)
}
Send a transfer action with api, moving USDC between the spot and perpetual accounts
javascript
function main() {
// Transfer actions are signed with the "Wallet Private Key" option; the caller fills in
// hyperliquidChain, signatureChainId and the other fields
var r = exchange.IO("api", "POST", "/exchange", {
type: "usdClassTransfer",
hyperliquidChain: "Mainnet", // Testnet on the testnet
signatureChainId: "0xa4b1", // signing chain ID 42161; 0x66eee (421614) on testnet
amount: "10", // a string
toPerp: true, // true: spot to perp; false: perp to spot
nonce: Date.now()
})
Log(r)
}
List the HIP-3 dexes and query the instruments and positions of one of them (Futures_Hyperliquid only)
javascript
function main() {
// perpDexs: the first item is the main dex (null), followed by the HIP-3 dexes
var dexs = exchange.IO("api", "POST", "/info", {type: "perpDexs"})
var names = []
for (var i = 0; i < dexs.length; i++) {
if (dexs[i]) {
names.push(dexs[i].name)
}
}
Log("HIP-3 dexes:", names.join(", "))
// Later range queries without a symbol cover only xyz (GetMarkets and GetTickers
// always add the HIP-4 Outcome instruments)
exchange.IO("dex", "xyz")
var markets = exchange.GetMarkets()
var n = 0
for (var k in markets) {
if (k.indexOf("xyz:") == 0) {
n++
}
}
Log("Perpetuals on xyz:", n)
Log("Positions on xyz:", exchange.GetPositions())
// Calls with a symbol follow the symbol's own dex prefix, whatever IO("dex") says
Log(exchange.GetTicker("xyz:XYZ100_USD.swap"))
// An empty string clears it; range queries gather the main dex and all HIP-3 dexes again
exchange.IO("dex", "")
}
Find HIP-4 Outcome instruments and the questions they belong to (Futures_Hyperliquid only)
javascript
function main() {
// Rows of GetMarkets() with Info.isOutcome true are Outcome instruments, and
// Info.outcomeId is the Outcome number
var markets = exchange.GetMarkets()
var byId = {}
for (var k in markets) {
var info = markets[k].Info
if (info.isOutcome) {
byId[info.outcomeId] = byId[info.outcomeId] || []
byId[info.outcomeId].push(k)
}
}
// A question consists of several Outcomes (namedOutcomes) plus a fallback Outcome
var meta = exchange.IO("api", "POST", "/info", {type: "outcomeMeta"})
Log("Outcomes:", meta.outcomes.length, "questions:", meta.questions.length)
var q = meta.questions[0]
Log("Question", q.question, q.description)
for (var i = 0; i < q.namedOutcomes.length; i++) {
Log("Outcome", q.namedOutcomes[i], byId[q.namedOutcomes[i]])
}
Log("Fallback Outcome", q.fallbackOutcome, byId[q.fallbackOutcome])
var symbol = byId[q.namedOutcomes[0]][0]
Log(symbol, exchange.GetDepth(symbol))
}
Split, merge and negate HIP-4 Outcome positions (Futures_Hyperliquid only)
javascript
function main() {
var symbol = "BTC-above-100k---Dec_USD.Yes" // replace with an Outcome code of GetMarkets()
// Split: an amount of 10 into positions on each side of the Outcome; must be above 0
var r = exchange.IO("split", symbol, 10)
Log("split:", r ? r.status : GetLastError())
// Merge the positions on each side back; the amount may be omitted
r = exchange.IO("merge", symbol, 10)
Log("merge:", r ? r.status : GetLastError())
// negate and mergeQuestion only work for an Outcome that belongs to a question
r = exchange.IO("negate", symbol, 10)
Log("negate:", r ? r.status : GetLastError())
r = exchange.IO("mergeQuestion", symbol)
Log("mergeQuestion:", r ? r.status : GetLastError())
}
Function Support
Hyperliquid (Spot)
Not supported (the call fails with an error and returns null): exchange.CreateConditionOrder, exchange.ModifyConditionOrder, exchange.CancelConditionOrder, exchange.GetConditionOrder, exchange.GetConditionOrders, exchange.GetHistoryConditionOrders.
Served through a fallback:
exchange.GetRecords: Native periods are 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 8h, 12h, 1d, 3d, 1w, 1M; other periods are synthesized by the docker.
Futures_Hyperliquid (Futures)
No unsupported standard functions.
Served through a fallback:
exchange.GetRecords: Native periods are 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 8h, 12h, 1d, 3d, 1w; other periods are synthesized by the docker. Outcome instruments have no bars.
Margin, Account and Simulation
Futures_Hyperliquid (Futures)
Margin mode: Choose cross/isolated margin with exchange.IO("cross", bool); it is submitted together with the leverage on the next exchange.SetMarginLevel() (the exchange's updateLeverage action). The leverage is truncated to an integer. HIP-3 margin is kept per dex.
Position mode: One-way positions only. Closing orders (closebuy, closesell) are sent as reduce-only.
Account: For a unified account or portfolio margin account, the balance and equity of exchange.GetAccount() come from the spot USDC balance and the unrealized PnL from the perpetual account; a standard account reads the perpetual account (for HIP-3, the dex of the current symbol). The balance currency is USDC.
Notes
Hyperliquid (Spot)
- Market orders are sent as IOC orders priced at the mid price ±0.5%; the amount of a market buy is the number of coins to buy, not a quote-currency amount. An explicit
{type: "limit"}with a price of 0 or below is an error; it is never sent as a market order. - Order options go in the last object argument:
{tif: "ioc"}for IOC and{postOnly: true}for post-only (the exchange'sAlo, not allowed on market orders);fokis not supported on limit orders and fails.builder(builder fee,{b: builder address, f: integer fee}) andgroupingare merged into the order action and signed with it; other keys are ignored. - Prices allow at most 5 significant figures and at most 8 minus the coin's size decimals (szDecimals) decimal places; integer prices are always valid.
TickSizeandPricePrecisionofexchange.GetMarkets()are computed at the magnitude of the current price, so the tick changes when the price crosses a power of 10: for exampleHYPE_USDC(szDecimals 2) has a tick of 0.001 below 100 and 0.01 from 100 up. An order or amendment whose price breaks the rule fails with an error that gives the tick at that price and the nearest valid prices on both sides; the price is not rounded automatically. The protective price of a market order is rounded by the connector according to the rule. AvgPriceof an order is the actual average fill price aggregated per order from the exchange's fill records (userFillsByTime), and 0 when nothing is filled. For a few seconds after a fill the exchange's fill records may not be updated yet;AvgPriceis then 0 (or the average of the fills already recorded) and is accurate when queried again shortly afterwards. The exchange keeps only the latest 10000 fills, so orders filled earlier report 0. Fill records are queried only for filled orders, and the results are cached.- After a successful
exchange.ModifyOrder()the order ID changes; the return value is the new order ID. BuyandSellofexchange.GetTicker()are the best bid and ask (the mid price when one side is empty);Last,HighandLoware all the mid price, as the exchange has no 24h high/low.BuyandSellofexchange.GetTickers()are the mid price too.exchange.GetHistoryOrders()returns only the recent orders the exchange provides; thesinceparameter is not supported and asincegreater than 0 fails.
Futures_Hyperliquid (Futures)
- Market orders are sent as IOC orders priced at the mid price ±0.5%; for Outcome instruments ±1% (bounded to 0.001–0.999). A conditional order that executes at market after triggering is priced at the mid price ±0.5% as well. An explicit
{type: "limit"}with a price of 0 or below is an error; it is never sent as a market order. - Order options go in the last object argument:
{tif: "ioc"}for IOC and{postOnly: true}for post-only (the exchange'sAlo; an error on conditional orders and on market orders of Outcome instruments; other market orders are always IOC);fokis not supported on limit orders and fails.builder(builder fee,{b: builder address, f: integer fee}) andgroupingare merged into the order action and signed with it;orders(a non-empty array) replaces the order legs built by the connector entirely, with the legs written by the caller in the exchange's format; other keys are ignored. - Prices allow at most 5 significant figures and at most 6 minus the contract's size decimals (szDecimals) decimal places; integer prices are always valid.
TickSizeandPricePrecisionofexchange.GetMarkets()are computed at the magnitude of the current price, so the tick changes when the price crosses a power of 10. An order or amendment (including the order price of a conditional order) whose price breaks the rule fails with an error that gives the tick at that price and the nearest valid prices on both sides; the price is not rounded automatically. The protective price of a market order is rounded by the connector according to the rule. HIP-4 Outcome instruments are not checked locally. AvgPriceof orders and conditional orders is the actual average fill price aggregated per order from the exchange's fill records (userFillsByTime), and 0 when nothing is filled. For a few seconds after a fill the exchange's fill records may not be updated yet;AvgPriceis then 0 (or the average of the fills already recorded) and is accurate when queried again shortly afterwards. The exchange keeps only the latest 10000 fills, so orders filled earlier report 0. Fill records are queried only for filled orders, and the results are cached.- Conditional orders support take-profit and stop-loss, not OCO; take-profit and stop-loss are separate trigger orders. After a successful
exchange.ModifyOrder()orexchange.ModifyConditionOrder()the order ID changes; the return value is the new order ID. Lastofexchange.GetTicker()andexchange.GetTickers()is the mid price;BuyandSellare the exchange's bid/ask impact prices (not the best bid and ask; useexchange.GetDepth()for those), andHigh/Lowtake the same impact prices, as the exchange has no 24h high/low.exchange.GetFundings(): the main dex returns predicted funding rates (settled hourly); HIP-3 instruments need an explicit symbol and return the funding records of the last 24 hours.exchange.GetHistoryOrders()andexchange.GetHistoryConditionOrders()return only the recent orders the exchange provides; thesinceparameter is not supported and asincegreater than 0 fails.- HIP-4 Outcome instruments are spot-like holdings: trade them by buying and selling (integer amounts); reduce-only is not supported, so closing orders (
closebuy,closesell) fail; holdings come from the Outcome tokens in the spot account. Outcome instruments have no bars or funding rates, andLastofGetTicker()is the mid price whileBuyandSellare 0. An Outcome instrument the exchange has no mid price for yet (newly listed, not traded yet, and so on) is still listed byGetMarkets()(PricePrecisionis 4 andInfo.assetCtx.midPxisnull), is left out ofGetTickers(), and failsGetTicker()and market orders; a holding of it is valued at a mid price of 0 (Marginis 0 andProfitis minus the entry cost).