Table of Contents generated with DocToc
Python CLI for Hyperliquid account management, market data, and order execution.
- Python 3.10+
hyperliquid-python-sdkfor API interactionsrichfor pretty console outputeth-accountfor key managementNuitkafor building the single binary from source- Optional:
makefor installation and uninstallation scripts
This project builds release artifacts as Nuitka onefile binaries. The fastest
way to use hl is to download the matching binary from GitHub Releases and put
it somewhere on your PATH. If you do not trust the binary artifact, or if you
hit a binary-specific bug, install from PyPI with pip install or clone the
repository and use pip install -e ..
GitHub Releases include Nuitka-built single binaries for:
hl-linux-x86_64hl-linux-arm64hl-macos-arm64hl-macos-x86_64hl-windows-x86_64.exe
Linux x86_64:
TAG=v0.1.14
curl -L -o hl "https://github.com/haturatu/hl/releases/download/${TAG}/hl-linux-x86_64"
chmod +x hl
mkdir -p ~/.local/bin
mv hl ~/.local/bin/hl
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
hl --helpLinux arm64:
TAG=v0.1.14
curl -L -o hl "https://github.com/haturatu/hl/releases/download/${TAG}/hl-linux-arm64"
chmod +x hl
mkdir -p ~/.local/bin
mv hl ~/.local/bin/hl
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
hl --helpmacOS Apple Silicon:
TAG=v0.1.14
curl -L -o hl "https://github.com/haturatu/hl/releases/download/${TAG}/hl-macos-arm64"
chmod +x hl
mkdir -p ~/.local/bin
mv hl ~/.local/bin/hl
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
hl --helpmacOS Intel:
TAG=v0.1.14
curl -L -o hl "https://github.com/haturatu/hl/releases/download/${TAG}/hl-macos-x86_64"
chmod +x hl
mkdir -p ~/.local/bin
mv hl ~/.local/bin/hl
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
hl --helpWindows PowerShell:
$Tag = "v0.1.14"
$BinDir = "$env:USERPROFILE\bin"
New-Item -ItemType Directory -Force -Path $BinDir | Out-Null
Invoke-WebRequest `
-Uri "https://github.com/haturatu/hl/releases/download/$Tag/hl-windows-x86_64.exe" `
-OutFile "$BinDir\hl.exe"
$UserPath = [Environment]::GetEnvironmentVariable("Path", "User")
if ($UserPath -notlike "*$BinDir*") {
[Environment]::SetEnvironmentVariable("Path", "$UserPath;$BinDir", "User")
}
& "$BinDir\hl.exe" --helpOpen a new PowerShell session after updating the user PATH. Then run:
hl --helpmake binary and make install build a Nuitka onefile executable. They do not
install the Python console script generated by pip.
Build the single binary from git, install it to ~/.local/bin/hl, and set up
Bash completion with make install:
git clone https://github.com/haturatu/hl.git
cd hl
make installBuild the binary without installing it:
make binary
./dist/hl-linux-x86_64 --helpRemove local build outputs, Nuitka output directories, and the build virtualenv:
make cleanInstall from source for local development:
cd hl
python3 -m pip install --user -e .Install from PyPI:
pip install --user hyperliquid-cli-pythonAfter installation, the hl command is available:
hl --helphl can print a Bash completion script for top-level commands and subcommands.
Note: pip install -e . and pip install hyperliquid-cli-python install the
hl command, but they do not automatically enable Bash completion.
Enable it for the current shell:
eval "$(hl completion bash)"Persist it in ~/.bashrc:
echo 'eval "$(hl completion bash)"' >> ~/.bashrcTo remove the package and any managed ~/.bashrc completion line:
make uninstall$ hl --help
usage: hl [-h] [--json] [--testnet] {account,order,asset,markets,referral,completion} ...
CLI for Hyperliquid DEX
positional arguments:
{account,order,asset,markets,referral,completion}
account Account management and information
order Order management and trading
asset Asset-specific information
markets Market information
referral Referral management
completion Print shell completion script
options:
-h, --help show this help message and exit
--json Output in JSON format
--testnet Use testnet
Command tree:
account add|ls|set-default|remove|positions|orders|balances|portfolio
order ls|limit|market|tpsl|twap|twap-cancel|cancel|cancel-all|set-leverage|configure
asset price|book|leverage
markets ls
referral set|status
Examples:
hl account add
hl order twap buy 1 BTC 30 --randomize
hl order twap-cancel BTC 12345
hl account positions --watch--jsonOutput JSON--testnetUse testnet
hl account add|ls|set-default|removehl account positions|orders|balances|portfoliohl order ls|limit|market|tpsl|twap|twap-cancel|cancel|cancel-all|set-leverage|configurehl asset price|book|leveragehl markets ls|searchhl referral set|status
- DB:
~/.hl/hl.db - Order config:
~/.hl/order-config.json
Environment variable fallback (when DB account is not configured):
HYPERLIQUID_PRIVATE_KEYHYPERLIQUID_WALLET_ADDRESS
Account data stored in ~/.hl/hl.db is encrypted at rest for these fields:
user_addressapi_wallet_public_keyapi_wallet_private_key
The current implementation derives a 32-byte key as follows:
- Resolve the command path used to run
hl - Hash that path with SHA-256
- Use the resulting digest as the ChaCha20 key
Each stored value is encrypted independently with its own random nonce.
This means:
- the same installed command path can transparently decrypt the saved values
- changing the executable path can make existing saved account data undecryptable
- this is path-bound encryption, not password-based encryption
Example:
$ which hl
/home/haturatu/.local/bin/hlIf hl is installed at a user-local path like /home/haturatu/.local/bin/hl, then
the encryption key is effectively tied to that installed command path. In normal usage,
that often behaves like "the user who has this hl on their path can decrypt the DB".
So in practice it can look close to per-user decryption when each user has their own
home directory and their own local install path.
Important limitation:
- this mechanism does not prove OS user identity by itself
- if another OS user can both read
~/.hl/hl.dband execute the samehlbinary path, path-based derivation alone does not prevent that user from decrypting the data
So this mechanism is mainly useful as a coupling between the saved DB contents and the specific installed command path. It helps prevent casual reuse of the DB from a different binary location, but it is not a substitute for filesystem permissions or disk encryption.
Environment variable fallback still exists when DB account data is not configured:
HYPERLIQUID_PRIVATE_KEYHYPERLIQUID_WALLET_ADDRESS
These environment variables are not stored in the encrypted DB. They are read as plain process environment values at runtime.
Practical guidance:
- Use wallets or API keys that would not be catastrophic if leaked
- Restrict which OS user can run this tool
- If you need stronger protection, use disk encryption as the higher-level control
cd hl
PYTHONPATH=src python -m hl_cli.cli.argparse_main --helptests/ validates that every subcommand pattern produces parseable raw JSON output in --json mode.
cd hl
PYTHONPATH=src python -m unittest -v tests.test_json_patternsOrder side semantics:
buy/sellare for spot marketslong/shortare for perp marketscloseis for closing an open perp position
hyperliquid-python-sdk does not provide a high-level TWAP method, so this CLI signs and submits the official
exchange actions twapOrder / twapCancel. Successful submissions store the returned twapId
locally under ~/.hl/twap_orders.json so the CLI can show and cancel tracked TWAPs later.
TWAP is perp-only, so use long / short.
# 30-minute native TWAP
hl order twap long 1.0 BTC 30
# Derive total TWAP size from USD margin (stake * leverage)
hl order twap long 0 BTC 30 --stake 5
# Compatibility format: 5,10 is sent as total 50 minutes
hl order twap short 2.0 ETH 5,10 --randomize
# Cancel TWAP
hl order twap-cancel BTC 12345
# Or list tracked active TWAPs and pick one interactively
hl order twap-cancel--stake is used by the CLI to derive order size.
Mode-specific behavior:
-
buy/sellderive spot order size -
long/shortderive perp order size -
--leverage,--cross,--isolated, and--reduce-onlyare only supported withlong/short -
If you pass
--stake 50 --leverage 20, the CLI derives size from about$1000of notional (50 * 20). -
If you pass
--stake 50without--leverage, the CLI derives size from about$50of notional.
Important: omitting --leverage does not mean your account or position is forced
to 1x. It only means the CLI does not multiply --stake by leverage when calculating
the order size. If the exchange/account already has leverage set for that asset, the
resulting position can still show that existing leverage in hl account positions.
This means:
--stake 50means the CLI sizes the order from about$50of notional--stake 50 --leverage 20means about$1000of position notional
So:
--leveragechanges how--stakeis converted into order size- existing leverage on the exchange can still affect margin usage and the leverage
shown later in
hl account positions
# Spot buy: CLI sizes the order from about $50 of spot notional
hl order market buy @142 --stake 50
# Spot sell: CLI sizes the order from about $50 of spot notional
hl order market sell @142 --stake 50
# Perp long with leverage 20: CLI sizes the order from about $1,000 of BTC notional
hl order limit long BTC 65000 --stake 50 --leverage 20 --cross
# Perp long with leverage 20: CLI sizes the order from about $1,000 of BTC notional
hl order market long BTC --stake 50 --leverage 20 --isolated
# Example:
# BTC at 69,000
# - --stake 50 => about 0.000724 BTC of order size
# - --stake 50 --leverage 20 => about 0.01449 BTC
#
# ETH at 2,020
# - --stake 50 => about 0.02475 ETH of order size
# - --stake 50 --leverage 20 => about 0.2475 ETH
# Set leverage and margin mode at order time
hl order limit long BTC 65000 --stake 50 --leverage 20 --cross
hl order market long BTC --stake 50 --leverage 20 --isolated
# Set leverage directly
hl order set-leverage BTC 20 --cross
# If leverage is invalid, show warning and retry with coin maxLeverage from /info type=meta
hl order set-leverage BTC 60
# Close full position by coin
hl order market close ETH
hl order market close xyz:TSLA
# Close 50% of a position
hl order market close ETH --ratio 0.5
# Set TP/SL trigger orders for an open position
hl order tpsl ETH --tp 1900 --sl 1800
hl order tpsl ETH --sl 1800 --ratio 0.5- https://app.hyperliquid.xyz/
- https://github.com/chrisling-dev/hyperliquid-cli
- https://github.com/ehfuzzz/hyperliquid-CLI
This project is primarily a Python implementation of https://github.com/chrisling-dev/hyperliquid-cli. Some features, including the TWAP order implementation, are also based on ideas from https://github.com/ehfuzzz/hyperliquid-CLI.
This repository also includes changes such as expanded order subcommands, the
--stake option, and additional market subcommand functionality.
At the moment, I am not fully sure how this should be handled from a licensing and attribution perspective, so this repository is being published under my BSD 2-Clause License as a temporary choice. If you have a better idea for the appropriate license notice or attribution, please open an issue.