Skip to main content

Off-chain HIP-2 Hyperliquidity market maker for Hyperliquid spot markets

Project description

pyperliquidity

PyPI version Python 3.11+ License: MIT

A Python implementation of HIP-2 "Hyperliquidity" market-making algorithm. While HIP-2's logic runs fully on-chain, certain spot markets (especially bridged assets) are unable to use this feature. pyperliquidity recovers HIP-2 behavior using an off-chain market maker.

Core concept: Uniswap V3 concentrated liquidity, but on an order book. You specify a finite price range via a geometric grid, and pricing emerges from inventory position — no oracle needed.

Installation

pip install pyperliquidity

For development:

git clone https://github.com/AlliedToasters/pyperliquidity.git
cd pyperliquidity
python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"

How It Works

The Price Grid

The grid is a fixed geometric ladder of price levels, set once at deployment:

Level 0:  start_px
Level 1:  start_px * 1.003
Level 2:  start_px * 1.003^2
...
Level N:  start_px * 1.003^N

The grid does not move. Price discovery comes from where your inventory sits on it.

The Cursor

The cursor is the boundary between bids and asks, derived from token inventory each tick:

total_ask_levels = min(floor(token / order_sz) + (1 if remainder), n_orders)
cursor = n_orders - total_ask_levels
  • More tokens → cursor lower → more asks → lower effective price
  • Fewer tokens → cursor higher → more bids → higher effective price

As people buy your token (filling asks), the cursor rises and bids appear at lower levels. As people sell (filling bids), the cursor drops and asks appear above. The price is never set explicitly — it emerges from inventory.

Deployment Styles

Style Token allocation start_px Behavior
Full deploy (HIP-2 genesis) Fill the whole grid = current price All asks initially, bids appear as people buy
Balanced Use target_px Below current price Bids and asks from the start

Quick Start

1. Set environment variables

These are required:

export PYPERLIQUIDITY_PRIVATE_KEY="0x..."   # Ethereum private key (hex)
export PYPERLIQUIDITY_WALLET="0x..."        # Wallet address

2. Create a config file

cp config.example.toml config.toml

3. Configure your strategy

There are two ways to set your initial position:

Option A: target_px (recommended) — set where you want the cursor to start. Token and USDC allocations are computed automatically:

[market]
coin = "@1434"            # Spot pair (find via Hyperliquid spotMeta API)
testnet = true            # Use testnet API

[strategy]
n_orders = 1656           # Total grid levels ($350-$50k at 0.3% spacing)
order_sz = 0.0286         # Tokens per level (must clear $10 min at start_px)
start_px = 350.0          # Bottom of grid — fixed forever
active_levels = 20        # Only 20 bids + 20 asks on the book at a time
target_px = 557.0         # Start cursor here (auto-computes allocations)

[tuning]
interval_s = 0.5          # Tick every 500ms (safe with dead zone)
# dead_zone_bps = 5.0     # Skip requote if mid drifted less than this (default)
# price_tolerance_bps = 1.0  # Skip modify if price moved less than this (default)
# size_tolerance_pct = 1.0   # Skip modify if size changed less than this (default)
# reconcile_every = 20    # REST reconciliation interval (default)

When using target_px, the [allocation] section is not needed. The target level is computed as:

target_level = ln(target_px / start_px) / ln(1.003)

Option B: Manual allocation — calculate allocated_token and allocated_usdc yourself:

[strategy]
n_orders = 100
order_sz = 1000.0
start_px = 0.01

[allocation]
allocated_token = 1000.0
allocated_usdc = 500.0

4. Run

pyperliquidity run --config config.toml

Key Concepts

active_levels — Essential for Wide Grids

Without active_levels, orders are placed on every grid level. For a wide grid (e.g., 1,656 levels covering $350-$50k), that's far too many resting orders.

With active_levels = 20, only 20 bids + 20 asks nearest the cursor are placed on the exchange. The window slides automatically as fills move the cursor.

Sizing Considerations

Hyperliquid enforces a $10 minimum order notional. This constrains order_sz at the bottom of the grid:

order_sz * start_px >= $10

For wide grids starting at a low price, order_sz = $10 / start_px is the minimum viable size. Orders below the minimum notional are automatically filtered out.

Rate Limit Budget

Hyperliquid uses a budget model:

budget = 10,000 + cumulative_volume_usd - cumulative_requests
  • Every API mutation (place, modify, cancel) costs 1 from budget
  • Every $1 of filled volume earns 1 back
  • Batch operations (bulk_modify, bulk_cancel) cost 1 regardless of batch size
  • At budget=0, throttled to 1 request per 10 seconds

The dead zone and tolerance filters prevent unnecessary API calls. A faster interval_s is safe because updates are only sent when orders actually need to change. active_levels keeps the resting order count manageable.

All resting orders use ALO (Add Liquidity Only) to ensure maker-only fills, which replenish the budget.

Architecture

WebSocket Feeds ──► StateManager ──► QuotingEngine ──► OrderDiffer ──► BatchEmitter ──► API
     ^                (single source      (pure math,     (dead zone +     (budget-aware,   |
     |                 of truth)           no I/O)         level-index      prioritized)     |
     └──────────── orderUpdates / userFills / webData2 ──────────────────────────────────────┘
  • QuotingEngine — pure math, no I/O. Translates inventory position on the grid into desired orders.
  • OrderDiffer — dead-zone filtering and tolerance checks to minimize unnecessary API calls.
  • BatchEmitter — budget-aware, prioritized order emission that respects Hyperliquid's rate limit model.
  • WsState — WebSocket-first state management with periodic REST reconciliation.

Development

This project uses OpenSpec for spec-driven development. Domain specs live in openspec/specs/.

.venv/bin/pytest              # Run tests
.venv/bin/mypy src/           # Type check
.venv/bin/ruff check src/     # Lint

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyperliquidity-0.2.13.tar.gz (168.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyperliquidity-0.2.13-py3-none-any.whl (30.1 kB view details)

Uploaded Python 3

File details

Details for the file pyperliquidity-0.2.13.tar.gz.

File metadata

  • Download URL: pyperliquidity-0.2.13.tar.gz
  • Upload date:
  • Size: 168.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyperliquidity-0.2.13.tar.gz
Algorithm Hash digest
SHA256 7be5d28c7ae140792dea11218da5659feafe8c9ffedd382b93060fd2b8371bff
MD5 b42a7652255e2248631a15709f25cdce
BLAKE2b-256 bbfd5a3721400ebd76a072b508a2274fa338e254a597fe2acbe123c4713daf25

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyperliquidity-0.2.13.tar.gz:

Publisher: release.yml on AlliedToasters/pyperliquidity

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyperliquidity-0.2.13-py3-none-any.whl.

File metadata

File hashes

Hashes for pyperliquidity-0.2.13-py3-none-any.whl
Algorithm Hash digest
SHA256 61dc614e9636cf0145fc349f6bede089f695c7d5d5bf1fb058961f7e181ca31c
MD5 4994a6263eff13b90a751b3ad9482c60
BLAKE2b-256 c04617ac4cb4438c48f4407f44b67feb5f5d7e403a47edc5d2340ddde4851478

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyperliquidity-0.2.13-py3-none-any.whl:

Publisher: release.yml on AlliedToasters/pyperliquidity

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page