中文文档 / Chinese documentation → README.zh-CN.md
Open-source two-venue perp arbitrage bot. One leg is always Entropy
(the io builder dex on Hyperliquid); the other leg — the hedge — is one of:
--hedge |
venue | quote | taker fee | protocol |
|---|---|---|---|---|
lighter |
Lighter mainnet | USDC | 0 bps | zkLighter ws (diff books, async settle) |
lighter-rh |
Lighter Robinhood chain | USDG | 0 bps | zkLighter ws |
tradexyz |
Hyperliquid trade.xyz dex | USDC | ~1 bps | HL l2Book, sync IOC settle |
Referral links — signing up through these supports this project:
- Entropy — Tier 4 referral, 100% rebates: https://entropy.io/?r=yourquantguy
- Lighter Robinhood chain: https://robinhoodchain.lighter.xyz/?referral=QUANT
- trade.xyz (Hyperliquid): https://app.hyperliquid.xyz/join/QUANTGUY
When the same symbol trades rich on one venue and cheap on the other, the bot
simultaneously sells the rich book and buys the cheap book with taker orders,
carrying a delta-neutral position until the premium reverts and the opposite
crossing unwinds it. Every price it acts on is the actual order book of the
exchange that will fill the order — Hyperliquid books come from the official
websocket (wss://api.hyperliquid.xyz/ws), Lighter books from Lighter's
official websocket.
While it runs — even with no credentials and no strategy — it records both books to 1-minute CSV bars, and the bundled analyzer turns that data into the three numbers that define the whole strategy.
The band is three numbers in config.yaml, derived by you from recorded
data:
premium_bps = (Entropy price / hedge price − 1) × 10 000
┌────────────── SELL entropy + BUY hedge
midline + upper ───────────────────────────────────────────────────
▲
midline ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┼ ─ ─ the premium's usual level
▼
midline − lower ───────────────────────────────────────────────────
└────────────── BUY entropy + SELL hedge
midline_bps— where the premium normally sits. Cross-venue premiums are rarely centered at zero (different oracles, different quote assets, listing premia), so a zero-centered band would fire one direction only, cap out and never unwind. Measure where the premium actually sits and type it in.upper_bps/lower_bps— the entry bands on each side of the midline.
Both hurdles are applied to executable prices (entropy bid vs hedge ask, and vice versa) and are net of both venues' taker fees — the engine adds fees on top before a slice qualifies. A full round trip therefore nets ≥ upper + lower bps after fees by construction.
One consequence worth understanding: with midline_bps: 5, the buy-entropy
hurdle is lower − midline, which can be negative. That is intentional —
if entropy is persistently 5 bps rich, buying it at a 0 bps premium is 5 bps
cheap versus its own equilibrium, and that trade is the profitable unwind of
an earlier sell at midline + upper. It also means a wrong midline loses
money: if you type midline_bps: 5 while the true premium sits at 0, the
bot happily buys entropy at fair value all day. Measure first, then trade —
that is what the recorder and analyzer are for.
git clone https://github.com/your-quantguy/entropy-arb.git && cd entropy-arb
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt # data collection needs only this
cp config.example.yaml config.yaml # the strategy (thresholds, sizing, risk)
cp .env.example .env # credentials — required to tradeThe markets are not in the config file — you state them explicitly on
every start: --symbol (traded on both venues) and --hedge (one of
lighter, lighter-rh, tradexyz; Entropy is always the
other leg).
There is no paper mode — the bot either collects data (--record-only)
or trades live. Validate with recorded data and tiny position caps, not with
simulated fills.
1. Collect data first (no credentials needed):
python3 main.py --record-only --symbol SNDK --hedge lighter-rhLet it run for at least a few hours (a day is better — premiums have
intraday regimes). It writes logs/minutes.csv.
2. Analyze and set your thresholds:
python3 tools/analyze.pyIt prints the premium distribution, how often each candidate band would have
fired, and a ready-to-paste thresholds: block for config.yaml.
3. Go live — fill in .env, install the signing SDKs, and start with
the smallest position caps that clear the venue minimums:
pip install -r requirements-live.txt
python3 main.py --symbol SNDK --hedge lighter-rhRunning without --record-only sends real orders immediately once both
feeds are fresh and the band is crossed.
Dashboard. On a terminal the bot shows a live Rich dashboard: both
books with age/spread, positions and caps, equity and session PnL, the
executable premium of each direction against its full hurdle (fees and
inventory surcharge included, ● = armed), recorder progress, the last
executions, and a tail of the log (the full log goes to logging.file,
default logs/engine.log). It works in --record-only too. Add --cn to
display the dashboard in Chinese. Use --no-dashboard for plain console
logs (nohup/systemd — off-terminal runs fall back automatically), or set
logging.dashboard: false.
The recorder runs automatically in every mode (recorder.enabled: true).
Once per second it samples both live books; once per minute it writes a row:
| column | meaning |
|---|---|
minute_ts, time_utc |
minute start (epoch seconds, ISO UTC) |
entropy_bid/ask, hedge_bid/ask |
last fresh top-of-book of the minute |
premium_open/high/low/close/mean/std_bps |
mid-to-mid premium of Entropy over the hedge |
sell_edge_mean/max_bps |
executable premium for SELL entropy (entropy bid / hedge ask − 1) |
buy_edge_mean/max_bps |
executable premium for BUY entropy (hedge bid / entropy ask − 1) |
samples |
how many of the ~60 seconds both books were fresh |
Recorded edges are pre-fee; the analyzer subtracts --fees-bps (pass the
sum of both venues' taker fees — default 0.0 for the zero-fee venues,
~1.0 with a tradexyz hedge) before counting firings, so its table and
suggestions translate directly into config values. --hours 24 restricts to
recent data; premiums drift, so re-run it regularly and update
config.yaml.
Strategy lives in config.yaml (validated — unknown keys are startup
errors), credentials in .env, and the markets on the command line
(--symbol, --hedge). Full commented reference:
config.example.yaml. The essentials:
| key | meaning | default |
|---|---|---|
thresholds.midline_bps |
premium center (measure it!) | — |
thresholds.upper_bps / lower_bps |
entry bands (> 0) | — |
entropy.dex |
Entropy's dex name on Hyperliquid | io |
*.taker_fee_bps |
per-venue taker fee | 0.0 (tradexyz hedge: 1.0) |
*.max_position_usd |
per-venue position cap | 1000 |
*.max_orders_per_min |
per-venue send budget (sliding 60 s) | 120; lighter hedges 30 |
sizing.take_fraction |
fraction of crossable depth taken | 0.5 |
sizing.max_order_notional_usd |
per-slice cap | 500 |
inventory.scale_bps / floor_frac |
inventory ladder (extra bps past floor_frac of the cap) |
10 / 0.5 |
execution.premium_persist_sec |
edge must persist before firing | 0.3 |
execution.* |
slippage bounds, timeouts, reconcile cadence… | see file |
recorder.* |
minute-data recorder | on, logs/minutes.csv |
logging.dashboard / logging.file |
Rich dashboard on a tty; log file while it runs | on, logs/engine.log |
- Entropy / tradexyz (Hyperliquid) — create an API ("agent") wallet at
https://app.hyperliquid.xyz/API.
HL_PRIVATE_KEYis the agent key,HL_ACCOUNT_ADDRESSyour main account address. With--hedge tradexyzboth legs share this account by default (one nonce sequence is handled internally); setHL_PRIVATE_KEY_XYZ/HL_ACCOUNT_ADDRESS_XYZto split them. Fund the dex-specific clearinghouses you trade. - Lighter —
LIGHTER_ACCOUNT_INDEX,LIGHTER_API_KEY_INDEX,LIGHTER_API_PRIVATE_KEY, registered on the same deployment as your--hedgeflag (mainnet and the Robinhood chain are separate accounts and keys — see lighter-python).
- Both legs are taker orders sent concurrently: Lighter market orders with average-price protection settling on the authenticated account websocket; Hyperliquid IOC limits settling synchronously (with orderStatus polling for unknown outcomes).
- A persistence gate (
premium_persist_sec) arms each direction and only fires if the edge survives — one-tick phantoms are filtered. - Inventory ladder: past
floor_fracof a venue's cap, adding to the position requires linearly more edge, up toscale_bpsextra at the cap. - Net-delta hedge: if legs fill unevenly, the imbalance is immediately
reduced (reduce-only, price-protected), and positions are reconciled
against the chain every
reconcile_sec. - Failure containment: a rate-limited venue pauses briefly; an
unreachable venue (e.g. exchange maintenance) pauses trading and is probed
every
venue_probe_secuntil it recovers;max_consecutive_errorsexecution pathologies halt the engine entirely. - Live-only: there is no simulated-fill mode.
--record-onlyis the risk-free way to run it; anything else trades real money.
main.py entry point (--record-only, or live by default)
entropy_arb/config.py YAML + .env contract, validation
entropy_arb/book.py order books + fee-aware crossing/sizing math
entropy_arb/feeds.py official HL ws + zkLighter ws book feeds
entropy_arb/venue_hl.py Hyperliquid dex adapter (Entropy, tradexyz)
entropy_arb/venue_lighter.py zkLighter adapter (mainnet, Robinhood chain)
entropy_arb/engine.py the two-venue strategy loop
entropy_arb/dashboard.py Rich terminal dashboard
entropy_arb/recorder.py 1-minute orderbook bars
tools/analyze.py minutes.csv -> suggested thresholds
tests/ python3 -m pytest tests/
- A wrong midline is a losing strategy. The premium center drifts;
re-measure regularly and keep
config.yamlcurrent. - USDG basis (
lighter-rh): the hedge quotes in USDG. Part of any persistent premium is the stablecoin itself; your midline absorbs the level, but a USDG move is real PnL. - Funding: two venues, two independent funding rates; carry is not modeled. Position caps bound it — keep them modest.
- Thin books: Entropy depth can be tiny;
take_fractionand notional caps keep clips small, but slippage on the hedge leg after a partial fill is real. - Market hours: for equity perps (e.g. SNDK), off-hours oracle regimes differ per venue; consider wider bands or not trading them.
- One-leg risk: a leg can fail after the other filled. The bot hedges and reconciles automatically, but you should still watch it.
Use at your own risk. This is trading software operating with real money; nothing here is investment advice. Start with tiny position caps.