Hyperliquid Ruby SDK
A Ruby SDK for interacting with the Hyperliquid decentralized exchange API.
The SDK supports both read operations (Info API) and authenticated write operations (Exchange API) for trading.
Installation
Add this line to your application's Gemfile:
gem 'hyperliquid'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install hyperliquid
Usage
Basic Setup
require 'hyperliquid'
# Create SDK instance for read-only operations (mainnet by default)
sdk = Hyperliquid.new
# Or use testnet
testnet_sdk = Hyperliquid.new(testnet: true)
# Access the Info API (read operations)
info = sdk.info
# For trading operations, provide a private key
trading_sdk = Hyperliquid.new(
testnet: true,
private_key: ENV['HYPERLIQUID_PRIVATE_KEY']
)
# Access the Exchange API (write operations)
exchange = trading_sdk.exchange
Supported APIs
The SDK provides access to the following Hyperliquid APIs:
Info Methods
all_mids()- Retrieve mids for all coinsopen_orders(user)- Retrieve a user's open ordersfrontend_open_orders(user, dex: nil)- Retrieve a user's open orders with additional frontend infouser_fills(user)- Retrieve a user's fillsuser_fills_by_time(user, start_time, end_time = nil)- Retrieve a user's fills by time (optional end time)user_rate_limit(user)- Query user rate limitsorder_status(user, oid)- Query order status by order id (oid)order_status_by_cloid(user, cloid)- Query order status by client order id (cloid)l2_book(coin)- L2 book snapshot (Perpetuals and Spot)candles_snapshot(coin, interval, start_time, end_time)- Candle snapshot (Perpetuals and Spot)max_builder_fee(user, builder)- Check builder fee approvalhistorical_orders(user, start_time = nil, end_time = nil)- Retrieve a user's historical ordersuser_twap_slice_fills(user, start_time = nil, end_time = nil)- Retrieve a user's TWAP slice fillsuser_subaccounts(user)- Retrieve a user's subaccountsvault_details(vault_address, user = nil)- Retrieve details for a vaultuser_vault_equities(user)- Retrieve a user's vault depositsuser_role(user)- Query a user's roleportfolio(user)- Query a user's portfolioreferral(user)- Query a user's referral informationuser_fees(user)- Query a user's fees and fee scheduledelegations(user)- Query a user's staking delegationsdelegator_summary(user)- Query a user's staking summarydelegator_history(user)- Query a user's staking historydelegator_rewards(user)- Query a user's staking rewards
Perpetuals Methods
perp_dexs()- Retrieve all perpetual DEXsmeta(dex: nil)- Get asset metadata (optionally for a specific perp DEX)meta_and_asset_ctxs()- Get extended asset metadatauser_state(user, dex: nil)- Retrieve user's perpetuals account summary (optionally for a specific perp DEX)predicted_fundings()- Retrieve predicted funding rates across venuesperps_at_open_interest_cap()- Query perps at open interest capsperp_deploy_auction_status()- Retrieve Perp Deploy Auction statusactive_asset_data(user, coin)- Retrieve a user's active asset data for a coinperp_dex_limits(dex)- Retrieve builder-deployed perp market limits for a DEXuser_funding(user, start_time, end_time = nil)- Retrieve a user's funding history (optional end time)user_non_funding_ledger_updates(user, start_time, end_time = nil)- Retrieve a user's non-funding ledger updates. Non-funding ledger updates include deposits, transfers, and withdrawals. (optional end time)funding_history(coin, start_time, end_time = nil)- Retrieve historical funding rates (optional end time)
Spot Methods
spot_meta()- Retrieve spot metadata (tokens and universe)spot_meta_and_asset_ctxs()- Retrieve spot metadata and asset contextsspot_balances(user)- Retrieve a user's spot token balancesspot_deploy_state(user)- Retrieve Spot Deploy Auction informationspot_pair_deploy_auction_status()- Retrieve Spot Pair Deploy Auction statustoken_details(token_id)- Retrieve information about a token by tokenId
Examples: Info
# Retrieve mids for all coins
mids = sdk.info.all_mids
# => { "BTC" => "50000", "ETH" => "3000", ... }
user_address = "0x..."
# Retrieve a user's open orders
orders = sdk.info.open_orders(user_address)
# => [{ "coin" => "BTC", "sz" => "0.1", "px" => "50000", "side" => "A" }]
# Retrieve a user's open orders with additional frontend info
frontend_orders = sdk.info.frontend_open_orders(user_address)
# => [{ "coin" => "BTC", "isTrigger" => false, ... }]
# Retrieve a user's fills
fills = sdk.info.user_fills(user_address)
# => [{ "coin" => "BTC", "sz" => "0.1", "px" => "50000", "side" => "A", "time" => 1234567890 }]
# Retrieve a user's fills by time
start_time_ms = 1_700_000_000_000
end_time_ms = start_time_ms + 86_400_000
fills_by_time = sdk.info.user_fills_by_time(user_address, start_time_ms, end_time_ms)
# => [{ "coin" => "ETH", "px" => "3000", "time" => start_time_ms }, ...]
# Query user rate limits
rate_limit = sdk.info.user_rate_limit(user_address)
# => { "nRequestsUsed" => 100, "nRequestsCap" => 10000 }
# Query order status by oid
order_id = 12345
status_by_oid = sdk.info.order_status(user_address, order_id)
# => { "status" => "filled", ... }
# Query order status by cloid
cloid = "client-order-id-123"
status_by_cloid = sdk.info.order_status_by_cloid(user_address, cloid)
# => { "status" => "cancelled", ... }
# L2 order book snapshot
book = sdk.info.l2_book("BTC")
# => { "coin" => "BTC", "levels" => [[asks], [bids]], "time" => ... }
# Candle snapshot
candles = sdk.info.candles_snapshot("BTC", "1h", start_time_ms, end_time_ms)
# => [{ "t" => ..., "o" => "50000", "h" => "51000", "l" => "49000", "c" => "50500", "v" => "100" }]
# Check builder fee approval
builder_address = "0x..."
fee_approval = sdk.info.max_builder_fee(user_address, builder_address)
# => { "approved" => true, ... }
# Retrieve a user's historical orders
hist_orders = sdk.info.historical_orders(user_address)
# => [{ "oid" => 123, "coin" => "BTC", ... }]
hist_orders_ranged = sdk.info.historical_orders(user_address, start_time_ms, end_time_ms)
# => []
# Retrieve a user's TWAP slice fills
twap_fills = sdk.info.user_twap_slice_fills(user_address)
# => [{ "sliceId" => 1, "coin" => "ETH", "sz" => "1.0" }, ...]
twap_fills_ranged = sdk.info.user_twap_slice_fills(user_address, start_time_ms, end_time_ms)
# => []
# Retrieve a user's subaccounts
subaccounts = sdk.info.user_subaccounts(user_address)
# => ["0x1111...", ...]
# Retrieve details for a vault
vault_addr = "0x..."
vault = sdk.info.vault_details(vault_addr)
# => { "vaultAddress" => vault_addr, ... }
vault_with_user = sdk.info.vault_details(vault_addr, user_address)
# => { "vaultAddress" => vault_addr, "user" => user_address, ... }
# Retrieve a user's vault deposits
vault_deposits = sdk.info.user_vault_equities(user_address)
# => [{ "vaultAddress" => "0x...", "equity" => "123.45" }, ...]
# Query a user's role
role = sdk.info.user_role(user_address)
# => { "role" => "tradingUser" }
# Query a user's portfolio
portfolio = sdk.info.portfolio(user_address)
# => [["day", { "pnlHistory" => [...], "vlm" => "0.0" }], ...]
# Query a user's referral information
referral = sdk.info.referral(user_address)
# => { "referredBy" => { "referrer" => "0x..." }, ... }
# Query a user's fees
fees = sdk.info.user_fees(user_address)
# => { "userAddRate" => "0.0001", "feeSchedule" => { ... } }
# Query a user's staking delegations
delegations = sdk.info.delegations(user_address)
# => [{ "validator" => "0x...", "amount" => "100.0" }, ...]
# Query a user's staking summary
summary = sdk.info.delegator_summary(user_address)
# => { "delegated" => "12060.16529862", ... }
# Query a user's staking history
history = sdk.info.delegator_history(user_address)
# => [{ "time" => 1_736_726_400_073, "delta" => { ... } }, ...]
# Query a user's staking rewards
rewards = sdk.info.delegator_rewards(user_address)
# => [{ "time" => 1_736_726_400_073, "source" => "delegation", "totalAmount" => "0.123" }, ...]
Note: l2_book and candles_snapshot work for both Perpetuals and Spot. For spot, use "{BASE}/USDC" when available (e.g., "PURR/USDC"). Otherwise, use the index alias "@{index}" from spot_meta["universe"].
Examples: Perpetuals
# Retrieve all perpetual DEXs
perp_dexs = sdk.info.perp_dexs
# => [nil, { "name" => "test", "full_name" => "test dex", ... }]
# Retrieve perpetuals metadata (optionally for a specific perp dex)
= sdk.info.
# => { "universe" => [...] }
= sdk.info.(dex: "perp-dex-name")
# => { "universe" => [...] }
# Retrieve perpetuals asset contexts (includes mark price, current funding, open interest, etc.)
= sdk.info.
# => { "universe" => [...], "assetCtxs" => [...] }
# Retrieve user's perpetuals account summary (optionally for a specific perp dex)
state = sdk.info.user_state(user_address)
# => { "assetPositions" => [...], "marginSummary" => {...} }
state = sdk.info.user_state(user_address, dex: "perp-dex-name")
# => { "assetPositions" => [...], "marginSummary" => {...} }
# Retrieve a user's funding history or non-funding ledger updates (optional end_time)
funding = sdk.info.user_funding(user_address, start_time)
# => [{ "delta" => { "type" => "funding", ... }, "time" => ... }]
funding = sdk.info.user_funding(user_address, start_time, end_time)
# => [{ "delta" => { "type" => "funding", ... }, "time" => ... }]
# Retrieve historical funding rates
hist = sdk.info.funding_history("ETH", start_time)
# => [{ "coin" => "ETH", "fundingRate" => "...", "time" => ... }]
# Retrieve predicted funding rates for different venues
pred = sdk.info.predicted_fundings
# => [["AVAX", [["HlPerp", { "fundingRate" => "0.0000125", "nextFundingTime" => ... }], ...]], ...]
# Query perps at open interest caps
oi_capped = sdk.info.perps_at_open_interest_cap
# => ["BADGER", "CANTO", ...]
# Retrieve information about the Perp Deploy Auction
auction = sdk.info.perp_deploy_auction_status
# => { "startTimeSeconds" => ..., "durationSeconds" => ..., "startGas" => "500.0", ... }
# Retrieve User's Active Asset Data
aad = sdk.info.active_asset_data(user_address, "APT")
# => { "user" => user_address, "coin" => "APT", "leverage" => { "type" => "cross", "value" => 3 }, ... }
# Retrieve Builder-Deployed Perp Market Limits
limits = sdk.info.perp_dex_limits("builder-dex")
# => { "totalOiCap" => "10000000.0", "oiSzCapPerPerp" => "...", ... }
Examples: Spot
# Retrieve spot metadata
= sdk.info.
# => { "tokens" => [...], "universe" => [...] }
# Retrieve spot asset contexts
= sdk.info.
# => [ { "tokens" => [...], "universe" => [...] }, [ { "midPx" => "...", ... } ] ]
# Retrieve a user's token balances
balances = sdk.info.spot_balances(user_address)
# => { "balances" => [{ "coin" => "USDC", "token" => 0, "total" => "..." }, ...] }
# Retrieve information about the Spot Deploy Auction
deploy_state = sdk.info.spot_deploy_state(user_address)
# => { "states" => [...], "gasAuction" => { ... } }
# Retrieve information about the Spot Pair Deploy Auction
pair_status = sdk.info.spot_pair_deploy_auction_status
# => { "startTimeSeconds" => ..., "durationSeconds" => ..., "startGas" => "...", ... }
# Retrieve information about a token by onchain id in 34-character hexadecimal format
details = sdk.info.token_details("0x00000000000000000000000000000000")
# => { "name" => "TEST", "maxSupply" => "...", "midPx" => "...", ... }
Exchange Methods (Trading)
Note: Exchange methods require initializing the SDK with a private_key.
order(coin:, is_buy:, size:, limit_px:, ...)- Place a single limit orderbulk_orders(orders:, grouping:, ...)- Place multiple orders in a batchmarket_order(coin:, is_buy:, size:, slippage:, ...)- Place a market order with slippagecancel(coin:, oid:, ...)- Cancel an order by order IDcancel_by_cloid(coin:, cloid:, ...)- Cancel an order by client order IDbulk_cancel(cancels:, ...)- Cancel multiple orders by order IDbulk_cancel_by_cloid(cancels:, ...)- Cancel multiple orders by client order IDaddress- Get the wallet address associated with the private key
All exchange methods support an optional vault_address: parameter for vault trading.
Examples: Exchange (Trading)
# Initialize SDK with private key for trading
sdk = Hyperliquid.new(
testnet: true,
private_key: ENV['HYPERLIQUID_PRIVATE_KEY']
)
# Get wallet address
address = sdk.exchange.address
# => "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
# Place a limit buy order
result = sdk.exchange.order(
coin: 'BTC',
is_buy: true,
size: '0.01',
limit_px: '95000',
order_type: { limit: { tif: 'Gtc' } } # Good-til-canceled (default)
)
# => { "status" => "ok", "response" => { "type" => "order", "data" => { "statuses" => [...] } } }
# Place a limit sell order with client order ID
cloid = Hyperliquid::Cloid.from_int(123) # Or Cloid.random
result = sdk.exchange.order(
coin: 'ETH',
is_buy: false,
size: '0.5',
limit_px: '3500',
cloid: cloid
)
# Place a market order (IoC with slippage)
result = sdk.exchange.market_order(
coin: 'BTC',
is_buy: true,
size: '0.01',
slippage: 0.03 # 3% slippage tolerance (default: 5%)
)
# Place multiple orders at once
orders = [
{ coin: 'BTC', is_buy: true, size: '0.01', limit_px: '94000' },
{ coin: 'BTC', is_buy: false, size: '0.01', limit_px: '96000' }
]
result = sdk.exchange.bulk_orders(orders: orders)
# Cancel an order by order ID
oid = result.dig('response', 'data', 'statuses', 0, 'resting', 'oid')
sdk.exchange.cancel(coin: 'BTC', oid: oid)
# Cancel an order by client order ID
sdk.exchange.cancel_by_cloid(coin: 'ETH', cloid: cloid)
# Cancel multiple orders by order ID
cancels = [
{ coin: 'BTC', oid: 12345 },
{ coin: 'ETH', oid: 12346 }
]
sdk.exchange.bulk_cancel(cancels: cancels)
# Cancel multiple orders by client order ID
cloid_cancels = [
{ coin: 'BTC', cloid: Hyperliquid::Cloid.from_int(1) },
{ coin: 'ETH', cloid: Hyperliquid::Cloid.from_int(2) }
]
sdk.exchange.bulk_cancel_by_cloid(cancels: cloid_cancels)
# Vault trading (trade on behalf of a vault)
vault_address = '0x...'
sdk.exchange.order(
coin: 'BTC',
is_buy: true,
size: '1.0',
limit_px: '95000',
vault_address: vault_address
)
Order Types:
{ limit: { tif: 'Gtc' } }- Good-til-canceled (default){ limit: { tif: 'Ioc' } }- Immediate-or-cancel{ limit: { tif: 'Alo' } }- Add-liquidity-only (post-only)
Trigger Orders (Stop Loss / Take Profit):
# Stop loss: Sell when price drops to trigger level
sdk.exchange.order(
coin: 'BTC',
is_buy: false,
size: '0.1',
limit_px: '89900',
order_type: {
trigger: {
trigger_px: 90_000,
is_market: true, # Execute as market order when triggered
tpsl: 'sl' # Stop loss
}
}
)
# Take profit: Sell when price rises to trigger level
sdk.exchange.order(
coin: 'BTC',
is_buy: false,
size: '0.1',
limit_px: '100100',
order_type: {
trigger: {
trigger_px: 100_000,
is_market: false, # Execute as limit order when triggered
tpsl: 'tp' # Take profit
}
}
)
Client Order IDs (Cloid):
# Create from integer (zero-padded to 16 bytes)
cloid = Hyperliquid::Cloid.from_int(42)
# => "0x0000000000000000000000000000002a"
# Create from hex string
cloid = Hyperliquid::Cloid.from_str('0x1234567890abcdef1234567890abcdef')
# Create from UUID
cloid = Hyperliquid::Cloid.from_uuid('550e8400-e29b-41d4-a716-446655440000')
# Generate random
cloid = Hyperliquid::Cloid.random
Configuration
# Custom timeout (default: 30 seconds)
sdk = Hyperliquid.new(timeout: 60)
# Enable retry logic for handling transient failures (default: disabled)
sdk = Hyperliquid.new(retry_enabled: true)
# Enable trading with a private key
sdk = Hyperliquid.new(private_key: ENV['HYPERLIQUID_PRIVATE_KEY'])
# Set global order expiration (orders expire after this timestamp)
expires_at_ms = (Time.now.to_f * 1000).to_i + 30_000 # 30 seconds from now
sdk = Hyperliquid.new(
private_key: ENV['HYPERLIQUID_PRIVATE_KEY'],
expires_after: expires_at_ms
)
# Combine multiple configuration options
sdk = Hyperliquid.new(
testnet: true,
timeout: 60,
retry_enabled: true,
private_key: ENV['HYPERLIQUID_PRIVATE_KEY'],
expires_after: expires_at_ms
)
# Check which environment you're using
sdk.testnet? # => false
sdk.base_url # => "https://api.hyperliquid.xyz"
# Check if exchange is available (private_key was provided)
sdk.exchange # => nil if no private_key, Hyperliquid::Exchange instance otherwise
Retry Configuration
By default, retry logic is disabled for predictable API behavior. When enabled, the SDK will automatically retry requests that fail due to:
- Network connectivity issues (connection failed, timeouts)
- Server errors (5xx status codes)
- Rate limiting (429 status codes)
Retry Settings:
- Maximum retries: 2
- Base interval: 0.5 seconds
- Backoff factor: 2x (exponential backoff)
- Randomness: ±50% to prevent thundering herd
Note: Retries are disabled by default to avoid unexpected delays in time-sensitive trading applications. Enable only when you want automatic handling of transient failures.
Error Handling
The SDK provides comprehensive error handling:
begin
orders = sdk.info.open_orders(user_address)
rescue Hyperliquid::AuthenticationError
# Handle authentication issues
rescue Hyperliquid::RateLimitError
# Handle rate limiting
rescue Hyperliquid::ServerError
# Handle server errors
rescue Hyperliquid::NetworkError
# Handle network connectivity issues
rescue Hyperliquid::Error => e
# Handle any other Hyperliquid API errors
puts "Error: #{e.}"
puts "Status: #{e.status_code}" if e.status_code
puts "Response: #{e.response_body}" if e.response_body
end
Available error classes:
Hyperliquid::Error- Base error classHyperliquid::ClientError- 4xx errorsHyperliquid::ServerError- 5xx errorsHyperliquid::AuthenticationError- 401 errorsHyperliquid::BadRequestError- 400 errorsHyperliquid::NotFoundError- 404 errorsHyperliquid::RateLimitError- 429 errorsHyperliquid::NetworkError- Connection issuesHyperliquid::TimeoutError- Request timeouts
Development
After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.
Run the example:
ruby example.rb
Run tests:
rake spec
Run tests and linting together:
rake
Run linting:
rake rubocop
Roadmap
The SDK now supports both Info API (read) and Exchange API (trading). Future versions will include:
- WebSocket support for real-time data
- Additional exchange operations (leverage, margin adjustments, transfers)
- Advanced trading features (TWAP, etc.)
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/carter2099/hyperliquid.
License
The gem is available as open source under the terms of the MIT License.