A multi-strategy Hyperliquid trading bot in TypeScript. Supports market making, momentum, grid/DCA, cross-venue arbitrage, and copy trading on perps and spot, testnet and mainnet.
Status: five live strategies (grid, momentum, market making, arbitrage, copy trading) + risk manager + state DB + kill-switch tests + live testnet smoke. Backtest harness with parameter sweep (
npm run sweep) inspired by the FORGE workflow — replay candles, rank by Sharpe / win rate / max DD.
npm install
copy .env.example .env # fill in HL_PRIVATE_KEY (testnet key shipped for dev)
npm start # boots, prints mids + account snapshotDefault config is DRY_RUN=true on testnet. No real orders are sent until you flip both.
Contact here
All config is loaded from .env and validated with zod (src/config.ts).
| Key | Default | Notes |
|---|---|---|
HL_PRIVATE_KEY |
— | Master account private key (0x-prefixed 32-byte hex). Required. |
HL_API_WALLET_KEY |
empty | Optional API-wallet (sub-signer) key. If set, this signs orders while HL_PRIVATE_KEY only identifies the master account. Recommended for live use — revoke from the HL UI if compromised. |
HL_NETWORK |
testnet |
testnet or mainnet. |
RISK_MAX_NOTIONAL_USD |
1000 |
Per-order notional cap. |
RISK_MAX_LEVERAGE |
3 |
Projected account-wide leverage cap (post-order). |
RISK_MAX_DRAWDOWN_PCT |
10 |
Max drawdown from high-water account value before kill switch trips. |
DRY_RUN |
true |
When true, orders are logged but not sent. |
LOG_LEVEL |
info |
trace / debug / info / warn / error / fatal. |
DB_PATH |
./data/state.db |
SQLite path for fills, intents, PnL, kill switch. |
BINANCE_WS_URL |
wss://fstream.binance.com/ws |
Used by the arbitrage strategy. |
For mainnet trading, do not put your master key in the bot. Instead:
- In the Hyperliquid UI, click More → API → Approve API Wallet (the master signs once).
- Save the API-wallet private key to
HL_API_WALLET_KEY. - Keep
HL_PRIVATE_KEYset to your master so the bot can read positions/fills, but the API wallet does the signing. - If the API wallet ever leaks, revoke it from the same UI page — funds stay safe.
src/
config.ts env loading + zod validation
logger.ts pino with pretty-print in dev
index.ts boot smoke
exchange/
client.ts HyperliquidClient — wraps info/exchange/ws SDK clients,
enforces DRY_RUN, formats prices/sizes per HL precision rules
types.ts friendly OrderIntent / Side / AccountSnapshot types
state/
db.ts node:sqlite — intents, fills, pnl_snapshots, kill_switch
risk/
manager.ts pre-trade checks (notional, leverage, kill switch),
drawdown watchdog, kill-switch tripping
strategy/ (M3) base interface + lifecycle
strategies/ (M4) market-making, momentum, grid, arbitrage, copy-trading
market/ (M4d) cross-venue feeds for arbitrage
runner.ts (M3) CLI: --strategy <name> --network <net>
| Strategy | Name in CLI | Required flags | Description |
|---|---|---|---|
| Grid / DCA | grid |
--coin --range-low --range-high --levels --size-per-level |
Ladder of post-only bids and asks across a price range. Each fill replenishes opposite side at adjacent level. |
| Momentum | momentum |
--coin --fast --slow --interval --size |
EMA-cross on candle close. Signal change → market order to flip target position. |
| Market making | mm |
--coin --spread-bps --size --max-inventory |
Quotes both sides around mid; inventory-aware skew shifts quotes opposite to position. |
| Arbitrage | arb |
--coin --threshold-bps --size |
HL vs Binance mark-price spread. When spread > threshold, take a directional HL position betting on revert. Trades only HL — does NOT hedge Binance. |
| Copy trading | copy |
--target-wallet --scale [--coin] |
Mirrors a target wallet's fills as market orders, scaled by --scale. |
| (smoke) | noop |
--coin |
Logs mid every 5s. No orders. Useful to verify the runner. |
Examples:
# Grid on BTC, 5 levels each side, $1k range, 0.001 BTC per level
npm run run:strategy -- --strategy grid --coin BTC --range-low 70000 --range-high 90000 --levels 5 --size-per-level 0.001
# Momentum 12/26 EMA cross on 5m candles, $100 notional
npm run run:strategy -- --strategy momentum --coin BTC --fast 12 --slow 26 --interval 5m --size 100
# MM with 20bps spread, 0.001 size, max 0.01 BTC inventory
npm run run:strategy -- --strategy mm --coin BTC --spread-bps 20 --size 0.001 --max-inventory 0.01
# Arb on BTC, enter at 30bps spread, exit at 5bps, $100 per leg
npm run run:strategy -- --strategy arb --coin BTC --threshold-bps 30 --size 100
# Copy trade a leader wallet at 0.1x scale
npm run run:strategy -- --strategy copy --target-wallet 0xc64c...3111 --scale 0.1Every order passes through RiskManager.checkOrder before submission:
- Kill switch — if on (set automatically on drawdown breach, or manually), all new orders are rejected.
- Per-order notional —
size × price ≤ RISK_MAX_NOTIONAL_USD. - Projected leverage —
(currentNotional + orderNotional) / accountValue ≤ RISK_MAX_LEVERAGEand≤ asset maxLeverage. Skipped forreduceOnlyand spot orders.
Independently, a periodic watchdog (snapshotAndCheckDrawdown) snapshots equity to SQLite and trips the kill switch if drawdown from high-water exceeds RISK_MAX_DRAWDOWN_PCT. Tripping the kill switch best-effort cancels all open orders.
npm run sweep runs a Cartesian grid backtest over strategies × assets × intervals × params, fetches mainnet candles (cached on disk for 1h), and prints a Sharpe-sorted leaderboard. Inspired by the FORGE autoresearch workflow — let machines explore the search space, then validate the winners with paper/live trading.
npm run sweep -- --strategy bb --assets BTC,ETH,SOL,HYPE --intervals 1h,4h \
--period 10,20,30 --k 1.5,2,2.5,3 --days 91Available backtest strategies:
| Strategy | Params | Description |
|---|---|---|
bb |
--period --k |
Bollinger Band Reversion: long below lower band, short above upper, exit at mean. |
Sweep flags: --days N, --initial-capital, --size, --slippage-bps, --fee-bps, --top N. The leaderboard is sorted by annualized Sharpe.
Limitations (same as the inspiration post, document them rather than hide them):
- No order-book slippage model — pass
--slippage-bps 5for sensitivity testing - Fees default to 0 — pass
--fee-bps 4.5to model HL taker fees - A high-Sharpe sweep result is not a green light to deploy capital. Validate via paper trading first, look for stability across parameter neighbors, and watch for over-fitting on a short window.
npm run dev # tsx watch — hot reload entry
npm start # one-shot boot
npm run run:strategy -- --strategy <name> [flags] # run a live/dry-run strategy
npm run smoke:testnet -- BTC # live testnet smoke (DRY_RUN=false, funded wallet)
npm run sweep -- [...] # parameter-sweep backtester
npm run typecheck # tsc --noEmit
npm test # vitest run- Never commit
.env. The.gitignorealready covers it. - Use a fresh wallet for the bot — not your main account. The bot only needs trading funds.
- Always test new strategies on testnet first. The HL testnet faucet: https://app.hyperliquid-testnet.xyz/drip
- Start with low
RISK_MAX_NOTIONAL_USDandRISK_MAX_LEVERAGE. Raise them only after the bot has run profitably for a week. - The kill switch persists in SQLite. To resume after a trip:
RiskManager.reset()or manuallyUPDATE kill_switch SET enabled=0 WHERE id=1;
Private. Do not redistribute.