Expand description
Hyperliquid spot trading ExecutionClient implementation.
Uses the same hyperliquid_rust_sdk clients as the perpetuals client, but with
spot-specific endpoints and data handling.
§Differences from Perpetuals
- Coin naming: Spot pairs are named
@{index}("@107"is HYPE/USDC), except"PURR/USDC"; perps by their asset ("BTC"). See Spot coins. - Asset indices: Spot uses 10000+ (vs 0-9999 for perps)
- Balances: Uses
user_token_balances()instead ofuser_state()margin summary - No positions: a spot order opens no position. Under portfolio margin it can still
borrow, implicitly, when the account falls short; there is no order flag for it, so this
client refuses every
RequestOpen::margin_effect(OrderError::UnsupportedMarginEffect) - $10 minimum: Spot orders require minimum $10 notional value
§Unified Account Model
Hyperliquid uses a unified account model:
- Spot balances count as perpetual collateral
- Separate wallets within the unified account (explicit transfer required)
- Perpetual liquidation cannot sweep spot holdings
§WebSocket Events
UserFills and OrderUpdates subscriptions deliver both spot and perp events,
intermingled in the same stream. Events are filtered by the shape of the coin name, with
CoinKind::of: this client keeps only spot coins ("@107", "PURR/USDC").
If a user has both perp and spot clients for the same wallet, events will be duplicated. Consumers should use one client type per account, or deduplicate externally.
§Spot coins
Hyperliquid names every spot pair but PURR/USDC by its index ("@107"), which does not name
its assets. The client reads Hyperliquid’s spotMeta when it is created, and fails to be
created if it cannot, and resolves each coin through it to the instrument BASE-QUOTE-SPOT,
named from the pair’s tokens ("@107" is HYPE-USDC-SPOT, "@207" is HYPE-USDT0-SPOT).
A spot coin missing from spotMeta, such as a pair listed after the client was created, makes
it read spotMeta again, at most once every ten seconds, each read abandoned after five. A coin still missing after that is:
- an error from
ExecutionClient::account_snapshot,ExecutionClient::fetch_open_ordersandExecutionClient::fetch_trades, whose lists would otherwise be short with nothing to say so. This holds whichever instruments were asked for: the coin’s instrument is unknown, so it cannot be told apart from them; - left out of the account stream, logged once per stream and coin, with
error!for fills andwarn!for order updates.ExecutionClient::fetch_tradesrecovers a fill left out once the pair resolves.
Since every report names a pair from its tokens as Hyperliquid spells them, an order’s
instrument must spell them the same way: kPEPE-USDC-SPOT, not KPEPE-USDC-SPOT.
ExecutionClient::open_order refuses an order under another spelling unsent, with
ApiError::InstrumentInvalid naming the one to
use. An order is then reported under the name it was placed under, and the reads that take
instruments, which match names exactly, find it. The perpetuals client matches names
exactly too.
Neither the reads nor cancel_order check the spelling. An instruments filter naming a pair
in another spelling, or no listed pair, matches nothing, so the read returns nothing for it
without an error. ExecutionClient::cancel_order sends the coin as the instrument spells it, so a
cancel under another spelling fails in the SDK.
Orders are placed through the SDK’s ExchangeClient, which reads spotMeta once, when it is
created, and is never refreshed. So a pair listed after the client was created can be reported
but not traded until the client is created again.
§Conditional Orders (Stop, TakeProfit)
See super module documentation for conditional order support details.
The same constraints apply to spot:
- Supported:
Stop,StopLimit,TakeProfit,TakeProfitLimit - Unsupported:
TrailingStop,TrailingStopLimit,Market
§Client order ids
As for perpetuals, every order must be placed under a client id in
ClientOrderId::uuid() form. See the
super module documentation for why.
Structs§
- Hyperliquid
Spot Client - Hyperliquid spot trading execution client.