A read-only research terminal for discovering mispricings in Hyperliquid HIP-4 prediction markets. It does not trade, never touches real funds, never stores private keys, and never auto-orders.
It detects four classes of pricing error:
- YES/NO arbitrage — same-event binary where
YES ask + NO ask < 1.0. - Logical arbitrage — nested-threshold events where the stricter event is priced above the event that logically contains it.
- Cross-market arbitrage — structurally identical events priced differently across distinct contracts.
- Early-stage illiquid mispricing — thin books where the orderbook rarely admits a fair price.
HIP-4 outcome assets are ordinary Hyperliquid CLOB coins. An outcome id N
with binary side s (0=YES, 1=NO) is encoded as:
coin = #(N*10 + s) e.g. outcome 1209 side 0 -> "#12090"
token = +(N*10 + s)
asset id = 100_000_000 + N*10 + s
The scanner reads the live outcomeMeta catalog from
https://api.hyperliquid.xyz/info, streams l2Book + allMids over the
public WebSocket, and evaluates the detectors in-memory.
hip4-arb/
├── src/
│ ├── main.py # Scanner orchestrator (live loop)
│ ├── config.py # YAML + env config (no secrets)
│ ├── log.py # logging
│ ├── types.py # core domain types + outcome encoding
│ ├── api/
│ │ ├── client.py # read-only REST info client
│ │ └── websocket.py # live WS subscriber (l2Book/allMids)
│ ├── market/ # catalog+books -> MarketSnapshot
│ ├── parser/
│ │ ├── descriptions.py# structured description parser
│ │ └── events.py # natural-language event parser
│ ├── arbitrage/
│ │ ├── models.py # ArbOpportunity, ArbLeg, ArbType
│ │ ├── detector.py # YES/NO arb
│ │ ├── logical.py # event graph + logical arb
│ │ └── cross.py # cross-market arb
│ ├── risk/ # fee/slippage/depth realism model
│ └── notifier/ # Telegram alerts (optional)
├── tests/ # unit tests (pytest)
├── config.example.yaml
├── requirements.txt
└── run_scanner.py # entry point
cd hip4-arb
python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS/Linux
source .venv/bin/activate
pip install -r requirements.txtCopy the example config and fill in only what you need:
cp config.example.yaml config.yamlTelegram alerts require a bot token + chat id from the environment (never committed):
export TELEGRAM_BOT_TOKEN="..."
export TELEGRAM_CHAT_ID="..."Continuous scanner (read-only):
python run_scanner.py --config config.yamlOne-shot scan (cron / smoke test):
python run_scanner.py --config config.yaml --onceEach opportunity is logged with:
[THREAT_TYPE] name | cost | gross% | expected% | risk
buy yes #<coin> @ price (size)
buy no #<coin> @ price (size)
expected% is the gross edge after taker fees and a conservative slippage
model; risk is low/medium/high based on depth vs maximum modeled size.
python -m pytest tests/ -q- Read-only by design. No signing, no orders, no keys. Removing that boundary is a deliberate, separate step.
- Do not trust a title. Cross-market detection matches only on structural identity (asset + threshold + expiry window). Always verify settlement rules before acting.
- Slippage & depth. A clean
YES+NO < 1signal is not a tradeable edge if the book is 20 shares deep. The risk module is conservative by design. - Market efficiency. Live mainnet books currently often price to just over 1.00 — zero opportunities is an expected, correct result, not a bug.
- Dry-run paper trading with max-cap and kill-switch (default off).
- Settled-outcome reconciliation to detect rule-mismatch arb.
- Multi-outcome question-group arbitrage (merge/negate paths).
- Database-backed historical signal store.
Run the scanner continuously without a human at the terminal. Pick one host
path; the service files are portable and were authored against Linux/systemd
and Docker but were not executed on the current Windows host (no Docker or
systemctl is present there).
schtasks /create /tn hip4-scanner /tr "cmd /c cd C:\path\to\hip4-arb && .venv\Scripts\python run_scanner.py --config config.yaml" /sc onlogon /fsudo cp deploy/hip4-scanner.service /etc/systemd/system/ && sudo systemctl daemon-reload && sudo systemctl enable --now hip4-scannerdocker build -t hip4-arb . && docker run -d --name hip4-scanner --restart=always -v hip4-data:/app/data hip4-arbSet HIP4_LOG_PATH to a writable directory (e.g. logs) for daily rotation
with 14 retained backups; otherwise logs go to stderr only.
export HIP4_LOG_PATH=logs