hyperliquid Β· diff

v1.7.0 to v1.8.0

1 added, 1 removed. Audit A to A.

---
name: hyperliquid
- version: 1.7.0
+ version: 1.8.0
description: |
Trade perp futures, spot, and RWA on Hyperliquid DEX with up to asset max leverage.
Use when placing perp or spot orders, setting TP/SL, or moving funds on Hyperliquid (e.g. long BTC 5x, sell ETH, deposit USDC, set stop).
delivery: script
metadata:
starchild:
emoji: "πŸ“ˆ"
skillKey: hyperliquid
requires:
env: [WALLET_SERVICE_URL]
user-invocable: true
disable-model-invocation: false
---
# Hyperliquid Trading
Trade perpetual futures and spot tokens on Hyperliquid, a fully on-chain decentralized exchange. Orders are signed using this agent's EVM wallet and submitted directly to the Hyperliquid L1.
## Prerequisites
Before trading, the wallet policy must be active. Load the **wallet-policy** skill and propose the standard wildcard policy (deny key export + allow `*`). This covers all Hyperliquid operations β€” USDC deposits, EIP-712 order signing, and withdrawals.
## Runtime Model: How to Call Hyperliquid (Read This First)
This skill is **script-delivery**. It registers **no** `hl_*` agent tools β€” calling
`hl_deposit`, `hl_order`, or any other `hl_*` name as a tool will always fail with
"not found in registry". That is by design, not a bug or a missing install.
There are exactly two working lanes:
### Lane 1 β€” Read-only queries (`exports.py`)
```python
from core.skill_tools import hyperliquid
account = hyperliquid.hl_account()
mids = hyperliquid.hl_market()
candles = hyperliquid.hl_candles(coin="BTC", interval="1h", hours_back=24)
```
**Any wallet, not just your own.** Every user-scoped function takes an optional
`address`. Omit it for the agent's own wallet; pass a 0x address to inspect a
third party. This is what makes "analyse this wallet's Hyperliquid PnL"
answerable β€” Hyperliquid is an off-chain order book, so a DeBank-style
chain scan cannot see any of it.
```python
hyperliquid.hl_portfolio(address="0x1f16...") # PnL time series
hyperliquid.hl_account(address="0x1f16...") # their open positions
```
32 functions, grouped:
| Group | Functions |
|-------|-----------|
| Account | `hl_account` `hl_balances` `hl_total_balance` `hl_user_role` `hl_user_fees` `hl_rate_limit` `hl_sub_accounts` `hl_referral` `hl_extra_agents` |
| PnL & history | `hl_portfolio` `hl_fills` `hl_fills_by_time` `hl_historical_orders` `hl_ledger` `hl_funding_payments` `hl_twap_fills` `hl_vault_equities` |
| Orders | `hl_open_orders` `hl_open_orders_full` `hl_order_status` |
| Market | `hl_market` `hl_orderbook` `hl_candles` `hl_funding` `hl_predicted_funding` `hl_meta` `hl_meta_ctxs` `hl_spot_meta` `hl_spot_meta_ctxs` `hl_perp_dexs` |
| Staking | `hl_staking` `hl_staking_delegations` `hl_staking_rewards` |
Read-only only β€” no writes on this lane.
### Answering "what is this wallet's PnL?"
`hl_portfolio` returns 8 windows β€” `day`, `week`, `month`, `allTime` and the
`perp*` equivalents β€” each with `accountValueHistory` and `pnlHistory` as
`[epoch_ms, value]` pairs. `pnlHistory` restarts at 0 at the start of each
window, so read `allTime` for lifetime PnL.
```python
pf = dict(hyperliquid.hl_portfolio(address=addr))
pnl = float(pf["allTime"]["pnlHistory"][-1][1])
```
For a cost-basis reconstruction, combine three sources: `hl_ledger` (capital
in/out β€” deposits, withdrawals, vault moves), `hl_fills_by_time` (realized
`closedPnl` per fill, 2000 max per call β€” page by passing the last fill's
`time` as the next `start`), and `hl_funding_payments` (funding paid/received).
Check `hl_user_role` first: role `"missing"` means the address never traded
here, which is not the same as "no positions".
### Lane 2 β€” Writes: orders, cancels, transfers, deposits (`client.py`)
Every write goes through `HyperliquidClient`, which owns the EIP-712 signing
pipeline. It is an **async** class β€” `await` every call.
```python
from skills.hyperliquid.client import HyperliquidClient
client = HyperliquidClient()
# Deposit USDC to the Hyperliquid bridge (minimum 5 USDC)
res = await client.deposit_usdc(amount=500)
# Place an order
res = await client.place_order(
coin="BTC", is_buy=True, size=0.001, price=95000, order_type="limit",
)
# Cancel / leverage / transfer / withdraw
await client.cancel_all("BTC")
await client.update_leverage(coin="BTC", leverage=5, is_cross=True)
await client.transfer_usd(amount=100, to_perp=True)
await client.withdraw_from_bridge(amount=50)
```
Prerequisite for Lane 2: the wallet policy must be active β€” load the
**wallet-policy** skill and propose the standard wildcard policy (deny key
export + allow `*`). That covers deposits, EIP-712 order signing, and withdrawals.
**Naming note:** the rest of this document refers to operations by their
historical `hl_*` names (e.g. "`hl_deposit`"). Those are *labels for the
operation*, not callable tools β€” always reach them via Lane 1 or Lane 2 above.
## Available Tools
### Account & Market Info
| Tool | What it does |
|------|--------------|
| `hl_total_balance` | Check how much you can trade with (use this for balance checks!) |
| `hl_account` | Open positions and unrealized PnL |
| `hl_balances` | Token holdings (USDC, HYPE, etc.) |
| `hl_portfolio` | **PnL and account value over time** β€” day/week/month/allTime |
| `hl_ledger` | Deposits, withdrawals, transfers β€” the capital in/out record |
| `hl_fills_by_time` | Fills within a date range, for cost-basis work |
| `hl_market` | Get current prices for crypto or stocks |
| `hl_meta_ctxs` | Market-wide scan: markPx, funding, OI, volume per asset |
| `hl_orderbook` | Check order book depth and liquidity |
| `hl_fills` | See recent trade fills and execution prices |
| `hl_candles` | Get price charts (1m, 5m, 1h, 4h, 1d) |
| `hl_funding` | Check funding rates for perps |
| `hl_open_orders` | See pending orders |
| `hl_open_orders_full` | Pending orders **with** stop-loss / take-profit detail |
All of the above accept `address="0x..."` to inspect any wallet, not just
the agent's own.
### Trading
| Tool | What it does |
|------|--------------|
| `hl_order` | Buy or sell perps (crypto/stocks) |
| `hl_spot_order` | Buy or sell spot tokens |
| `hl_tpsl_order` | Place stop loss or take profit orders |
| `hl_leverage` | Set leverage (1x to asset max) |
| `hl_cancel` | Cancel a specific order |
| `hl_cancel_all` | Cancel all open orders |
| `hl_modify` | Change order price or size |
### Funds
| Tool | What it does |
|------|--------------|
| `hl_deposit` | Add USDC from Arbitrum (min $5) |
| `hl_withdraw` | Send USDC to Arbitrum (1 USDC fee, ~5 min) |
| `hl_transfer_usd` | Move USDC between spot/perp (rarely needed) |
### Platform
| Tool | What it does |
|------|--------------|
| `hl_approve_builder` | Approve Starchild builder fee collection (auto-done on first order) |
| `hl_builder_status` | Check builder approval status and collected rewards |
---
## Quick Start
Just tell the agent what you want to trade - it handles everything automatically.
**Examples:**
```
User: "Buy $20 of Bitcoin with 5x leverage"
Agent: [checks balance β†’ sets leverage β†’ places order β†’ reports fill]
Result: "βœ“ Bought 0.0002 BTC at $95,432 with 5x leverage. Position opened."
User: "Long NVIDIA with $50, 10x"
Agent: [auto-detects NVIDIA = xyz:NVDA β†’ executes β†’ verifies]
Result: "βœ“ Bought 0.25 NVDA at $198.50 with 10x leverage. Filled at $198.62."
User: "Sell my ETH position"
Agent: [checks position size β†’ closes β†’ reports PnL]
Result: "βœ“ Sold 0.5 ETH at $3,421. Realized PnL: +$12.50"
```
**You don't need to:**
- Understand account modes or fund transfers
- Check balances manually (agent does it)
- Calculate position sizes (agent does it)
- Verify fills (agent does it)
**Just say what you want, the agent handles the rest.**
---
## Agent Behavior Guidelines
**πŸ€– As the agent, you should ALWAYS do these automatically (never ask the user):**
1. **Check available funds** - Use `hl_total_balance` before EVERY trade to see total available margin
2. **Detect asset type** - Recognize if user wants crypto (BTC, ETH, SOL) or stocks/RWA (NVIDIA→xyz:NVDA, TESLA→xyz:TSLA)
3. **Set leverage** - Always call `hl_leverage` before placing orders (unless user specifies not to)
4. **Verify fills** - After placing ANY order, immediately call `hl_fills` to check if it filled
5. **Report results** - Tell user the outcome: filled price, size, and any PnL
6. **Suggest risk management** - For leveraged positions, remind users about stop losses or offer to set them
**🎯 User just says:** "buy X" or "sell Y" or "long Z with $N"
**πŸ”§ You figure out:**
- Current balance (hl_total_balance)
- Asset resolution (crypto vs RWA)
- Leverage settings (hl_leverage)
- Order sizing (calculate from user's $ amount or size)
- Execution (hl_order)
- Verification (hl_fills)
- Final report to user
**πŸ“Š Balance checking hierarchy:**
- βœ… Use `hl_total_balance` - shows ACTUAL available margin regardless of account mode
- ❌ Don't use `hl_account` for balance - may show $0 even if funds available
- ❌ Don't use `hl_balances` for margin - only shows spot tokens
**πŸš€ Be proactive, not reactive:**
- Don't wait for user to ask "did it fill?" - check automatically
- Don't ask "should I check your balance?" - just do it
- Don't explain account modes - user doesn't care, just execute
---
## Tool Usage Examples
### Check Account State
```
hl_account() # Default crypto perps account
hl_account(dex="xyz") # Builder dex (RWA/stock perps) account
```
Returns `marginSummary` (accountValue, totalMarginUsed, withdrawable) and `assetPositions` array with each position's coin, szi (signed size), entryPx, unrealizedPnl, leverage.
**Important:** Builder perps (xyz:NVDA, xyz:TSLA, etc.) have separate clearinghouses. Always check the correct dex when trading RWA/stock perps.
### Check Spot Balances
```
hl_balances()
```
Returns balances array with coin, hold, total for USDC and all spot tokens.
### Check Market Prices
```
hl_market() # All mid prices
hl_market(coin="BTC") # BTC price + metadata (maxLeverage, szDecimals)
```
### Side Parameter Convention (read this first)
All order tools (`hl_order`, `hl_spot_order`, `hl_tpsl_order`, `hl_modify`)
use the same `side` parameter. **Use `"buy"` or `"sell"`** β€” these are the
documented values and should be your default.
For safety, the tools also accept these aliases so a model guess doesn't
reverse direction on a leveraged order:
- Buy family: `"buy"`, `"B"`, `"bid"`, `"long"`, `"L"`, `1`, `true`
- Sell family: `"sell"`, `"S"`, `"A"`, `"ask"`, `"short"`, `0`, `false`
**An unrecognized value will fail the call with a clear error** β€” the tool
never defaults to sell (or buy) when `side` is ambiguous. This is intentional:
silently reversing direction on a leveraged position is the worst failure mode.
Note: Hyperliquid's L1 wire protocol uses `"B"` and `"A"` internally, but the
tool interface here is `buy`/`sell`. Stick to `buy`/`sell` in your calls and
you will never be surprised.
### Place a Perp Limit Order
```
hl_order(coin="BTC", side="buy", size=0.01, price=95000)
```
Places a GTC limit buy for 0.01 BTC at $95,000.
### Place a Perp Market Order
```
hl_order(coin="ETH", side="sell", size=0.1)
```
Omitting `price` submits an IoC order at mid price +/- 3% slippage.
**Parameter format behavior:**
- Preferred: pass correct JSON types (`size` as number, `reduce_only` as boolean)
- Hyperliquid tools now include tolerant coercion for common LLM formatting mistakes:
- numeric strings like `"0.01"` β†’ `0.01`
- boolean strings like `"true"/"false"` β†’ `true/false`
- integer strings like `"5"`/`"5.0"` β†’ `5`
- Invalid/empty/non-finite values still fail with explicit validation errors
### Place a Post-Only Order
```
hl_order(coin="BTC", side="buy", size=0.01, price=94000, order_type="alo")
```
ALO (Add Liquidity Only) = post-only. Rejected if it would immediately fill.
**Practical guardrail for bots:** If your ALO price is too close to mid (often within ~0.1% on liquid pairs), Hyperliquid may reject it. For market-making/grid bots, compute current mid first and skip or shift levels that sit inside your no-cross buffer zone.
### Place a Stop Loss Order
```
hl_tpsl_order(coin="BTC", side="sell", size=0.01, trigger_px=90000, tpsl="sl")
```
Automatically sells 0.01 BTC if the price drops to $90,000. Executes as market order when triggered.
For a limit order when triggered (instead of market):
```
hl_tpsl_order(coin="BTC", side="sell", size=0.01, trigger_px=90000, tpsl="sl", is_market=false, limit_px=89900)
```
### Place a Take Profit Order
```
hl_tpsl_order(coin="ETH", side="sell", size=0.5, trigger_px=3500, tpsl="tp")
```
Automatically sells 0.5 ETH if the price rises to $3,500. Executes as market order when triggered.
### Close a Perp Position
```
hl_order(coin="BTC", side="sell", size=0.01, reduce_only=true)
```
Use `reduce_only=true` to ensure it only closes, never opens a new position.
### Place a Spot Order
```
hl_spot_order(coin="HYPE", side="buy", size=10, price=25.0)
```
Spot orders use the same interface β€” just specify the token name.
### Cancel an Order
```
hl_cancel(coin="BTC", order_id=12345678)
```
Get `order_id` from `hl_open_orders`.
### Cancel All Orders
```
hl_cancel_all() # Cancel everything
hl_cancel_all(coin="BTC") # Cancel only BTC orders
```
### Modify an Order
```
hl_modify(order_id=12345678, coin="BTC", side="buy", size=0.02, price=94500)
```
### Set Leverage
```
hl_leverage(coin="BTC", leverage=10) # 10x cross margin
hl_leverage(coin="ETH", leverage=5, cross=false) # 5x isolated margin
```
### Transfer USDC (rarely needed)
```
hl_transfer_usd(amount=1000, to_perp=true) # Spot β†’ Perp
hl_transfer_usd(amount=500, to_perp=false) # Perp β†’ Spot
```
Note: Usually not needed - funds are automatically shared. Only use if you get an error saying you need to transfer.
### Withdraw USDC to Arbitrum
```
hl_withdraw(amount=100) # Withdraw to own wallet
hl_withdraw(amount=50, destination="0xABC...") # Withdraw to specific address
```
Fee: 1 USDC deducted by Hyperliquid. Processing takes ~5 minutes.
### Deposit USDC from Arbitrum
```
hl_deposit(amount=500)
```
Sends USDC from the agent's Arbitrum wallet to the Hyperliquid bridge contract. Minimum deposit: 5 USDC. Requires USDC balance on Arbitrum.
### Get Candles
```
hl_candles(coin="BTC", interval="1h", lookback=48)
```
Intervals: `1m`, `5m`, `15m`, `1h`, `4h`, `1d`. Lookback in hours.
### Check Funding Rates
```
hl_funding() # All predicted fundings
hl_funding(coin="BTC") # BTC predicted + 24h history
```
### Get Recent Fills
```
hl_fills(limit=10)
```
---
## Coin vs RWA Resolution
When a user asks to trade a ticker, you need to determine whether it's a **native crypto perp** (use plain name) or an **RWA/stock perp** (use `xyz:TICKER` prefix).
### Decision Workflow
1. **Known crypto** β†’ use plain name: `"BTC"`, `"ETH"`, `"SOL"`, `"DOGE"`, `"HYPE"`, etc.
2. **Known stock/commodity/forex** β†’ use `xyz:` prefix: `"xyz:NVDA"`, `"xyz:TSLA"`, `"xyz:GOLD"`, etc.
3. **Unsure** β†’ resolve with tool calls:
- First try `hl_market(coin="X")` β€” if it returns a price, it's a crypto perp
- If not found, try `hl_market(dex="xyz")` to list all RWA markets and search the results
- Use whichever returns a match
### Common RWA Categories (all use `xyz:` prefix)
| Category | Examples |
|----------|----------|
| **US Stocks** | `xyz:NVDA`, `xyz:TSLA`, `xyz:AAPL`, `xyz:MSFT`, `xyz:AMZN`, `xyz:GOOG`, `xyz:META`, `xyz:TSM` |
| **Commodities β€” Metals** | `xyz:GOLD`, `xyz:SILVER`, `xyz:COPPER`, `xyz:PLATINUM`, `xyz:PALLADIUM`, `xyz:ALUMINIUM` |
| **Commodities β€” Energy** | `xyz:CL` (WTI), `xyz:BRENTOIL`, `xyz:NATGAS`, `xyz:TTF` (EU Gas) |
| **Commodities β€” Agriculture** | `xyz:CORN`, `xyz:WHEAT` |
| **Commodities β€” Other** | `xyz:URANIUM` |
| **Indices** | `xyz:SPY` |
| **Forex** | `xyz:EUR`, `xyz:GBP`, `xyz:JPY` |
> If a user says "buy NVDA" or "trade GOLD", use `xyz:NVDA` / `xyz:GOLD`. These are real-world assets, not crypto.
### ⚠️ HIP-3 Commodity Price Lookup
**All 13 commodity markets are HIP-3 builder-deployed perps.** Their symbols use the `xyz:` prefix (e.g. `xyz:GOLD`, `xyz:CL`), NOT standard formats like XAU, XAG, or WTI.
**Full commodity list:** GOLD, SILVER, COPPER, PLATINUM, PALLADIUM, ALUMINIUM, CL (WTI crude), BRENTOIL, NATGAS, TTF (EU gas), CORN, WHEAT, URANIUM.
**Key gotcha:** HIP-3 assets are **NOT included in `allMids`** (the standard price feed). This means:
- `hl_market(coin="xyz:GOLD")` may return **no price** or fail to find the asset
- `hl_market(dex="xyz")` lists all builder markets but may not include mid prices
**The reliable way to get commodity prices is `hl_candles`:**
```
# Get latest gold price (use 1h candles, lookback=24 for 24h data)
hl_candles(coin="xyz:GOLD", interval="1h", lookback=24)
# Get latest copper price
hl_candles(coin="xyz:COPPER", interval="1h", lookback=24)
# Get latest silver price
hl_candles(coin="xyz:SILVER", interval="1h", lookback=24)
```
The `close` field of the most recent candle = current price. The oldest candle's `open` vs latest `close` gives 24h change.
### Prefixed Name β€” Same Tools
All existing tools work with `xyz:TICKER` β€” just pass the prefixed coin name:
```
hl_market(coin="xyz:NVDA") # Check NVIDIA stock perp price
hl_market(dex="xyz") # List ALL available RWA/stock perps
hl_orderbook(coin="xyz:NVDA") # Check liquidity
hl_leverage(coin="xyz:NVDA", leverage=3) # Set leverage (auto-isolated)
hl_order(coin="xyz:NVDA", side="buy", size=0.5, price=188) # Limit buy 0.5 NVDA
hl_order(coin="xyz:TSM", side="buy", size=1) # Market buy 1 TSM
hl_cancel(coin="xyz:NVDA", order_id=12345678) # Cancel order
```
### Example: User Says "Buy NVIDIA"
1. Recognize NVIDIA = stock β†’ use `xyz:NVDA`
2. `hl_market(coin="xyz:NVDA")` β€” Check current price, leverage limits
3. `hl_leverage(coin="xyz:NVDA", leverage=3)` β€” Set leverage (builder perps use isolated margin)
4. `hl_order(coin="xyz:NVDA", side="buy", size=0.5, price=188)` β€” Place limit buy
5. `hl_fills()` β€” Check if filled
### Notes
- Builder perps (HIP-3) use isolated margin only β€” `hl_leverage` handles this automatically
- The `dex` prefix (e.g. `xyz`) identifies which builder deployed the perp
- All tools (candles, orderbook, funding, etc.) work the same way with prefixed names
---
## Common Workflows
### Query Commodity Prices
User: "What's the gold price?" or "Show me commodity prices" or "Oil price?"
**Name β†’ Symbol mapping:**
- Metals: GOLD→`xyz:GOLD`, SILVER→`xyz:SILVER`, COPPER→`xyz:COPPER`, PLATINUM→`xyz:PLATINUM`, PALLADIUM→`xyz:PALLADIUM`, ALUMINIUM→`xyz:ALUMINIUM`
- Energy: WTI/Crude Oil→`xyz:CL`, Brent→`xyz:BRENTOIL`, Natural Gas→`xyz:NATGAS`, EU Gas→`xyz:TTF`
- Agriculture: Corn→`xyz:CORN`, Wheat→`xyz:WHEAT`
- Other: Uranium→`xyz:URANIUM`
**Steps:**
1. Map commodity name β†’ HIP-3 symbol using the table above
2. `hl_candles(coin="xyz:GOLD", interval="1h", lookback=24)` β€” Get 24h of hourly candles
3. Current price = last candle's `close`
4. 24h change = `(last_close - first_open) / first_open * 100`
5. Repeat for each commodity as needed
**Do NOT use `hl_market()` for commodities** β€” HIP-3 assets are not in `allMids`. Always use `hl_candles`.
**Liquidity note:** CL (WTI) and BRENTOIL have the highest volume. ALUMINIUM, URANIUM, CORN, WHEAT, TTF may have zero or very low liquidity β€” warn the user before trading these.
### Trade Crypto Perps (BTC, ETH, SOL, etc.)
User: "Buy BTC" or "Long ETH with 5x"
Agent workflow:
1. `hl_total_balance()` β†’ Check available funds
2. `hl_leverage(coin="BTC", leverage=5)` β†’ Set leverage
3. `hl_order(...)` β†’ Place order
4. `hl_fills()` β†’ Verify fill and report result
### Trade Stocks/RWA (NVIDIA, TESLA, GOLD, etc.)
User: "Buy NVIDIA" or "Short TESLA"
Agent workflow:
1. Detect asset type β†’ Convert "NVIDIA" to "xyz:NVDA"
2. `hl_total_balance()` β†’ Check available funds
3. `hl_leverage(coin="xyz:NVDA", leverage=10)` β†’ Set leverage
4. `hl_order(coin="xyz:NVDA", ...)` β†’ Place order
5. `hl_fills()` β†’ Verify fill and report result
### Close Positions
User: "Close my BTC position"
Agent workflow:
1. `hl_account()` β†’ Get current position size
2. `hl_order(coin="BTC", side="sell", size=X, reduce_only=true)` β†’ Close position
3. `hl_fills()` β†’ Report PnL
### Grid / Market-Making Bot Loop (service mode)
For always-on bots running inside FastAPI/worker services:
1. Read open orders via `get_open_orders(address)`
2. Read fills via `get_user_fills(address)`
3. Use **fills as source of truth** for "order executed" events
4. On fill:
- buy fill β†’ place paired sell at next grid level
- sell fill β†’ place paired buy at previous grid level
5. Keep periodic reconciliation: local state vs exchange open orders
**Important:** Do not treat "order disappeared from open orders" as guaranteed fill. It can also mean cancel/reject/expired. Always confirm with `get_user_fills` (or `get_order_status` when needed).
### Spot Trading
User: "Buy 100 HYPE tokens"
Agent workflow:
1. `hl_total_balance()` β†’ Check available USDC
2. `hl_spot_order(coin="HYPE", side="buy", size=100)` β†’ Buy tokens
3. `hl_balances()` β†’ Verify purchase
### Deposit/Withdraw Funds
**Deposit:**
User: "Deposit $500 USDC to Hyperliquid"
Agent: `hl_deposit(amount=500)` β†’ Done
**Withdraw:**
User: "Withdraw $100 to my Arbitrum wallet"
Agent: `hl_withdraw(amount=100)` β†’ Done (5 min, 1 USDC fee)
---
## Order Types
| Type | Parameter | Behavior |
|------|-----------|----------|
| **Limit (GTC)** | `order_type="limit"` | Rests on book until filled or cancelled |
| **Market (IoC)** | omit `price` | Immediate-or-Cancel at mid +/- 3% slippage |
| **Post-Only (ALO)** | `order_type="alo"` | Rejected if it would cross the spread |
| **Fill-or-Kill** | `order_type="ioc"` + explicit price | Fill immediately at price or cancel |
| **Stop Loss** | `hl_tpsl_order` with `tpsl="sl"` | Triggers when price drops to limit losses |
| **Take Profit** | `hl_tpsl_order` with `tpsl="tp"` | Triggers when price rises to lock gains |
---
## Stop Loss & Take Profit Orders
Stop loss and take profit orders are **trigger orders** that automatically execute when the market reaches a specified price level. Use these to manage risk and lock in profits without monitoring positions 24/7.
### How They Work
1. **Order Placement**: Place a dormant trigger order with a trigger price
2. **Monitoring**: Order sits inactive, watching the market price
3. **Trigger**: When market price reaches `trigger_px`, order activates
4. **Execution**: Order executes immediately (as market or limit order)
### Stop Loss (SL)
**Use case**: Limit losses on a position by automatically exiting if price moves against you.
**Example**: You're long BTC at $95,000 and want to exit if it drops below $90,000.
```
hl_tpsl_order(coin="BTC", side="sell", size=0.1, trigger_px=90000, tpsl="sl")
```
- **trigger_px=90000**: Activates when BTC drops to $90k
- **side="sell"**: Closes your long position
- **tpsl="sl"**: Marks this as a stop loss order
- **Default**: Executes as market order when triggered (instant exit)
### Take Profit (TP)
**Use case**: Lock in gains by automatically exiting when price reaches your profit target.
**Example**: You're long ETH at $3,000 and want to take profit at $3,500.
```
hl_tpsl_order(coin="ETH", side="sell", size=1.0, trigger_px=3500, tpsl="tp")
```
- **trigger_px=3500**: Activates when ETH rises to $3,500
- **side="sell"**: Closes your long position
- **tpsl="tp"**: Marks this as a take profit order
- **Default**: Executes as market order when triggered (instant exit)
### Market vs Limit Execution
By default, TP/SL orders execute as **market orders** when triggered (instant fill, possible slippage).
For more control, use a **limit order** when triggered:
```
hl_tpsl_order(
coin="BTC",
side="sell",
size=0.1,
trigger_px=90000,
tpsl="sl",
is_market=false,
limit_px=89900
)
```
- **trigger_px=90000**: Activates at $90k
- **is_market=false**: Use limit order (not market)
- **limit_px=89900**: Limit price when triggered ($89,900)
**Trade-off**: Limit orders avoid slippage but may not fill in fast-moving markets.
### Short Positions
For short positions, reverse the `side` parameter:
**Stop loss on short** (exit if price rises):
```
hl_tpsl_order(coin="BTC", side="buy", size=0.1, trigger_px=98000, tpsl="sl")
```
**Take profit on short** (exit if price drops):
```
hl_tpsl_order(coin="BTC", side="buy", size=0.1, trigger_px=92000, tpsl="tp")
```
### Best Practices
1. **Always use `reduce_only=true`** (default) - ensures TP/SL only closes positions, never opens new ones
2. **Match size to position** - TP/SL size should equal or be less than your position size
3. **Set both TP and SL** - protect both upside (take profit) and downside (stop loss)
4. **Account for volatility** - don't set stops too tight or they'll trigger on normal price swings
5. **Check open orders** - use `hl_open_orders` to verify TP/SL orders are active
### Common Mistakes
| Mistake | Problem | Solution |
|---------|---------|----------|
| Wrong side | SL buys instead of sells | Long position β†’ `side="sell"` for SL/TP |
| Size too large | TP/SL opens new position | Set `size` ≀ position size, use `reduce_only=true` |
| Trigger = limit | Confusion about prices | `trigger_px` = when to activate, `limit_px` = execution price |
| No SL on leverage | Liquidation risk | Always set stop loss on leveraged positions |
---
## Perps vs Spot
| Aspect | Perps | Spot |
|--------|-------|------|
| Tool | `hl_order` | `hl_spot_order` |
| Leverage | Yes (up to asset max) | No |
| Funding | Paid/received every hour | None |
| Short selling | Yes (native) | Must own tokens to sell |
| Check positions | `hl_account` | `hl_balances` |
---
## Risk Management
- **Always check account state before trading** β€” know your margin usage and existing positions
- **Set leverage explicitly** before opening new positions (default may vary)
- **Use reduce_only** when closing to avoid accidentally opening the opposite direction
- **Monitor funding rates** β€” high positive funding means longs are expensive to hold
- **Start with small sizes** β€” Hyperliquid has minimum order sizes per asset (check szDecimals)
- **Post-only (ALO) orders** save on fees (maker vs taker rates)
- **Check fills after market orders** β€” IoC orders may partially fill or not fill at all
---
## Builder Code (Platform Fee)
Starchild automatically collects a **2 bps (0.02%) builder fee** on every perp and spot order placed through this skill. This fee supports platform operations and is separate from Hyperliquid's own trading fees.
**How it works:**
- The first time a user places an order, the skill auto-approves the Starchild builder address via the `ApproveBuilderFee` action (signed by the user's main wallet)
- All subsequent orders include a `builder` parameter: `{"b": "0x2c5320F40305fFC933385c6DCec5493fbA7b98b8", "f": 20}` (20 tenths-of-bps = 2 bps)
- The fee is collected in the quote/collateral asset (USDC) and accumulates in the builder's referral rewards
- Users can revoke approval at any time on app.hyperliquid.xyz
**Tools:**
- `hl_approve_builder` β€” Manually approve the Starchild builder (normally auto-done on first order)
- `hl_builder_status` β€” Check approval status and view unclaimed builder rewards
**If builder approval fails:** Orders still go through without the builder parameter. The error is logged but does not block trading.
---
## Common Errors
| Error | Fix |
|-------|-----|
| "Unknown perp asset" | Check coin name. Crypto: "BTC", "ETH". Stocks: "xyz:NVDA", "xyz:TSLA" |
| "Insufficient margin" | Use `hl_total_balance` to check funds. Reduce size or add more USDC |
| "Order must have minimum value of $10" | Increase size. Formula: `size Γ— price β‰₯ $10` |
| "Size too small" | BTC min is typically 0.001. Check asset's szDecimals |
| "Order would cross" | ALO order rejected. Use regular limit order instead |
| "User or wallet does not exist" | Deposit USDC first with `hl_deposit(amount=500)` |
| "Minimum deposit is 5 USDC" | Hyperliquid requires at least $5 per deposit |
| "Policy violation" | Load wallet-policy skill and propose wildcard policy |
| "Action disabled when unified account is active" | Transfers blocked in unified mode (default). Just place orders directly |
| "'side' must be one of: buy/sell ..." | You passed an unrecognized direction. Use `"buy"` or `"sell"`. See **Side Parameter Convention** above |