lp-agent
npx skills add https://github.com/hummingbot/skills --skill lp-agent
Agent 安装分布
Skill 文档
lp-agent
This skill manages concentrated liquidity (CLMM) positions on decentralized exchanges like Meteora (Solana) and Raydium. It provides automated LP position management with rebalancing capabilities similar to the LP Manager controller.
Prerequisites
Before using this skill, ensure hummingbot-api and MCP are running:
bash <(curl -s https://raw.githubusercontent.com/hummingbot/skills/main/skills/lp-agent/scripts/check_prerequisites.sh)
If not installed, use the hummingbot-deploy skill first.
Quick Start
1. Find a Pool
Use the manage_gateway_clmm MCP tool:
# List popular pools on Meteora
manage_gateway_clmm(action="list_pools", connector="meteora")
# Search for specific pools
manage_gateway_clmm(action="list_pools", connector="meteora", search_term="SOL")
# Get detailed pool info
manage_gateway_clmm(action="get_pool_info", connector="meteora", network="solana-mainnet-beta", pool_address="<address>")
2. Create LP Position
# First, see the LP executor config schema
manage_executors(executor_type="lp_executor")
# Create position with quote only (buy base as price drops)
manage_executors(
action="create",
executor_config={
"type": "lp_executor",
"connector_name": "meteora/clmm",
"pool_address": "<pool_address>",
"trading_pair": "SOL-USDC",
"base_token": "SOL",
"quote_token": "USDC",
"base_amount": 0,
"quote_amount": 100,
"lower_price": 180,
"upper_price": 200,
"side": 1
}
)
Side values:
0= Both-sided (base + quote)1= Buy (quote-only, range below current price)2= Sell (base-only, range above current price)
IMPORTANT – Verify Position Creation:
After creating an executor, you MUST verify the position was actually created on-chain. Follow these steps:
Step 1: Get the executor ID from the creation response
The manage_executors(action="create") call returns the executor_id. Use this ID for verification.
Step 2: Poll executor state until it changes from OPENING
manage_executors(action="get", executor_id="<executor_id>")
Check custom_info.state:
OPENINGâ Transaction in progress, wait 5-10 seconds and check againIN_RANGEorOUT_OF_RANGEâ Position created successfully âFAILEDorRETRIES_EXCEEDEDâ Transaction failed â
Step 3: Confirm position exists on-chain Even if state shows success, verify the position actually exists:
manage_gateway_clmm(
action="get_positions",
connector="meteora",
network="solana-mainnet-beta",
pool_address="<pool_address>"
)
The response should contain a position with matching lower_price and upper_price.
If verification fails:
- Stop the failed executor:
manage_executors(action="stop", executor_id="<id>", keep_position=false) - Check the error in
custom_info.errorif available - Common issues: range too wide (reduce width), insufficient balance, network congestion
IMPORTANT – Range Width Limits (check BEFORE opening position):
Meteora DLMM pools have bin limits. Each bin represents a small price increment based on bin_step:
bin_step=1â Each bin is 0.01% apartbin_step=10â Each bin is 0.1% apartbin_step=100â Each bin is 1% apart
Maximum bins per position is ~69 due to Solana account size limits.
Calculate maximum range width:
max_width_pct = bin_step * 69 / 100
user_width_pct = (upper_price - lower_price) / lower_price * 100
Before creating any position, the agent MUST:
- Get pool info:
manage_gateway_clmm(action="get_pool_info", connector="meteora", network="solana-mainnet-beta", pool_address="<address>") - Extract
bin_stepfrom response - Calculate
max_width_pct = bin_step * 69 / 100 - If user’s range exceeds max, warn user and suggest narrower range
- Check wallet balance: user needs token amounts + at least 0.06 SOL for position rent
- Use
get_portfolio_overviewto check balances - Warn if insufficient SOL or token balance
- Use
Examples:
bin_step=1: max ~0.69% widthbin_step=10: max ~6.9% widthbin_step=100: max ~69% width
3. Set Default Preferences (Optional)
Save commonly-used settings to avoid repeating them. Ask user which values they want to default:
# View current preferences
manage_executors(action="get_preferences")
# Save connector/pair defaults when creating
manage_executors(
action="create",
executor_config={
"type": "lp_executor",
"connector_name": "meteora/clmm",
"trading_pair": "SOL-USDC",
...
},
save_as_default=true
)
What can be defaulted:
connector_name– e.g.,meteora/clmm(must include/clmmsuffix)trading_pair– e.g.,SOL-USDCextra_params.strategyType– Meteora only: 0=Spot, 1=Curve, 2=Bid-Ask
What should NOT be defaulted:
side– Determined by amounts at creation timebase_token/quote_token– Inferred from trading_pairlower_price/upper_price– Market-dependent
Defaults stored at ~/.hummingbot_mcp/executor_preferences.md.
4. Monitor Positions
# List all LP positions
manage_executors(action="search", executor_types=["lp_executor"])
# Get specific position details
manage_executors(action="get", executor_id="<executor_id>")
# Get positions summary
manage_executors(action="get_summary")
5. Manage Positions
# Collect fees (via Gateway CLMM)
manage_gateway_clmm(
action="collect_fees",
connector="meteora",
network="solana-mainnet-beta",
position_address="<position_nft_address>"
)
# Close position
manage_executors(action="stop", executor_id="<executor_id>", keep_position=false)
Position Types
Double-Sided (Both Tokens)
Provide liquidity with both base and quote tokens. Best when you expect price to stay within range.
Lower Current Upper
|---------------|---------------|
|<-- Quote zone | Base zone -->|
- Price goes UP: You sell base, accumulate quote
- Price goes DOWN: You buy base with quote
Single-Sided: Quote Only (side=1)
Position entire range BELOW current price. You’re buying base as price drops.
Lower Upper Current
|---------------|--------|
|<---- Buy zone ---->|
Single-Sided: Base Only (side=2)
Position entire range ABOVE current price. You’re selling base as price rises.
Current Lower Upper
|--------|---------------|
|<-- Sell zone -->|
Rebalancing Strategy (Agent-Driven)
When price moves out of your position range, the agent handles rebalancing automatically.
Step 1: Monitor Position State
manage_executors(action="get", executor_id="<id>")
Check custom_info.state:
IN_RANGEâ No action neededOUT_OF_RANGEâ Wait for rebalance delay, then rebalance
Rebalance delay: Wait for position to be out of range for a set time (default: 60 seconds). Ask user to confirm delay before starting.
Step 2: Determine Rebalance Direction
Compare custom_info.current_price with custom_info.lower_price and custom_info.upper_price:
If current_price < lower_price (price dropped below range):
- You’re now holding mostly BASE tokens
- Strategy: Create BASE-ONLY position ABOVE current price
- This lets you sell base as price recovers
If current_price > upper_price (price rose above range):
- You’re now holding mostly QUOTE tokens
- Strategy: Create QUOTE-ONLY position BELOW current price
- This lets you buy base if price drops
Step 3: Close Old Position
manage_executors(action="stop", executor_id="<old_id>", keep_position=false)
This returns tokens to wallet. Use the returned amounts for the new position.
Step 4: Create New Single-Sided Position
Use tokens received from close. For position width W% (ask user, check bin_step limits):
Price below range â base-only position ABOVE current price (side=2):
new_lower_price = current_price
new_upper_price = current_price * (1 + W/100)
base_amount = <amount received from close>
quote_amount = 0
side = 2
Price above range â quote-only position BELOW current price (side=1):
new_lower_price = current_price * (1 - W/100)
new_upper_price = current_price
base_amount = 0
quote_amount = <amount received from close>
side = 1
manage_executors(action="create", executor_config={
"type": "lp_executor",
"connector_name": "<same_connector>",
"pool_address": "<same_pool>",
"trading_pair": "<same_pair>",
"base_amount": <base_amount>,
"quote_amount": <quote_amount>,
"lower_price": <new_lower_price>,
"upper_price": <new_upper_price>,
"side": <side>
})
Step 5: Verify New Position
manage_executors(action="get", executor_id="<new_id>")
Confirm custom_info.state is IN_RANGE or OUT_OF_RANGE (not OPENING or FAILED).
MCP Tools Reference
manage_gateway_clmm
| Action | Parameters | Description |
|---|---|---|
list_pools |
connector, search_term, sort_key, limit | Browse available pools |
get_pool_info |
connector, network, pool_address | Get pool details |
get_positions |
connector, network, pool_address | Get positions in a pool |
open_position |
connector, network, pool_address, lower_price, upper_price, base_token_amount, quote_token_amount | Open position directly |
close_position |
connector, network, position_address | Close position |
collect_fees |
connector, network, position_address | Collect accumulated fees |
manage_executors
| Action | Parameters | Description |
|---|---|---|
| (none) | executor_type=”lp_executor” | Show config schema with your defaults |
create |
executor_config, save_as_default | Create LP executor (optionally save as default) |
search |
executor_types=[“lp_executor”] | List LP executors |
get |
executor_id | Get executor details |
stop |
executor_id, keep_position | Stop executor |
get_summary |
– | Get overall summary |
get_preferences |
– | View preferences file |
save_preferences |
preferences_content | Save edited preferences |
reset_preferences |
– | Reset to default template |
Scripts
| Script | Purpose |
|---|---|
check_prerequisites.sh |
Verify API, Gateway, wallet setup |
LP Executor Config Schema
{
"type": "lp_executor",
"connector_name": "meteora/clmm",
"pool_address": "2sfXxxxx...",
"trading_pair": "SOL-USDC",
"base_token": "SOL",
"quote_token": "USDC",
"base_amount": 0,
"quote_amount": 100,
"lower_price": 70,
"upper_price": 90,
"side": 1,
"extra_params": {
"strategyType": 0
}
}
Fields:
connector_name: CLMM connector – append/clmmto connector name (e.g.,meteora/clmm)pool_address: Pool contract addresstrading_pair: Format “BASE-QUOTE”base_amount/quote_amount: Token amounts (set one to 0 for single-sided)lower_price/upper_price: Position price boundsside: 0=both, 1=buy (quote-only), 2=sell (base-only)extra_params: Connector-specific (Meteora strategyType: 0=Spot, 1=Curve, 2=Bid-Ask)
Supported Connectors:
meteora/clmm– Tested and fully supported- Other Gateway CLMM connectors – Should work but not yet tested
To list available CLMM connectors:
manage_gateway_config(resource_type="connectors", action="list")
Append /clmm to any CLMM connector name when creating executors.
Example: Full LP Management Flow
# 1. Check prerequisites
bash <(curl -s https://raw.githubusercontent.com/hummingbot/skills/main/skills/lp-agent/scripts/check_prerequisites.sh)
# 2. Find a pool
manage_gateway_clmm(action="list_pools", connector="meteora", search_term="SOL", sort_key="volume")
# 3. Get pool details (note the bin_step for range calculation)
manage_gateway_clmm(action="get_pool_info", connector="meteora", network="solana-mainnet-beta", pool_address="2sfXxxxx")
# Example response shows: bin_step=10, current_price=190
# Max range width = 10 * 69 / 100 = 6.9%
# Use conservative 5% width: lower=185.5, upper=194.5
# 4. Create position
manage_executors(action="create", executor_config={
"type": "lp_executor",
"connector_name": "meteora/clmm",
"pool_address": "2sfXxxxx",
"trading_pair": "SOL-USDC",
"base_token": "SOL",
"quote_token": "USDC",
"base_amount": 0,
"quote_amount": 100,
"lower_price": 185.5,
"upper_price": 194.5,
"side": 1
})
# 5. VERIFY position was created (critical step!)
manage_executors(action="get", executor_id="<id>")
# Check custom_info.state:
# - "OPENING" â wait and check again
# - "IN_RANGE" or "OUT_OF_RANGE" â success!
# - "FAILED" â check error, possibly reduce range width
# 6. Monitor position
manage_executors(action="get", executor_id="<id>")
# 7. If out of range for 60+ seconds, rebalance (see Rebalancing Strategy)
# - Close: manage_executors(action="stop", executor_id="<id>", keep_position=false)
# - Reopen with tokens received as single-sided position
# 8. When done, close
manage_executors(action="stop", executor_id="<id>", keep_position=false)
Error Handling
| Error | Cause | Solution |
|---|---|---|
| “Prerequisites not met” | API or MCP not running | Run hummingbot-deploy skill |
| “Pool not found” | Invalid pool address | Use list_pools to find valid pools |
| “Insufficient balance” | Not enough tokens | Check wallet balance, reduce amounts |
| “Position not in range” | Price outside bounds | Wait or rebalance |
| “InvalidRealloc” | Position range spans too many bins | Reduce range width (see bin_step limits above) |
| State stuck at “OPENING” | Transaction failed silently | Stop executor and retry with narrower range |