hl-read
by akagifreeez
README.md
# hl-read
**A key-free, read-only toolkit for [Hyperliquid](https://hyperliquid.xyz).** Use it as a Python library, a CLI, or an **MCP server** that lets an LLM agent (Claude, n8n, …) observe Hyperliquid markets and any wallet's public state.
> **Why "read-only" is the feature.** `hl-read` imports only the read side of the Hyperliquid SDK (`Info`) — never `Exchange`. There is no code path that can sign a transaction, place an order, or move funds. **You never hand it a private key, so there is no key to leak.** Most Hyperliquid MCP servers ask for your key so the model can trade; this one is safe to point an autonomous agent at by construction.
Everything it reads is *public* on-chain / exchange data: prices, order books, funding, and any address's positions, orders and fills.
---
## Install
Not on PyPI (yet) — install from source:
```bash
git clone https://github.com/akagifreeez/hl-read.git
cd hl-read
pip install . # library + CLI
pip install ".[mcp]" # also installs the MCP server deps
```
## CLI
```bash
hl-read mids # all mid prices
hl-read mids BTC ETH # just these
hl-read book ETH --depth 5 # order book snapshot
hl-read funding --top 10 # markets with the most extreme funding
hl-read predicted BTC ETH # predicted funding across venues (HL vs Binance/Bybit)
hl-read markets # every perp + max leverage
hl-read spot # every spot pair + mid price
hl-read spot PURR # filter by base coin / pair
hl-read positions 0xYourAddr... # anyone's positions (public data)
hl-read positions 0xYourAddr... --watch # live, re-polled every few seconds
hl-read portfolio 0xYourAddr... # account value / PnL history by period
hl-read ledger 0xYourAddr... # deposits / withdrawals / transfers (--since, --limit 0 = all)
hl-read balances 0xYourAddr... # spot token balances
hl-read orders 0xYourAddr... # resting orders
hl-read fills 0xYourAddr... --limit 20
hl-read fills 0xYourAddr... --since 7d # fills within a time window (e.g. 24h/7d, 2024-01-31)
hl-read watch ETH # live order book over websocket
hl-read health # is the API up? round-trip latency (exit 1 if down)
```
Global flags: `--testnet` (use the testnet API), `--json` (raw JSON, great for piping to `jq`), `--format table|json|csv|ndjson` (output format; `--json` is the alias for `--format json`), `--retries N` (retry transient failures), `--rate-limit N` (cap HTTP calls/min), `--no-cache` (always fetch fresh), `--api-url URL` (override the endpoint, e.g. a proxy/mirror), `--fallback-url URL` (repeatable; tried on persistent failure).
```bash
hl-read --json funding | jq '.[] | select(.funding > 0.0001)'
hl-read --format csv funding > funding.csv # any list command as CSV / NDJSON
```
### Export to a file
`export` writes straight to a UTF-8 file (no BOM) so it survives the Windows/PowerShell `>` redirect, which otherwise emits UTF-16 and corrupts CSVs. Defaults to CSV; use `--format json|ndjson` to change.
```bash
hl-read export ledger 0xYourAddr... --out ledger.csv # full deposit/withdrawal history
hl-read export fills 0xYourAddr... --since 30d --out fills.csv
hl-read --format ndjson export candles BTC --hours 168 --out btc.ndjson
```
## Library
```python
from hl_read import HLRead
hl = HLRead() # mainnet; HLRead(testnet=True) for testnet
# custom endpoint + optional fallbacks (Hyperliquid is single-host, so these
# only matter for your own proxy/mirror; failover applies at connect and reads):
# HLRead(api_url="https://my-proxy", fallback_urls=["https://api.hyperliquid.xyz"])
hl.mids()["BTC"] # current mid price
hl.book("ETH", depth=5) # {"bids": [...], "asks": [...], "mid": ..., "spread": ...}
hl.positions("0xabc...") # account value + open positions for any address
hl.portfolio("0xabc...") # account-value / PnL history by period (day..allTime)
hl.funding() # funding / mark / oracle / OI per market
hl.predicted_fundings() # predicted funding per coin across venues (HL + CEXes)
hl.fills("0xabc...", limit=20) # recent fills
hl.fills_by_time("0xabc...", start_ms, end_ms) # fills within an epoch-ms window
hl.ledger("0xabc...") # deposits/withdrawals/transfers (non-funding ledger)
hl.health() # liveness probe: {ok, latency_ms, markets, error}
hl.spot_markets() # spot pairs: name, base/quote token, mid
hl.spot_balances("0xabc...") # spot token balances for any address
# live streams (open their own websocket — keep the returned Info alive)
hl.stream_book("ETH", lambda msg: print(msg["data"]["levels"][0][0]))
hl.stream_user_events("0xabc...", print) # live fills / funding / liquidations
# auto-reconnecting streams — survive a dropped connection (the SDK's don't):
# the supervisor rebuilds the socket and re-subscribes with backoff.
stream = hl.resilient_stream_book("BTC", on_msg, on_reconnect=lambda: print("reconnected"))
# ... stream.connected -> bool; stream.close() to stop
```
The CLI `watch` uses this, so a long-running order-book view recovers on its own after a network blip.
### Resilience (built in, configurable)
Every HTTP read goes through a default timeout, exponential backoff with jitter on
transient failures (network errors, HTTP 429/5xx → `HLReadError` once exhausted), an
optional client-side rate limit, and short-lived caching of the high-frequency market
endpoints (so e.g. `mid()` in a loop costs one fetch per cache window, not one per call).
Websocket streams can auto-reconnect (`resilient_stream*`), and you can point at a custom
endpoint with optional fallbacks (applied at connect and on persistent read failure).
```python
hl = HLRead(
max_retries=4, # retry transient failures
rate_limit_per_min=600, # cap HTTP calls/min (None = off)
cache_ttl=1.0, # seconds to cache mids / funding ctxs (0 = always fresh)
meta_ttl=300.0, # seconds to cache the market/token tables
http_timeout=10.0, # per-request timeout
api_url=None, # override endpoint (None = official mainnet/testnet)
fallback_urls=None, # e.g. ["https://api.hyperliquid.xyz"]; tried on failure
)
hl.clear_cache() # drop cached data on demand
```
## MCP server (the differentiator)
Expose read-only Hyperliquid data to any MCP client over stdio.
```bash
hl-read-mcp # mainnet
HL_READ_TESTNET=1 hl-read-mcp # testnet
```
**Claude Desktop** — add to `claude_desktop_config.json`:
```json
{
"mcpServers": {
"hl-read": { "command": "hl-read-mcp" }
}
}
```
**Claude Code:**
```bash
claude mcp add hl-read -- hl-read-mcp
```
Tools exposed to the model (16): `get_health`, `list_markets`, `get_mids`, `get_book`, `get_funding`, `get_funding_history`, `get_predicted_fundings`, `get_positions`, `get_portfolio`, `get_open_orders`, `get_ledger`, `get_fills`, `get_fills_by_time`, `get_candles`, `get_spot_markets`, `get_spot_balances`. None of them can place an order.
> Ask Claude: *"What's the funding on the top 5 Hyperliquid perps right now, and what's 0xabc…'s open position on the highest one?"* — it answers using only public reads.
## Safety model
- **No key, ever.** The library has no parameter, env var, or file from which it reads a private key.
- **No trading code in the import graph.** `hyperliquid.exchange.Exchange` is never imported, so signing/order/cancel functions are not reachable.
- **Read-only network calls.** Only Hyperliquid's public `info` endpoint and public websocket subscriptions are used.
This makes `hl-read` a sound base for monitoring bots, dashboards, and **autonomous agents** where you want market awareness without ceding the ability to spend.
## Development
```bash
pip install -e ".[dev]"
python -m unittest discover -s tests # or: pytest
```
The test suite is fully offline — the SDK is mocked, so it exercises the retry/backoff,
cache, and parsing logic deterministically without touching the network.
## License
MIT © akagifreeez. Not affiliated with Hyperliquid. Public market data only; nothing here is financial advice.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues