Skip to content
hypurrquantPublic

About

Multi-DEX perpetual futures CLI + MCP server — Pacifica (Solana), Hyperliquid, Lighter (Ethereum). 18 MCP tools for AI-powered trading

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

39 stars

Watchers

0 watching

Forks

Latest commit

 

History

683 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

perp-cli

npm version npm downloads license

Multi-DEX perpetual futures CLI — Pacifica (Solana), Hyperliquid (HyperEVM), Lighter (Ethereum), Aster (BNB Chain), Lighter RH (Robinhood chain), Ondo Perps (off-chain), Arcus (Robinhood chain), QFEX (off-chain, TradFi perps).

npm install -g perp-cli       # global install
perp --json portfolio

# Or without global install (restricted environments)
npx -y perp-cli --json portfolio

Features

  • 8 Venues — trade on Pacifica, Hyperliquid, Lighter, Aster, Lighter RH, Ondo Perps, Arcus, QFEX (bridge / perp-perp arb cover the original four)
  • Funding Rate Arb — perp-perp + spot-perp scan & one-command dual-leg execution
  • Portfolio — single call returns balances, positions, risk level across all exchanges
  • Funds — deposit, withdraw, transfer, multi-provider bridge (cctp/relay/debridge), inter-exchange rebalance — all in one group
  • Bots — TWAP, grid, DCA, trailing-stop with background job management
  • Agent-First Design — --json, --fields, --ndjson, --dry-run, runtime schema introspection
  • Safety — pre-trade validation, response sanitization, client-id deduplication

Setup

# Import an exchange key into the encrypted OWS vault and make it the active wallet.
# The key is read from a hidden prompt or stdin — never argv (shell history), never ~/.perp/.env.
perp wallet set hl                   # Hyperliquid (EVM) — hidden prompt
pbpaste | OWS_PASSPHRASE="$PP" perp wallet set pac --name pac   # Pacifica (Solana) — piped
# The active wallet serves every venue; one EVM key covers HL / Lighter / Aster.
# Lighter trading also needs: perp wallet agent approve lighter

# Or the interactive setup wizard (all 7 venues): picks / creates / imports an OWS
# vault wallet, network, venues, registers agent wallets (y/N confirmation before
# any signature — never moves funds), explains + sets the slippage bound, and the
# default venue. It never writes keys to ~/.perp/.env.
perp setup

# Scriptable (CI / agents) — writes settings only, signs nothing:
perp --json setup --non-interactive --wallet <ows-wallet> --venues hyperliquid,aster \
  --network testnet --default-venue hyperliquid --slippage-bps 50 --slippage aster=80
# Add agent registration explicitly (Ondo key id + secret via stdin only):
OWS_PASSPHRASE=<pp> perp --json setup --non-interactive --wallet <ows-wallet> \
  --venues hyperliquid,arcus --approve-agents --yes --arcus-account-index 0

# Verify
perp wallet show

Same EVM key works for both Hyperliquid and Lighter.

Lighter API Key Index: Indexes 0–3 are reserved by Lighter's frontend (web/mobile). perp-cli defaults to index 4. Override with LIGHTER_API_KEY_INDEX env var, or use perp wallet agent approve lighter --api-key-index <n> for managed agent slots. Valid range: 4–254.

Lighter RH, Ondo Perps, Arcus

These venues have no wallet set private-key path — register an agent / API key instead:

perp wallet agent approve lighter-rh                  # Lighter RH L2 slot key (USDG collateral, Robinhood chain)
printf '%s\n%s\n' "$KEY_ID" "$SECRET" | perp wallet agent approve ondo   # Ondo HMAC key id + secret, stdin only
perp wallet agent approve arcus --master <ows-wallet> # Arcus Ed25519 API key (OWS wallet agent-arcus-<master>)
perp wallet agent verify [lighter-rh|ondo|arcus]      # no venue = verify every configured venue

No master wallet on this computer — import a key created on the exchange website

Create the agent / API key on the venue's website, then import it. The master wallet never has to be on this machine; it is identified only by its public address. The key is read from a hidden prompt or stdin (never argv) and checked against the venue before anything is stored — a refused check stores nothing; a venue that cannot be checked without the master is reported as unverified, never as verified.

perp -n testnet wallet agent import hyperliquid                    # API wallet key; master read from HL (userRole)
pbpaste | perp wallet agent import aster --master-address 0xYOU     # signer key; signed /fapi/v3/balance check (works on Aster testnet too)
perp wallet agent import pacifica --master-address <SOL account>   # agent key; UNVERIFIED (Pacifica lists bindings only master-signed)
perp wallet agent import lighter --account-index 123 --api-key-index 5   # slot key; auth token accepted for that slot
perp wallet agent import arcus --master-address 0xOWNER            # Ed25519 key; public key listed ACTIVE for the owner
printf '%s\n%s\n' "$KEY_ID" "$SECRET" | perp wallet agent import ondo
printf '%s\n%s\n' "$PUBLIC_KEY" "$SECRET" | perp wallet agent import qfex --account-id <uuid>   # QFEX: import only (keys are created on the website, 2FA)
perp wallet agent list                                              # SOURCE column: approved | imported

# Setup without any master wallet: one stdin line per --import-agents venue, in order (ondo: 2 lines)
printf '%s\n%s\n' "$HL_AGENT_KEY" "$LT_KEY" | perp --json setup --non-interactive \
  --venues hyperliquid,lighter --import-agents hyperliquid,lighter --yes \
  --lighter-account-index 123 --lighter-api-key-index 5

Trading works with the imported key. Deposits, withdrawals, transfers, bridge, referral set and agent approvals need the master: without it they fail with NO_SIGNER_AVAILABLE ("do it on the exchange website, or add the master with perp wallet import"). The CLI cannot revoke or rotate an imported key — revoke it on the website; perp wallet agent revoke <venue> <name> --local-only removes the local copy, and wallet agent import <venue> --agent-name <name> --replace swaps in a new website-created key. perp setup offers the same choice per venue: approve with this computer's master wallet, or import a website-created key (Step 1 can skip the master wallet).

Secrets are stored once (see docs/SSOT_RULES.md Rule #3): Lighter RH → ~/.perp/lighter-rh-agents/, Ondo → ~/.perp/ondo-agents/<keyId>.json, Arcus → OWS wallet agent-arcus-<master>; imported EVM / Solana / Ed25519 keys → OWS wallet agent-{hl,aster,pac,arcus}-import-<name> (empty passphrase, like approved agent wallets), imported Lighter keys → the network-tagged Lighter keystore. A missing wallet/key now fails with KEY_NOT_FOUND / NO_SIGNER_AVAILABLE instead of silently falling back to read-only.

Venues

Venue -e id (aliases) Trading Notes
Pacifica pacifica (pac) yes Solana
Hyperliquid hyperliquid (hl) yes HyperEVM; HIP-3 dexes via --dex
Lighter lighter (lt) yes Ethereum L2
Aster aster (ast) yes BNB Chain; funding interval is per symbol
Lighter RH lighter-rh (lrh, rh) yes Lighter engine on the Robinhood chain, USDG collateral
Ondo Perps ondo (ondo-perps) yes Off-chain engine; limit TIF GTC (default) / IOC / ALO; restricted: US, PA
QFEX qfex (qf) yes (see QFEX below) Custodial, off-chain engine; equities / indices / commodities, cross margin, USDC; limit TIF GTC (default) / IOC / FOK / ALO; testnet = QFEX UAT; restricted: US, GB, ES and others
Arcus arcus yes Robinhood chain, USDG collateral; limit TIF GTC (default, sent as GTT) / IOC / FOK / ALO; restricted: US, CA, GB; access whitelist — unlisted addresses are rejected (request access at arcus.xyz)
  • Time in force: trade limit defaults to GTC on every venue (common names GTC | IOC | FOK | ALO; a TIF the venue does not offer → CAPABILITY_UNSUPPORTED). Lighter post-only (ALO) is disabled until verified on the venue.
  • TP/SL on an entry: trade market|buy|sell|limit ... --tp <px> --sl <px> means the same on every venue — protect this entry's verified fill. The direction is checked before anything is sent (long: tp > reference > sl; short: the reverse; reference = mark for market entries, the limit price for limit entries). Ondo attaches the legs to the order; Arcus sends an entry+TP/SL batch; Hyperliquid / Lighter / Aster verify the entry fill, then place reduce-only TP/SL trigger orders sized to it (only market or --tif IOC entries — a resting entry → CAPABILITY_UNSUPPORTED); Pacifica verifies the fill, then sets position TP/SL (refused if the symbol already has a position or TP/SL — never overwritten). Entry outcome unknown → ORDER_PENDING and no TP/SL (the position may be unprotected); entry filled but a leg failed → ORDER_PARTIAL (not retryable) with the entry result and which legs were placed — do not re-enter, finish with trade tpsl.
  • TP/SL on a position: trade tpsl <SYM> <long|short> --tp <px> --sl <px> [--tp-limit <px>] [--size <n>] — the argument is the position's side (buy/sell no longer accepted), checked against the live position; legs are reduce-only and sized to the live position (or --size).
  • Stop orders are reduce-only by default on every venue (trade stop); pass --no-reduce-only to let a stop open or flip a position (refused on Ondo and QFEX, whose stops are always reduce-only). Lighter / Arcus market triggers execute as a limit at trigger ± the slippage bound (--slippage-bps or settings) and may stay unfilled in a fast move; other venues use native market triggers (--slippage-bps → CAPABILITY_UNSUPPORTED).
  • Order edit: trade edit keeps the order's TIF. Pacifica: post-only (ALO) orders are edited natively; GTC / TOB orders placed by perp-cli (TIF recorded in the client order id) are cancelled and replaced with the remaining open size; orders whose TIF is unknown → CAPABILITY_UNSUPPORTED (pass --tif).
  • Slippage bound: every market-type order (entry, close, spot) is bounded by one value: --slippage-bps <n> → settings.slippageBps.<venue> → settings.defaultSlippageBps (shipped default 50, shown in perp settings show; change with perp settings set defaultSlippageBps <n>). Values outside 1..venue max (Arcus 1000) are rejected before sending.
  • Restricted regions: creating a signing adapter for a venue with restricted regions (Ondo, Arcus, QFEX) prints a one-time stderr notice; it never blocks — check the venue terms yourself.
  • Aggregate views (portfolio, account positions/orders, risk, history, wallet agent verify, MCP portfolio) cover every account venue with configured credentials.

What works — mainnet verification (2026-10-13)

Every mark below comes from a real-money mainnet run, not from code reading — at the venue minimum, with the per-venue cap raised to about $25–30 for multi-slice / multi-level checks and about $110 for the Hyperliquid TWAP. Details, evidence and the open issues: docs/MAINNET-VERIFICATION-STATUS.md.

✅ verified live · ⛔ not supported (refused before anything is sent) · ❌ implemented but not run on mainnet yet · — not offered by the venue

Feature HL HIP-3 xyz Pacifica Lighter Lighter RH Aster Ondo Arcus QFEX
Market / limit (GTC, ALO, IOC), cancel, edit, close, reduce, flatten, status ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
Entry --tp/--sl, trade tpsl, trade stop ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
Stop-limit ✅ ✅ ✅ ✅ ✅ ✅ ⛔ ✅ ⛔
Resting reduce-only limit ✅ ✅ ✅ ✅ ✅ ✅ ⛔ ✅ ⛔ (IOC only)
Client order id (place / status / cancel) ✅ ✅ ✅³ (UUID) ✅ (numeric) ✅ (numeric) ✅ ✅ ✅ generated ids only
Isolated margin (set, read back with a position, revert) ✅ ✅ ✅ ✅ ✅ ❌ (venue rejected with -4050, condition unknown) ⛔ ✅ ⛔
trade scale-in / scale-tp ✅ ✅ (position ≥ $20.5) ✅ ✅ ✅ ✅ scale-in ✅ / scale-tp ⛔ — use partial trade tpsl --size ✅ ✅ scale-in ✅ / scale-tp ⛔
trade split ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
trade multi (legs on several venues) ✅ ✅ (global --dex xyz) ✅ ✅ ✅ ✅ ✅ ✅ ✅
Native TWAP (trade twap) ✅ ❌ (HL minimum $100) ✅ master-signed / ⛔ agent-signed —² —² —² —² —² —²
Client-side TWAP (trade twap on other venues, strategy twap, --background) — — — ✅ ✅ ✅ ✅ ✅ ⛔ (automation gate)
account margin with a position ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅
Spot (trade spot-*) ✅ — ✅ ✅ ✅ ❌ (needs USDT) ✅ ❌ (needs an Arcus-issued key) —
Deposit via perp-cli ✅ (HL) ✅ ✅ ✅ ✅ ✅ — (web app) — (address only)
Withdraw ❌ (HL) ❌ ❌ ❌ ❌ ❌ ❌ ❌

² perp-cli has no native TWAP for this venue: trade twap runs the client-side TWAP (slices) instead. Whether the venue's API offers one is not checked.
³ Verified in the session; no saved log file.

Automation, verified live (bounded runs at minimum size, stopped and flattened afterwards):

Area Verified
Arbitrage arb exec / status / close on Aster–Arcus, Lighter–Arcus; arb auto (Lighter–HL); spot-perp arb exec <sym> spot:hl pacifica and arb close; strategy funding-arb, quick-arb, funding-auto (Pacifica–HL); strategy delta-neutral (HL spot + Pacifica perp)
Bots strategy grid / dca / trailing-stop / quick-grid / quick-dca / preset (Aster); all 12 engine strategies via strategy start <config> (Aster); strategy apex (Aster)
Execution helpers strategy twap (Aster), trade twap --background (Arcus), strategy plan execute (9 of 10 action types — cancel_order not run), perp background stop (graceful: orders cancelled, positions listed)
Hyperliquid HIP-4 outcomes GTC place / cancel, IOC buy, outcome sell --all / --size

Not run on mainnet yet: withdrawals and funds transfer / rebalance execute / bridge exchange (run last), subaccounts, builder fees, strategy claude-agent (needs an Anthropic key), alerts / dashboard.

QFEX

QFEX is custodial: there is no wallet signature. The only credential is an API key created on the QFEX website (Developer Settings, 2FA), imported with perp wallet agent import qfex (public key + secret via hidden prompt / stdin; stored encrypted in ~/.perp/qfex-agents/). The import resolves the one account UUID the key trades (primary, or --account-id <uuid>), shows it and stores nothing until you confirm it (piped: pass --account-id equal to it). Create the trading key without the "Deposit and withdraw" permission.

perp -n testnet wallet agent import qfex              # QFEX UAT (api.qfex.io); y/N on the resolved account
perp -e qfex market list                              # public: /refdata + market-data snapshot
perp -e qfex trade limit AAPL buy 320 0.01            # GTC: "accepted" after the ACK; "open" once listed (trade status)
perp -e qfex trade market AAPL buy 0.01               # IOC LIMIT at mark ± slippage (never the venue's unbounded MARKET)
perp -e qfex trade status c:<id> --symbol AAPL        # by the generated client order id
perp funds deposit qfex                               # prints the USDC / Arbitrum One deposit address; you send the funds

Verified on QFEX production (2026-10-13): trade close / close-all / flatten / reduce (sent as reduce-only IOC), trade stop, trade tpsl (both legs), market entry with --sl, trade edit (native modify — a new order id, the client id is kept, so c:<id> keeps working), cancel / status by c:<id>.

What perp-cli still refuses on QFEX (uniform CAPABILITY_UNSUPPORTED, before anything is sent):

Refused Why Do instead
Resting reduce-only orders (trade limit --reduce-only with GTC / ALO, trade scale-tp) Live: a resting reduce-only order stays open after the position goes flat; how the venue treats it if it later matches is unverified Reduce-only IOC (trade close / reduce), or trade stop / trade tpsl
Stop-limit (--tp-limit, trade stop with a limit price) The venue's stop orders convert to market orders when triggered Stop-market
Stops that open or flip a position (trade stop --no-reduce-only) QFEX stop orders only reduce a position Reduce-only stops
trade edit of a reduce-only order A reduce-only order is sized against the live position when placed; a modify would skip that check trade cancel, then place again
--client-id Client ids are not unique on the venue; perp-cli only trusts ids it generates Omit it (the generated id is reported)
Markets not quoted in USD (SKHYNIX-KRW, …) Sizing, risk limits and notionals assume USD QFEX web app
Unattended automation on QFEX: bots, plans, TWAP, DCA, grid, funding arb, trailing stop, background jobs; QFEX in arb scan rankings Automation is gated until verified (QFEX_AUTOMATION_VERIFIED); the funding rate's unit is unverified and equity funding accrues only part of the week (Q4) Trade QFEX by hand; view funding only: perp arb scan --rates --include-unverified

Known caveat: cancelling a stop / TP right after its position was closed can answer "unexpected error" while the venue removes the stop itself. QFEX keeps no record of stop orders, so perp-cli cannot prove the cancel and reports ORDER_PARTIAL (pending) — check perp -e qfex account orders; if it lists nothing, the stop is gone.

Order outcomes are never guessed: an IOC / market order is final only on a venue terminal frame (nothing filled → ORDER_REJECTED, reason: iocNoFill); anything unclear after the order was sent is ORDER_PENDING with the c:<id> to check — never resubmit. perp-cli never enables QFEX cancel-on-disconnect, but another connection of the same user that enabled it (e.g. the official QFEX CLI) cancels all of the account's orders when that connection drops.

Withdrawals are authorized by the API key alone, so they are off until you set a local gate in an interactive terminal (no --yes, refused under --json / pipes / MCP): perp settings set withdraw.qfex <address[+address…]>,<maxPerTx>,<maxPerDay>, then perp funds withdraw qfex <amount> --to <allowlisted address> (--dry-run shows the plan and the gate verdict). The gate guards against mistakes and misdirected automation — it is not a defence against key theft; that defence is a trading key without the withdraw permission. QFEX itself documents that withdrawals need 2FA on the web app, so the API may refuse. Subaccounts: perp -e qfex funds transfer <amount> primary --from <account uuid>.

Spot trading

Spot support is declared per venue (VenueDefinition.spot) and every spot command, portfolio view and bot goes through one factory. Symbols are BASE/QUOTE; a bare base (ETH) uses the venue's first quote asset.

Venue Account model Quote Limit / book / cancel Spot↔perp transfer
Hyperliquid runtime (unified accounts share USDC with perp; standard accounts are separate) USDC yes yes (no-op on unified accounts)
Lighter / Lighter RH separate USDC / USDG yes yes
Aster separate (sapi spot account) USDT, USD1 (bare base → USDT) yes yes
Pacifica unified — spot shares the perp account USDC yes no (not needed)
Ondo Perps separate (spot wallet ↔ margin) USDC yes yes
Arcus wallet — on-chain swaps from your master EVM wallet (router, Permit2) USDG no (market swaps only) no
perp --json -e <EX> trade spot-buy <SYM> <SIZE> [--slippage-bps <n>] [--yes]
perp --json -e <EX> trade spot-sell <SYM> <SIZE> [--slippage-bps <n>] [--yes]
perp --json -e <EX> trade spot-limit <SYM> <buy|sell> <PRICE> <SIZE> [--tif GTC|IOC|ALO]
perp --json -e <EX> trade spot-cancel <SYM> <ORDER_ID>
perp --json -e <EX> trade spot-orders [SYM]
perp --json -e <EX> trade spot-transfer <to-spot|to-perp> <AMOUNT>   # moves the venue's first quote asset
perp --json -e <EX> trade spot-balance
  • Unsupported operations fail loudly with CAPABILITY_UNSUPPORTED (e.g. spot-limit / spot-cancel / spot-orders / spot-transfer on Arcus).
  • spot-transfer on a shared-balance account (Pacifica, Hyperliquid unified) succeeds as a no-op with execution.method: "sharedAccount" (nothing needs to move); a real move reports execution.method: "transfer".
  • Slippage: same rule as perps — --slippage-bps <n> → settings.slippageBps.<venue> → settings.defaultSlippageBps (shipped 50).
  • Pacifica: spot buys spend the shared USDC perp margin and reduce perp available margin (a warning is printed before the first buy). Pacifica getMarkets() (perp) no longer lists the SOL-USDC spot market.
  • Aster: an agent signer needs spot permission — perp wallet agent rotate aster --can-spot (or perp wallet agent approve aster --can-spot); otherwise spot orders fail with POLICY_DENIED.
  • Arcus: swaps go through router.spot.arcus.xyz and settle on the Robinhood chain from the master EVM wallet (--ows / active OWS wallet; none → NO_SIGNER_AVAILABLE). Spot needs only the master wallet — no Arcus perp agent key; perp orders / account reads without one fail with AGENT_NOT_REGISTERED (perp wallet agent approve arcus). Listing Arcus spot markets is slow (~80 s, one router /price per token) — use spot-buy / spot-sell directly. Tokens without EIP-2612 permit need a one-time on-chain approve(Permit2) that costs Robinhood Chain ETH gas — pass --yes to allow it. Results show status, finality, receivedToken and a remediation; a pending result means the swap was submitted — do not resubmit.
  • Results: spot orders print the normalized result (status, finality, filled size, average price, received token, remediation). spot-buy / spot-sell add an execution record on every venue (method, slippage bps + source, protection price and reference where the venue path computes one). spot-cancel returns one SpotOrderResult shape on every venue (a Lighter cancel is pending until spot-orders confirms it); spot-orders lists the same columns on every venue (Hyperliquid included).
  • Portfolio / landing: spot value is added on top of perp equity except balances marked shared (Pacifica USDC, Hyperliquid unified USDC). Tokens without a spot price are excluded from totals with a stderr warning (never valued at 0).
  • Bots and arb (funding-arb, spot-perp-arb, arb exec spot:<venue>, arb close, arb scan --mode spot-perp) only use spot venues with a separate (or runtime) spot balance and a spot↔perp transfer: hyperliquid, lighter, lighter-rh, aster, ondo. Pacifica (shared margin) and Arcus (on-chain swaps) are refused with CAPABILITY_UNSUPPORTED; trade them manually with trade spot-*.

Command Groups

Group Description
market Prices, orderbook, funding, klines, HIP-3 dexes
account Balance, positions, orders, margin
trade Market/limit/stop orders, close, scale, split execution
outcome Hyperliquid Outcome (HIP-4) — binary/range contracts, quoted per outcome (outcomeMeta quoteToken, USDC today), no leverage
arb Funding rate arb — scan, exec, close, monitor (perp-perp & spot-perp)
strategy 19 bot algorithms (grid, dca, twap, APEX, REFLECT, presets) + nested scripted plans
funds Deposit, withdraw, transfer, cross-chain bridge (multi-provider), inter-exchange rebalance
risk Risk limits, liquidation distance, guardrails
wallet Multi-wallet management, agent wallets (wallet agent ...), builder fees (wallet builder ..., off by default), margin mode / subaccount / API keys (wallet manage ...), on-chain balances
history Execution log, PnL, performance breakdown
portfolio Cross-exchange unified overview (replaces former account balance / status / dashboard)
health Adapter health check: ping every venue's REST endpoint (connectivity + latency)
settings CLI settings (referrals, defaults, fees, builder fees, deBridge affiliate)
backtest Strategy backtesting
background Background process supervisor (tmux sessions for strategies, alerts, etc.)
alerts Funding rate alerts (Telegram / Discord) with background daemon
setup Setup wizard: OWS wallet, venues, agent wallets, slippage, default venue (alias: init; --non-interactive for scripts)

Builder fees (off by default)

perp-cli attaches no builder fee unless you configure one and the venue approval is confirmed:

perp settings set builder.hyperliquid 0xBuilder…,1   # <address|code>,<feeBps> — strict: format, venue cap; asks y/N (or --yes)
perp wallet builder status                            # per venue: supported? configured? approved? attached?
perp --dry-run wallet builder approve hyperliquid     # plan only
perp wallet builder approve hyperliquid               # master-signed, asks y/N (or --yes)
perp --no-builder trade market BTC buy 0.1            # skip it for one command
perp settings unset builder.hyperliquid               # off again

Supported: hyperliquid (≤ 10 bps, not on HIP-3 dexes), pacifica (≤ 10 bps max, not on spot), aster (≤ 10 bps, mainnet), ondo (≤ 10 bps, no approval step), qfex (perp settings set builder.qfex <uuid> — a fee share: your fills are attributed to the builder code and you pay the normal fee, nothing extra; the code rides on the trading connection; mainnet only). Lighter / Lighter RH / Arcus: unsupported. If the approval is missing or cannot be read, the order is sent without the fee and the result's execution.notes says why; execution.builderFee shows what was attached.

Core Commands

# Portfolio (balances + positions + risk across all exchanges)
perp --json portfolio

# Market data
perp --json -e <EX> market list
perp --json -e <EX> market book <SYM>
perp --json -e <EX> market mid <SYM>              # fast mid-price lookup
perp --json -e <EX> market funding <SYM>
perp --json -e <EX> market kline <SYM> 1h          # candlestick data
perp --json -e hl market hip3                       # list HIP-3 deployed dexes

# Trading
perp --json -e <EX> trade buy <SYM> <SIZE>          # shortcut for market buy
perp --json -e <EX> trade sell <SYM> <SIZE>         # shortcut for market sell
perp --json -e <EX> trade market <SYM> buy <SIZE> --smart  # IOC limit (less slippage)
perp --json -e <EX> trade split <SYM> buy 5000      # orderbook-aware split (large orders)
perp --json -e <EX> trade close <SYM>
perp --json -e <EX> trade flatten                    # close ALL positions on exchange
perp --json -e <EX> trade reduce <SYM> 50            # reduce position by 50%
perp --json -e <EX> trade cancel <SYM>               # cancel by symbol (or orderId)
perp --json -e <EX> trade buy <SYM> <SIZE> --tp <PX> --sl <PX>  # entry protected by TP/SL
perp --json -e <EX> trade tpsl <SYM> long --tp <PX> --sl <PX>   # TP/SL on an open position (long|short)
perp --json -e <EX> trade stop <SYM> sell <SIZE> <PX>            # reduce-only stop (default)
perp --json -e <EX> trade leverage <SYM> <N>

# Account
perp --json portfolio -e <EX>                        # balance + spot + positions (account balance was renamed in v0.12)
perp --json -e <EX> account positions
perp --json -e <EX> account pnl                      # realized + unrealized + funding
perp --json -e <EX> account funding                  # personal funding payment history
perp --json -e <EX> account settings                 # per-market leverage & margin mode

# Outcome markets (Hyperliquid HIP-4 — fully-collateralized binary contracts, quote token per outcome (USDC today), min 10 quote tokens)
perp --json outcome list                                       # active markets + Yes/No mid prices
perp --json outcome view <outcome>                             # symmetric Yes/No book + underlying gap + expiry
perp --json outcome book <outcome> <side>                      # one-side orderbook (e.g. '1 yes' or '1 0')
perp --json outcome positions                                  # open outcome holdings
perp --json outcome orders                                     # open outcome orders
perp --json outcome buy <outcome> <side> <usd> --dry-run       # validate before submit
perp --json outcome buy <outcome> <side> <usd>                 # market buy, notional in the outcome's quote token
perp --json outcome sell <outcome> <side> <usd> --limit <px> --tif gtc
perp --json outcome cancel <outcome> <side> <oid>

# Funding rate arbitrage
perp --json arb scan --min 5                         # perp-perp opportunities
perp --json arb scan --mode spot-perp                # spot+perp opportunities
perp --json arb scan --rates                         # funding rates across all exchanges
perp --json arb scan --basis                         # cross-exchange basis opportunities
perp --json arb scan --gaps                          # cross-exchange price gaps
perp --json arb scan --hip3                          # HIP-3 cross-dex funding spreads
perp --json arb scan --live                          # continuous live monitoring
perp --json arb exec <SYM> <longEx> <shortEx> <$>   # perp-perp dual-leg entry
perp --json arb exec <SYM> spot:<exch> <perpEx> <$>  # spot+perp entry
perp --json arb config                               # show arb defaults
perp --json arb history                              # past arb trade performance (alias: log)

# Funds (deposit, withdraw, transfer, bridge, rebalance)
perp --json funds deposit hyperliquid 100
perp --json funds withdraw pacifica 50
perp --json funds deposit lighter-rh 10                # USDG on Robinhood Chain (approve + deposit, mainnet)
perp --json -e lighter-rh funds withdraw lighter 10    # USDG → Robinhood Chain
perp --json --dry-run funds withdraw ondo 10 --to <ADDRESS>   # plan only, nothing sent
perp --json funds deposit aster 8                      # USDT → Aster vault on BNB Chain (--chain arbitrum / --asset USDC; mainnet)
perp --json funds withdraw aster 8 --chain bsc         # USDT → your own address (agent needs --can-withdraw --ip-whitelist)
perp --json funds deposit ondo 12 --probe 2            # USDC transfer to your Ondo funding address (Arbitrum; --chain ethereum)
perp --json funds address-book add ondo <MASTER_ADDR>  # SIWE challenge → Ondo withdrawal address book
perp --json funds withdraw arcus 10                   # to the Arcus account owner
perp --json funds transfer 100 <ADDRESS>             # HL internal transfer (instant)
perp --json funds bridge quote --from solana --to arbitrum --amount 100
perp --json funds bridge send --from solana --to arbitrum --amount 100   # auto-cheapest provider
perp --json --dry-run funds bridge send --from robinhood --to solana --from-asset USDG --to-asset SOL --amount 15   # Relay quote only
perp --json funds bridge send --from robinhood --to bsc --from-asset USDG --to-asset USDT --amount 15               # Relay swap, OWS master signs
perp --json funds bridge exchange --from pacifica --to hyperliquid --amount 100
perp --json funds rebalance check                    # balances across exchanges
perp --json funds rebalance plan                     # compute optimal moves
perp --json funds rebalance execute --auto-bridge    # withdraw → bridge → deposit
perp --json funds info                               # all routes & limits

# Risk
perp --json risk limits --max-leverage 5
perp --json risk liquidation-distance

# Strategies (19 bot algorithms + nested scripted plans)
perp strategy list-strategies                        # list all available strategies
perp strategy run <strategy> [symbol]                # run any strategy
perp strategy apex [symbol]                          # APEX autonomous orchestrator
perp strategy reflect                                # trading performance analysis
perp strategy preset-list                            # list strategy presets
perp --json strategy twap <SYM> buy <SIZE> 30m
perp --json strategy grid <SYM> --range 5 --grids 10 --size 100
perp strategy plan example                           # scripted multi-step plan format
perp --json strategy plan validate <FILE>            # validate scripted plan
perp --json strategy plan execute <FILE> --dry-run   # dry-run scripted plan

# Background process supervisor (tmux)
perp background list                                 # list running jobs
perp background stop <ID>                            # stop a job
perp background logs <ID> -f                         # follow logs
# Jobs inherit -n, --dry-run, -e, --ows, -w, --no-agent, --dex and never receive keys via argv/env:
# they read the OWS vault / agent keystores / ~/.perp/.env themselves. -k, --passphrase, --ows-key or a
# shell-exported key / OWS_PASSPHRASE is refused — register an agent (perp wallet agent approve <venue>).

Telegram Alerts

Funding rate alerts via Telegram with background daemon support.

# Interactive setup (BotFather token + chat ID auto-detection)
perp alerts setup

# Add alert rules
perp alerts add ETH 30              # alert when ETH funding > 30% annualized
perp alerts add --all 50            # alert for any symbol > 50%

# Test & manage
perp alerts test                    # send test message
perp alerts list                    # show active rules

# Run daemon
perp alerts start                   # foreground
perp alerts start --background      # tmux background daemon
perp alerts stop                    # stop background daemon

Setup flow: BotFather token → bot validation → send /start to bot → auto-detect chat ID → test message.

Exchange flag: -e hyperliquid / -e pacifica / -e lighter / -e aster (aliases: hl, pac, lt).

Global flags: --json, --fields <f>, --ndjson, --dry-run, --dex <name> (HIP-3), -w, --wallet <name>.

MCP Server

Glama MCP server

perp-cli includes a full-featured MCP server (18 tools, 3 resources, 2 prompts) for Claude Desktop, Cursor, and other MCP clients.

No API keys required for market data — explore prices, orderbooks, funding rates, and arb opportunities without any setup. Add keys only when you want to trade.

Network: set PERP_NETWORK=testnet in the server env to serve testnet (validated; unset = mainnet); every result reports meta.network. trade_execute / trade_close place real orders through the same local risk gate as perp trade (no override over MCP), refuse non-reduce-only orders on quarantined symbols, and are written to the execution log.

{
  "mcpServers": {
    "perp-cli": {
      "command": "npx",
      "args": ["-y", "-p", "perp-cli", "perp-mcp"]
    }
  }
}

For trading and account data, run perp setup first: the MCP server reads the same OWS vault wallet and agent keystores as the CLI. Never put private keys in the MCP config. Select the network with PERP_NETWORK (mainnet | testnet; unset = mainnet, invalid values stop the server):

{
  "env": {
    "PERP_NETWORK": "testnet"
  }
}

Read-only tools (no keys): get_markets, get_orderbook, get_funding_rates, get_prices, arb_scan, health_check

Account & trading tools (keys required): get_balance, get_positions, portfolio, trade_preview, trade_execute, trade_close, get_funding_analysis, get_pnl_analysis, get_arb_compare

Resources: market://prices, market://funding-rates, perp://schema

Prompts: trading-guide, arb-strategy

AI Agent Skill

Drop-in skill for Claude Code, Cursor, Codex, Gemini CLI, and other agent CLIs. Bundles a non-interactive command guide, ops playbook, strategy framework, and reusable shell scripts (preflight, arb monitor, validation) so your agent stops at the right confirmation points and never wedges on interactive wizards.

Install

# Claude Code — slash command
/install-skill hypurrquant/perp-cli

# Cursor / Codex / generic agent CLIs — via npx
npx skills add hypurrquant/perp-cli

# Manual install (any agent that reads a Skills directory)
git clone https://github.com/hypurrquant/perp-cli.git
cp -R perp-cli/skills/perp-cli ~/.claude/skills/        # or your CLI's skills dir

The skill ships inside the npm package (perp-cli/skills/perp-cli), so a global install also makes it available locally:

npm install -g perp-cli@latest
ls "$(npm root -g)/perp-cli/skills/perp-cli"

What's in the skill

File Purpose
SKILL.md Top-level agent guide — rules, workflows, examples
references/commands.md Full non-interactive command reference (every group)
references/agent-operations.md Setup flows, idempotency, error handling, common mistakes
references/strategies.md Funding-arb decision framework + risk management
scripts/preflight.sh Install + wallet + connectivity + risk readiness check
scripts/arb-monitor.sh Live monitor for open arb positions
scripts/spot-perp-scan.sh Scan spot+perp opportunities with balance context
scripts/funding-analysis.sh Cross-exchange funding overview / per-symbol drilldown
scripts/validate-arb.sh Pre-execution validation (price / balance / risk / dry-run)

See skills/perp-cli/SKILL.md for the full agent guide.

Agent-First CLI Design

Built following agent-first CLI principles:

# Every command returns structured JSON envelope
perp --json portfolio
# → { "ok": true, "data": {...}, "meta": { "timestamp": "..." } }

# Filter output to specific fields (saves tokens)
perp --json --fields totalEquity,risk portfolio

# Stream large lists as NDJSON (one JSON per line)
perp --json --ndjson -e hl market list

# Pre-validate before executing
perp --json -e hl trade check BTC buy 0.01
perp --json --dry-run -e hl trade market BTC buy 0.01

# Idempotent orders with client ID (Hyperliquid: a 128-bit cloid, 0x + 32 hex; --auto-id generates one)
perp --json -e hl trade market BTC buy 0.01 --client-id 0x1234567890abcdef1234567890abcdef
perp --json -e hl trade status c:0x1234567890abcdef1234567890abcdef

All responses are auto-sanitized (control chars stripped, prompt injection patterns blocked). Errors include retryable flag — only retry when true.

License

MIT

About

Multi-DEX perpetual futures CLI + MCP server — Pacifica (Solana), Hyperliquid, Lighter (Ethereum). 18 MCP tools for AI-powered trading

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

39 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages