
Hyperliquid’s HIP-4 brings outcome markets natively on-chain. Learn how HIP-4 works, walk through the API, set up your environment, and run a passive market-making bot on binary outcome markets.
TL;DR
HIP-4 is Hyperliquid’s native outcome market protocol, live on mainnet
- Hyperliquid’s native outcome market protocol, live on mainnet
- Settles in USDH, no leverage, no liquidations
- Binary and multi-price markets, automatically deployed and settled by the protocol
The API runs on the same engine as spot and perps
- Same REST and WebSocket engine as spot and perps
- Read state via
/infowithoutcomeMeta, write via/exchange - Outcome asset IDs follow
20000 + outcome_index
The bot quotes YES and NO tokens passively across multiple outcomes
- A passive market-making bot that quotes YES and NO tokens simultaneously
- Bot manages fair value, spread, inventory caps, and graceful shutdown
- Runs on Chainstack’s Hyperliquid node with a single endpoint for HyperCore and HyperEVM
Hyperliquid HIP-4 is live
🤔 Prefer diving straight into the code? Get the HIP-4 bot by Chainstack
HIP-4 is live on mainnet.
Hyperliquid integrated outcome markets directly into HyperCore that processes billions in daily spots and perpetuals volume. On day one, the initial BTC binary market generated 6.05 million contracts in the first 24 hours
and a cumulative volume of 25.1M in a week since May 2.
What is Hyperliquid HIP-4?
HIP-4 (Hyperliquid Improvement Proposal 4) introduces outcome markets: non-linear, expiry-based contracts designed as an alternative derivative primitive without leverage or liquidations.
For a deeper breakdown of all HIPs, read Hyperliquid HIPs Explained.
Outcomes are single tradable contract that settle into predefined results at expiry instead of behaving like continuously margined perpetual positions. For eg: “BTC closes above $80,922 at 06:00 UTC May 14”. Each outcome is identified by a positive integer index. On mainnet, the first BTC daily binary outcome has index 5915.
Recurring outcomes are markets automatically deployed and settled by the protocol on a fixed cadence, with the active market configuration stored in the description field of outcomeMeta.
Binary outcome markets settle into one of two states: YES or NO.
class:priceBinary|underlying:BTC|expiry:20260503-0600|targetPrice:78213|period:1d
class:priceBinary: specifies a binary price outcome marketunderlying:BTC: uses BTC as the reference assetexpiry:20260503-0600: settlement timestamp of the markettargetPrice:78213: strike price used for settlementperiod:1d: a new binary market is created every 1 day
Settlement uses linear interpolation between the mark price updates immediately before and after expiry. The market settles to YES if the interpolated price is greater than or equal to the target price.
Multi-price markets divide settlement into multiple price buckets.
class:priceBucket|underlying:BTC|expiry:20260507-0745|priceThresholds:81538,81783|period:15m
class:priceBucket→ specifies a bucket-based outcome marketunderlying:BTC→ BTC is the reference assetexpiry:20260507-0745→ settlement timestamppriceThresholds:81538,81783→ defines three settlement buckets:<81538,[81538,81783), and≥81783period:15m→ a new market instance launches every 15 minutes
There are three price buckets depending on the target price at the time of settlement:
< P1[P1, P2)≥ P2
Exactly one of the 3 outcomes settles to 1, and the others settle to 0. One such example is already live on testnet and on mainnet. Hyperliquid has stated additional features will be rolled out gradually in later stages.
Outcome tokens are the tradable units representing each possible market result, and their prices are bounded between [0,1], where 0 represents an impossible outcome and 1 represents a guaranteed winning outcome at settlement.
USDH is the quote and settlement denomination used for outcome markets, allowing outcome token prices ( probabilities ) to trade as decimal probabilities such as 0.001, 0.25, or 0.9999 depending on the outcome. For eg: The price tick on the BTC binary is 0.0001
Settlement is automatic. There is no claim, redeem, or settle call. At expiry, USDH credits land in the account in proportion to the side balances held, and the outcome is removed from the next outcomeMeta response.
Hyperliquid HIP-4 API
Before understanding how the bot works, it is important to understand how Hyperliquid exposes their APIs.
📖 All across Hyperliquid, whether spot, perps or outcomes, they run on the same engine accessible through the same HyperCore. It is recommended to read “Hyperliquid API for Developer” to understand the HIP-4 API smoothly.
Info
All on-chain state read from the chain flows through /info endpoint. The only thing that changes is the type field in the request.
Pass outcomeMeta in type
import requests
url = "<https://api.hyperliquid.xyz/info>"
payload = { "type": "outcomeMeta" }
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)
Returns all outcome markets with their asset IDs, question text, expiry timestamp, oracle type, and settlement status.
To see it in action: list outcomes
📖 Find the full availability matrix for all hyperliquid methods and in detail explanation of each in API reference
Exchange
POST /exchange is the write layer. Every state-changing operation, placing orders, canceling, splitting, merging, flows here. All requests on /exchange endpoint requires an EIP-712 structured data signature from the wallet key for authentication and security purposes.
The four outcome-specific exchange actions:
| Action | Effect |
|---|---|
splitOutcome | Burns 1 USDH, mints 1 YES + 1 NO for a question |
mergeOutcome | Burns 1 YES + 1 NO, returns 1 USDH |
negateOutcome | Converts YES to NO (or NO to YES) for the same question |
mergeQuestion | Settles a categorical question at expiry |
The Hyperliquid Python SDK handles signing and payload encoding. The hl4/ library in the repo wraps the SDK specifically for outcome asset IDs and action types.
WebSocket
Hyperliquid’s WebSocket endpoint streams l2Book and trades updates for any asset including outcomes at:
- mainnet :
wss://api.hyperliquid.xyz/ws - testnet :
wss://api.hyperliquid-testnet.xyz/ws
See an easy implementation of subscribing to l2Book + trades for one side of an outcome over WebSocket
Updates arrive as JSON frames with bid/ask depth changes. The bot uses this feed to track mid-price in real time without polling the REST endpoint on every tick.
Use this reference to check all subscription types: WebSocket subscriptions docs
Build the bot
We will use:
- A Chainstack account: Create your account for free
- Python 3.11 or higher
hyperliquid-python-sdk: Hyperliquid trading interfaceeth-account: Ethereum account signingpython-dotenv: Load environment variableshttpx: Async HTTP clientwebsockets: WebSocket communication libraryrich: Rich terminal formatting and UIIt is a Python project built withuvand organized into three layers:
hyperliquid-hip-4/
├── hl4/ ← core client library (API calls, signing, types)
├── examples/ ← 13 standalone scripts, one per primitive operation
├── bot/ ← passive market-maker
├── .env.example ← environment variable template
All scripts target testnet by default. Mainnet requires changing the base URL in the config.
Create Chainstack Account
Head to Console and create a free account
This is where you can manage all your nodes across 70+ protocols
Click on “Add node”
Choose Hyperliquid and then select “Hyperliquid Testnet” in the network section below
Click “Next”
In the next step, select the type of node. For this project, choose “Global Node”. Give your node a name, review all the settings in the summary, and click “Deploy Node”
Once the node is deployed, click “View Node Details”. Scroll down to the “Access and credentials” section. Here you will find the endpoint URL, copy it and keep it safe. It will be needed in the next step.
Do not expose your URL. Store it securely in a
.envfile and add it to your.gitignorebefore pushing the code to GitHub. Consider using password-protected endpoints to enhance security.
Environment Setup
git clone <https://github.com/chainstacklabs/hyperliquid-hip-4>
cd hyperliquid-hip-4
uv sync
cp .env.example .env
Fill in .env:
HYPERLIQUID_TESTNET_PRIVATE_KEY=0x...
TESTNET_WALLET_ADDRESS=0x...
For your RPC endpoint, use Chainstack, deploy a Hyperliquid node and drop the HTTPS URL into your config. Chainstack’s Hyperliquid nodes expose both HyperEVM /evm and a subset of HyperCore /info queries on a single endpoint, which simplifies auth and latency tuning when running bots.
Explore examples (optional)
# list all outcome IDs with metadata
uv run python examples/01_list_outcomes.py
# list categorical questions (multi-leg markets)
uv run python examples/02_list_questions.py
For learning purposes, explore and run scripts like 01_list_outcomes.py to call outcomeMeta on /info endpoint. It returns each outcome’s ID, question text, expiry timestamp, and settlement oracle type. On testnet, you will see the BTC daily binary, a HYPE 15-minute binary, and several validator-deployed test markets.
Move to next step to setup and run the bot.
Get USDH (critical)
HIP-4 settles in USDH. To get USDH, run script 00_get_usdh.pyThe standard testnet faucet pays USDC; handles the USDC → USDH swap.
uv run python examples/00_get_usdh.py --amount 50
Then, check your USDC, USDH, and outcome token balances
uv run python examples/03_account_state.py
Run the bot
The bot/ directory contains market_maker.py, a passive market-making loop designed for binary outcome markets. Here is what it does and how each parameter controls behavior. To run the bot:
# market-make BTC daily and HYPE 15-min binaries simultaneously
uv run python -m bot.market_maker --outcomes 5915,5969 \\
--quote-notional 12 --half-spread 0.04 --max-inventory 30 --tick 5
| Parameter | Description |
|---|---|
--outcomes | Comma-separated outcome IDs to make markets on simultaneously |
--quote-notional | USDH size of each resting order (bid and ask) |
--half-spread | One-sided spread from mid-price, in USDH. A half-spread of 0.04 places bids at mid - 0.04 and asks at mid + 0.04 |
--max-inventory | Maximum net position in USDH before the bot stops quoting the direction that would increase exposure |
--tick | Loop interval in seconds |
How does the bot work?
The bot/market_maker.py script runs a passive market-making strategy for HIP-4 binary outcome markets. Its job is to continuously place buy and sell quotes around the current market price while managing inventory risk automatically.
import argparse
import asyncio
import signal
import time
from dataclasses import dataclass, field
import httpx
from hyperliquid.exchange import Exchange
from hyperliquid.info import Info
from rich.console import Console
from hl4 import load_config
from hl4.client import make_clients
from hl4.outcomes import encode_balance_coin, encode_coin
console = Console()
- import async runtime, HTTP client, exchange SDK, and CLI tools
PRICE_MIN=0.001
PRICE_MAX=0.999
PRICE_TICK=0.001
- define price bounds, defaults at 0.001 for safety
- smallest allowed price movement (tick size)
def round_tick(px: float) -> float:
return max(PRICE_MIN, min(PRICE_MAX, round(px, 3)))
def fetch_book(base_url: str, coin: str) -> tuple[float | None, float | None]:
r = httpx.post(f"{base_url}/info", json={"type": "l2Book", "coin": coin}, timeout=5.0)
levels = r.json().get("levels", [[], []])
bid = float(levels[0][0]["px"]) if levels[0] else None
ask = float(levels[1][0]["px"]) if levels[1] else None
return bid, ask
def fair_from_book(bid: float | None, ask: float | None) -> float | None:
if bid is not None and ask is not None:
return (bid + ask) / 2
if bid is not None:
return min(PRICE_MAX, bid + PRICE_TICK)
if ask is not None:
return max(PRICE_MIN, ask - PRICE_TICK)
return 0.5
def position_for(base_url: str, address: str, balance_coin: str) -> float:
"""Look up an outcome side balance. Note: outcome balances appear under the
`+<encoding>` coin form, not the `#<encoding>` form used for trading."""
r = httpx.post(
f"{base_url}/info",
json={"type": "spotClearinghouseState", "user": address},
timeout=5.0,
)
for b in r.json().get("balances", []):
if b["coin"] == balance_coin:
return float(b["total"])
return 0.0
- round prices to valid ticks
- fetch order book data,
- calculate fair market prices or defaults to
0.5 - and retrieve current YES/NO inventory balances
The bot maintains 4 quote channels per outcome:
- YES bid / YES ask
- NO bid / NO ask
@dataclass
classSideState:
coin:str
is_buy:bool
open_oid:int|None=None
open_px:float|None=None
open_sz:float|None=None
SideState tracks the currently resting order
classOutcomeMM:
def__post_init__(self):
forsidein (0,1):
coin=encode_coin(self.outcome_id,side)
self.sides[(side,True)]=SideState(coin,True)
self.sides[(side,False)]=SideState(coin,False)
This prebuilds the full two-sided quoting structure for each prediction-market outcome.
def__post_init__(self):
forsidein (0,1):
coin=encode_coin(self.outcome_id,side)
self.sides[(side,True)]=SideState(coin=coin,is_buy=True)
self.sides[(side,False)]=SideState(coin=coin,is_buy=False)
This builds full quoting structure:
- side = 0 → YES contract
- side = 1 → NO contract
- each side has:
- BUY order state
- SELL order state
This gives the bot continuous two-sided liquidity on both contracts simultaneously.
Once initialized, the bot enters a continuous quoting cycle:
bid_px=round_tick(mid-half_spread)
ask_px=round_tick(mid+half_spread)
This creates a passive spread designed to earn edge from market flow while staying inventory-neutral over time.
Troubleshooting
Common errors and their fixes when running the HIP-4 bot for the first time.
“Order must have minimum value of 10 USDH”
- The server enforces a $10 USDH minimum notional per order. At a price of
0.42, a size of23gives a notional of9.66 USDHjust under the floor. - Use
--quote-notional 12or higher when starting the bot. Validate notional client-side before signing so the round-trip to the server is not wasted:
“Order has invalid size”
- Outcome side coins use integer size precision. Fractional sizes like
10.5are rejected at the server even when the price and notional are valid. - Always round sizes up to the nearest integer before placing an order. The bot does this internally. If you are placing orders manually:
Orders fill but the position does not appear in account state
- There are two coin string forms for the same side asset, and they are not interchangeable:
| Form | Used in |
|---|---|
#<encoding> | /info l2Book, order placement, WebSocket |
+<encoding> | spotClearinghouseState balances |
- Querying balances with
#59150returns nothing. Queryingl2Bookwith+59150also returns nothing. Both fail silently with no error.
Use encode_coin(outcome_id, side) for order placement and encode_balance_coin(outcome_id, side) for balance lookups. Both helpers are exported from hl4.outcomes.
outcomeMeta returns empty or fails against the Chainstack endpoint
outcomeMetais only served by the official Hyperliquid public API. It is not part of the open-source node software, so it is not available on Chainstack-hosted endpoints.- Point HIP-4 metadata and trading calls at the public API: “mainnet:
https://api.hyperliquid.xyztestnet:https://api.hyperliquid-testnet.xyz - Continue using your Chainstack endpoint for HyperEVM operations and the supported subset of
/infostatic metadata methods. The full availability matrix is at Hyperliquid methods.
USDH balance is zero
- HIP-4 settles and collateralizes in USDH, not USDC. The standard testnet faucet pays USDC. They are separate assets and the exchange layer does not substitute one for the other.
- Swap USDC to USDH using the
@1338spot pair (~1:1) before placing any outcome orders:
uv run python examples/00_get_usdh.py --amount 50
Then confirm the balance before proceeding:
uv run python examples/03_account_state.py
The bot stops quoting one side
- Once the net position in USDH exceeds
--max-inventory, the bot stops placing orders in the direction that would increase exposure. It continues quoting the opposite side. This is intentional — it is the inventory cap working as designed. - To widen the cap, increase
--max-inventory. To reset a position manually, useexamples/09_close_position.pyto flatten before restarting the bot.
WebSocket feed goes silent mid-session
- HIP-4 markets can have low liquidity, especially on testnet. Periods of no activity produce no WebSocket events, the connection stays open but nothing is pushed. A network-level disconnection can look identical since the library does not always surface it immediately.
- The example scripts are minimal and do not include reconnect logic. In the bot, the REST fallback in
fetch_book()covers this: if the WebSocket stalls, the--tickloop interval triggers a fresh REST snapshot instead. For production use, add a heartbeat or reconnect loop around the WebSocket connection.
Settlement lands but the position lingers: waiting for a claim call
- HIP-4 settlement is automatic. There is no
claim,redeem, orsettlecall. At expiry, USDH credits land in the account proportional to the side balances held, and the outcome is removed from the nextoutcomeMetaresponse. Waiting for a transaction to trigger settlement means waiting for something that will never come. - To confirm settlement happened, check that your USDH balance increased and that the outcome ID is no longer listed in
outcomeMeta. Useexamples/12_wait_for_settlement.pyto poll through expiry:
uv run python examples/12_wait_for_settlement.py
Price rejected near 0 or 1
- Outcome prices are bounded to
[0.001, 0.999]. Orders at0.0,1.0, or prices with too many decimal places are rejected. The price tick on the BTC binary is0.0001. - Always pass prices through
round_tick()before submitting. The bot enforcesPRICE_MIN = 0.001andPRICE_MAX = 0.999, andfair_from_book()clamps the result automatically when one side of the book is empty.
Hyperliquid builder tools
The builder codes enable many perks and benefits for developers who choose to build on top of Hyperliquid. Outcome, a builder on HIP-4, generated 1M in trade volume:
The HIP-4 ecosystem is moving fast. Outcome markets went live on May 2, 2026, and builders are already shipping on top of it. Here is everything you need to go further, from code and frontends to docs and data.
Code
- chainstacklabs/hyperliquid-hip-4: The reference implementation from this guide, with 13 standalone example scripts and the full market-making bot.
- Hyperliquid Python SDK: Core SDK for order placement, signing, and account management across spot, perps, and outcomes.
Frontends and Builders
- Outcomexyz: The first official HIP-4 builder, live with BTC daily binary markets.
- trade.xyz: The leading HIP-3 builder for tokenized stocks and commodities, a reference point for what builders can ship on Hyperliquid primitives.
Analytics and Data
- Artemis HIP-4: Protocol-level analytics for HIP-4 volume, traders, and market activity.
- Allium HIP-4 Deep Dive: On-chain data terminal with a dedicated HIP-4 breakdown.
Core Documentation
- HIP-4 Outcome Markets: Full protocol specification.
- Contract Specifications: Recurring outcome structure, binary and multi-price mechanics.
- Fee Schedule: Outcome token fee structure and settlement details.
- Asset IDs: Schema for deriving outcome asset IDs.
- Exchange Endpoint: Reference for
splitOutcome,mergeOutcome,negateOutcome, andmergeQuestion. - WebSocket Subscriptions: Real-time
l2Bookandtradesfeeds for outcome assets.
Chainstack
- Hyperliquid RPC: Deploy a Hyperliquid node with a single endpoint for HyperCore and HyperEVM.
- HIP-4 Trading Guide: Step-by-step guide for trading outcome markets via Chainstack.
- Hyperliquid API Reference: Full method availability matrix and in-depth endpoint documentation.
Community
- Hyperliquid Discord #api-traders: The go-to channel for builder questions, API discussions, and ecosystem updates.
Conclusion
HIP-4 brings a new class of derivative to Hyperliquid, one that settles automatically, runs on the same engine as spot and perps, and requires no leverage or liquidations. For builders, that means a clean surface to build on. Outcome markets expose the same REST and WebSocket APIs, use the same signing flow, and sit inside the same liquidity environment that already processes billions in daily volume.
The bot in this guide is a starting point. It covers the core loop: fetching fair value from the order book, placing resting quotes on both YES and NO sides, managing inventory caps, and cleaning up on shutdown. From here, you can extend it with dynamic spread skewing based on inventory, multi-outcome correlation logic, or signal layers that adjust quotes around known settlement windows.
To get started, deploy a Hyperliquid node on Chainstack, clone the repo, and run the bot on testnet first. Chainstack’s Hyperliquid nodes give you a reliable, low-latency endpoint with access to both HyperCore and HyperEVM on a single URL, which keeps the setup straightforward as you move from exploration to production.
With Chainstack Hyperliquid nodes, you get a single low-latency endpoint for both HyperCore and HyperEVM, making it easier to manage market data, order execution, and on-chain interactions without stitching together multiple providers. Whether you’re experimenting with passive market making on testnet or deploying production trading systems, Chainstack gives you reliable RPC performance, predictable connectivity, and fast global access for latency-sensitive bots.
FAQ
HIP-4 (Hyperliquid Improvement Proposal 4) introduces outcome markets — expiry-based contracts that settle into predefined results like YES or NO. Unlike perpetuals, they have no leverage, no liquidations, and settle automatically in USDH at expiry.
Settlement is fully automatic. At expiry, USDH credits land in your account proportional to the side balances you hold. There is no claim, redeem, or settle transaction to submit. The settled outcome disappears from the next outcomeMeta response.
USDH is Hyperliquid’s native stablecoin used as the quote and settlement currency for outcome markets. The testnet faucet pays USDC — they are separate assets. Swap USDC to USDH via the @1338 spot pair before placing any outcome orders.
No. outcomeMeta is served only by the official Hyperliquid public API and is not part of the open-source node software. Point HIP-4 metadata and trading calls at https://api.hyperliquid.xyz (mainnet) or https://api.hyperliquid-testnet.xyz (testnet). Use your Chainstack endpoint for HyperEVM operations and supported /info methods.
splitOutcome burns 1 USDH and mints 1 YES + 1 NO token for a question. mergeOutcome does the reverse — burns 1 YES + 1 NO and returns 1 USDH. negateOutcome converts a YES token to NO (or NO to YES) for the same question without touching USDH.
Outcome asset IDs follow the schema 20000 + outcome_index. The first BTC daily binary on mainnet has index 5915, giving asset ID 25915. Use encode_coin(outcome_id, side) for order placement and encode_balance_coin(outcome_id, side) for balance lookups — the two forms are not interchangeable.
The bot and all example scripts target testnet by default. To switch to mainnet, change the base URL in your config to https://api.hyperliquid.xyz and fund your wallet with real USDH. Run on testnet first — use examples/00_get_usdh.py to get testnet USDH from the faucet and verify your setup before moving to mainnet.
Each order must have a minimum notional of 10 USDH. Order sizes must be integers — fractional sizes are rejected. Prices are bounded to [0.001, 0.999] with a tick size of 0.0001 on the BTC binary. Always pass prices through round_tick() before submitting.
Related reading
Hyperliquid + HIPs
- Hyperliquid HIPs Explained
- Hyperliquid API Guide: Endpoints, SDK, WebSocket
- HIP-4 Outcome Markets Trading Guide
- Hyperliquid Methods
