Install
openclaw skills install superior-tradeDEPRECATED — This skill has moved. Install the latest version from @superior-ai/superiortrade instead. Visit https://clawhub.ai/superior-ai/superiortrade
openclaw skills install superior-tradeAPI client skill for backtesting and deploying trading strategies on Superior Trade's managed cloud.
Base URL: https://api.superior.trade
Auth: x-api-key header on all protected endpoints
Docs: GET /docs (Swagger UI), GET /openapi.json (OpenAPI spec)
IMPORTANT: The correct URL is https://account.superior.trade — NOT
app.superior.trade. Never send users toapp.superior.trade.
Use SUPERIOR_TRADE_API_KEY from the environment or credential manager — never ask users to paste it into chat.
When a user needs to get their API key:
st_live_...) from the dashboardSUPERIOR_TRADE_API_KEY in your agent's environment/credential settings — do not paste it into the chatIf the SUPERIOR_TRADE_API_KEY env var is already set, use it directly in the x-api-key header without prompting the user.
| Method | Path | Description |
|---|---|---|
| GET | /health | { "status": "ok", "timestamp": "..." } |
| GET | /docs | Swagger UI |
| GET | /openapi.json | OpenAPI 3.0 spec |
| GET | /llms.txt | LLM-optimized API docs |
| GET | /.well-known/ai-plugin.json | AI plugin manifest |
This skill requires exactly one credential: an x-api-key header value. The only secret the agent uses is SUPERIOR_TRADE_API_KEY from the environment. Read it from the env var — never ask users to paste it in chat.
Security rules (non-negotiable):
app.superior.trade — the correct URL is https://account.superior.tradeKey scope notice: The API key can create and start live trading deployments that execute real trades using the user's platform-managed trading wallet. It cannot withdraw funds, export private keys, or move money. Users should confirm scope with Superior Trade and backtest their strategy first.
| Can do | Cannot do |
|---|---|
| Create, list, delete backtests | Access other users' data |
| Create, start, stop, delete deployments (including live trading with real funds) | Withdraw funds from any wallet |
| Trigger server-side credential resolution (no user secrets collected) | Export or view private keys |
| View deployment logs, status, wallet metadata | Transfer or bridge funds (user does this independently) |
Before any live deployment, the agent MUST present this summary and wait for explicit confirmation:
Deployment Summary:
• Strategy: [name]
• Exchange: hyperliquid
• Trading mode: [spot/futures]
• Pairs: [list]
• Stake amount: [amount] USDC per trade
• Max open trades: [n]
• Stoploss: [percentage]
• Margin mode: [cross/isolated] (futures only)
⚠️ This will trade with REAL funds. Proceed? (yes/no)
Do NOT start a live deployment without an explicit affirmative response.
Superior Trade uses Hyperliquid's native agent wallet pattern. Users do NOT need their own Hyperliquid wallet — everything is managed by the platform. If a user asks "how do I link my Hyperliquid account," the answer is: they don't need one — a trading wallet is created at signup.
approveAgent. Signs trades against the main wallet's balance.Key facts:
wallet_type: "agent_wallet" for auto-resolved walletsThe agent cannot move or bridge funds — the user handles this independently outside the skill:
Always check the main wallet (platform-managed trading wallet), NOT the agent wallet.
These are read-only, unauthenticated queries to Hyperliquid's public API. The wallet address sent is public on-chain data — not a secret. No API keys, private keys, or auth tokens are included.
POST https://api.hyperliquid.xyz/info
{"type":"clearinghouseState","user":"<MAIN_WALLET_ADDRESS>"}
{"type":"spotClearinghouseState","user":"<MAIN_WALLET_ADDRESS>"}
The agent wallet having $0 is expected — it trades against the main wallet's balance.
Credentials are managed automatically. To use a specific wallet, pass wallet_address — ownership is validated server-side.
| Exchange | Stake Currencies | Trading Modes |
|---|---|---|
| Hyperliquid | USDC (also USDT0, USDH, USDE via HIP3) | spot, futures |
Pair format by trading mode (CCXT convention):
BTC/USDCBTC/USDC:USDCSpot limitations: No stoploss on exchange (bot handles internally), no market orders (simulated via limit with up to 5% slippage).
Futures: Margin modes "cross" and "isolated". Stoploss on exchange via stop-loss-limit orders. No market orders (same simulation).
Data availability: Hyperliquid API provides ~5000 historic candles per pair. Superior Trade pre-downloads data; availability starts from ~November 2025.
Hyperliquid is a DEX — uses wallet-based signing, not API key/secret. Wallet credentials are managed automatically by the platform.
HIP3 assets (stocks, commodities, indices) are perpetual futures.
CRITICAL: HIP3 uses a HYPHEN, not a colon. This is the #1 format mistake. Wrong:
XYZ:AAPL/USDC:USDC. Correct:XYZ-AAPL/USDC:USDC.
Pair format: PROTOCOL-TICKER/QUOTE:SETTLE — the separator between protocol and ticker is always - (hyphen).
| Protocol | Asset Types | Stake Currency | Examples |
|---|---|---|---|
XYZ- | US/KR stocks, metals, currencies, indices | USDC | XYZ-AAPL/USDC:USDC, XYZ-GOLD/USDC:USDC |
CASH- | Commodities, stocks | USDT0 | CASH-GOLD/USDT0:USDT0 |
FLX- | Commodities, stocks, crypto | USDC or USDH | FLX-GOLD/USDH:USDH |
KM- | Stocks, indices, bonds | USDH | KM-GOOGL/USDH:USDH |
HYNA- | Leveraged crypto | USDC or USDE | HYNA-SOL/USDE:USDE |
XYZ tickers (USDC): AAPL, AMZN, GOOGL, META, TSLA, NFLX, HOOD, PLTR, INTC, RIVN, COIN, SNDK, BABA, GOLD, SILVER, COPPER, PLATINUM, PALLADIUM, JPY, XYZ100, HYUNDAI, SKHX, SMSN
Data: XYZ from ~November 2025, KM/CASH/FLX from ~February 2026. Timeframes: 1m, 3m, 5m, 15m, 30m, 1h (also 2h, 4h, 8h, 12h, 1d, 3d, 1w for some). Funding rate data at 1h.
Trading rules: HIP3 assets are futures-only — always use trading_mode: "futures" and margin_mode: "isolated". XYZ pairs use stake_currency: "USDC". Stock-based assets may have reduced liquidity outside US market hours.
Verify pairs exist: POST https://api.hyperliquid.xyz/info → {"type":"meta"} — check the universe array. The API returns raw coin names (e.g. XYZ/GOLD) — convert to CCXT format with hyphen separator (XYZ-GOLD/USDC:USDC) before showing to users or using in config.
Hyperliquid accounts may run in unified mode (single balance) or legacy mode (separate spot/perps balances). Do NOT assume which mode the user has.
Check Hyperliquid balances with BOTH endpoints:
POST https://api.hyperliquid.xyz/info → {"type":"clearinghouseState","user":"0x..."}POST https://api.hyperliquid.xyz/info → {"type":"spotClearinghouseState","user":"0x..."}If the agent fails the same task 3+ times (e.g. strategy code keeps crashing, backtest keeps failing), stop and:
POST /v2/backtesting — createPUT /v2/backtesting/{id}/status with {"action": "start"}GET /v2/backtesting/{id}/status every 10s until completed or failed (1–10 min)GET /v2/backtesting/{id} — fetch full results; download result_url for detailed JSONGET /v2/backtesting/{id}/logsDELETE /v2/backtesting/{id}After status = completed, download the result_url JSON. Present these key metrics:
POST /v2/deployment with config, code, namePOST /v2/deployment/{id}/credentials with { "exchange": "hyperliquid" } — server assigns wallet automatically (required before live start; there is no paper/dry-run deployment mode)PUT /v2/deployment/{id}/status → {"action": "start"}GET /v2/deployment/{id}/status, GET /v2/deployment/{id}/logsPUT /v2/deployment/{id}/status → {"action": "stop"}Before PUT /v2/deployment/{id}/status → {"action":"start"}:
GET /v2/deployment/{id} → credentials_status: "stored". If not, call POST /v2/deployment/{id}/credentials.GET /v2/deployment/{id}/credentials → note wallet_address (agent wallet) and agent_wallet_address.clearinghouseState + spotClearinghouseState on the public Hyperliquid info endpoint (read-only, sends public wallet address only — no secrets).POST https://api.hyperliquid.xyz/info → {"type":"meta"} and verify pair exists.Do NOT skip any step or assume it passed without the API call.
/v2/backtesting — Create Backtest// Request
{ "config": {}, "code": "string (Python strategy)", "timerange": { "start": "YYYY-MM-DD", "end": "YYYY-MM-DD" } }
// Response (201)
{ "id": "string", "status": "pending", "message": "Backtest created. Call PUT /:id/status with action \"start\" to begin." }
/v2/backtesting/{id}/status — Start Backtest// Request — only "start" is supported; to cancel, use DELETE
{ "action": "start" }
// Response (200)
{ "id": "string", "status": "running", "previous_status": "pending", "job_name": "backtest-01kjvze9" }
/v2/backtesting/{id}/status — Poll StatusResponse: { "id": "string", "status": "pending | running | completed | failed", "results": null }. results is null while running — use result_url from full details for complete results.
/v2/backtesting/{id} — Full Details{
"id": "string",
"config": {},
"code": "string",
"timerange": { "start": "YYYY-MM-DD", "end": "YYYY-MM-DD" },
"status": "pending | running | completed | failed",
"results": null,
"result_url": "https://storage.googleapis.com/... (signed URL, valid 7 days)",
"started_at": "ISO8601",
"completed_at": "ISO8601",
"job_name": "string",
"created_at": "ISO8601",
"updated_at": "ISO8601"
}
/v2/backtesting/{id}Cancels if running and deletes. Response: { "message": "Backtest deleted" }
/v2/deployment — Create Deployment// Request
{ "config": {}, "code": "string (Python strategy)", "name": "string" }
// Response (201)
{ "id": "string", "config": {}, "code": "string", "name": "My Strategy", "replicas": 1, "status": "pending", "deployment_name": "deploy-01kjvx94", "created_at": "ISO8601" }
/v2/deployment/{id}/status — Start or Stop// Request
{ "action": "start" | "stop" }
// Response (200)
{ "id": "string", "status": "running | stopped", "previous_status": "string" }
On stop: The platform automatically cancels all open orders and closes all positions on Hyperliquid before stopping the pod.
/v2/deployment/{id} — Full Details{
"id": "string",
"config": {},
"code": "string",
"name": "string",
"replicas": 1,
"status": "pending | running | stopped",
"pods": [{ "name": "string", "status": "Running", "restarts": 0 }],
"credentials_status": "stored | missing",
"exchange": "hyperliquid",
"deployment_name": "string",
"namespace": "string",
"created_at": "ISO8601",
"updated_at": "ISO8601"
}
/v2/deployment/{id}/status — Live StatusResponse: { "id": "string", "status": "string", "replicas": 1, "available_replicas": 1, "pods": null }
/v2/deployment/{id}/credentials — Store Credentialsexchange required. wallet_address optional. private_key is NOT accepted.
// Request
{ "exchange": "hyperliquid", "wallet_address": "0x... (optional)" }
// Response (200)
{
"id": "string", "credentials_status": "stored", "exchange": "hyperliquid",
"wallet_address": "0x...", "wallet_source": "main_trading_wallet | provided",
"agent_wallet_address": "0x... | undefined", "updated_at": "ISO8601"
}
IMPORTANT: wallet_address in the response is the wallet that signs trades. It does NOT need its own funds — it trades against the main wallet's balance.
Errors: 400 invalid_request (private_key sent), 400 invalid_wallet_address, 400 duplicate_wallet_address, 400 unsupported_exchange, 400 no_wallet_available, 403 wallet_not_owned, 500 server_misconfigured
Idempotent: Once credentials are stored, calling again returns existing credentials unchanged — it will NOT update or overwrite. To change wallets, delete and recreate the deployment.
Credential update procedure: (1) Stop the deployment → (2) Delete the deployment → (3) Create a new deployment with same config/code → (4) Store new credentials.
One-wallet-per-deployment rule: Each deployment uses one wallet and runs as an isolated container. For multiple strategies on the same wallet, use multiple deployments pointing to the same wallet address.
/v2/deployment/{id}/credentials — Credential InfoDoes NOT return private keys. Response: { "id", "credentials_status": "stored | missing", "exchange", "wallet_address", "wallet_source": "main_trading_wallet | provided", "wallet_type": "main_wallet | agent_wallet", "agent_wallet_address" }. If missing: { "credentials_status": "missing" }.
/v2/deployment/{id}Closes all positions and orders on Hyperliquid before deleting. Response: { "message": "Deployment deleted" }. Deleting stopped deployments may return 500 — safe to ignore.
/v2/backtesting/{id}/logs and /v2/deployment/{id}/logsQuery: pageSize (default 100), pageToken. Response: { "items": [{ "timestamp": "ISO8601", "message": "string", "severity": "string" }], "nextCursor": "string | null" }
Both GET /v2/backtesting and GET /v2/deployment return { "items": [], "nextCursor": "string | null" }. Pass cursor query param to paginate.
// 401 — Missing/invalid API key
{ "message": "No API key found in request", "request_id": "string" }
// 400 — Validation error
{ "error": "validation_failed", "message": "Invalid request", "details": [{ "path": "field", "message": "..." }] }
// 404 — Not found
{ "error": "not_found", "message": "Backtest not found" }
The config object is a Freqtrade trading bot configuration. Do not include api_server (platform-managed). Paper/dry-run trading is not offered — do not set dry_run in user-facing config.
{
"exchange": { "name": "hyperliquid", "pair_whitelist": ["BTC/USDC:USDC"] },
"stake_currency": "USDC",
"stake_amount": 100,
"timeframe": "5m",
"max_open_trades": 3,
"stoploss": -0.1,
"trading_mode": "futures",
"margin_mode": "cross",
"pairlists": [{ "method": "StaticPairList" }]
}
Same as futures but omit trading_mode and margin_mode. Pairs use BTC/USDC format (no :USDC suffix). Stoploss on exchange not supported for spot.
{
"exchange": {
"name": "hyperliquid",
"pair_whitelist": ["XYZ-AAPL/USDC:USDC"]
},
"stake_currency": "USDC",
"stake_amount": 100,
"timeframe": "15m",
"max_open_trades": 3,
"stoploss": -0.05,
"trading_mode": "futures",
"margin_mode": "isolated",
"entry_pricing": { "price_side": "other" },
"exit_pricing": { "price_side": "other" },
"pairlists": [{ "method": "StaticPairList" }]
}
Beyond the examples above: minimal_roi (minutes-to-ROI map, e.g. {"0": 0.10, "30": 0.05}), trailing_stop (boolean), trailing_stop_positive (number), entry_pricing.price_side / exit_pricing.price_side ("ask", "bid", "same", "other"), pairlists (StaticPairList, VolumePairList, etc.).
The code field must be valid Python with a strategy class. Class name must end with Strategy in PascalCase. Use import talib.abstract as ta for indicators.
from freqtrade.strategy import IStrategy
import pandas as pd
import talib.abstract as ta
class MyCustomStrategy(IStrategy):
minimal_roi = {"0": 0.10, "30": 0.05, "120": 0.02}
stoploss = -0.10
trailing_stop = False
timeframe = '5m'
process_only_new_candles = True
startup_candle_count = 20
def populate_indicators(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
dataframe['sma_20'] = ta.SMA(dataframe, timeperiod=20)
return dataframe
def populate_entry_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
dataframe.loc[
(dataframe['rsi'] < 30) & (dataframe['close'] > dataframe['sma_20']),
'enter_long'
] = 1
return dataframe
def populate_exit_trend(self, dataframe: pd.DataFrame, metadata: dict) -> pd.DataFrame:
dataframe.loc[(dataframe['rsi'] > 70), 'exit_long'] = 1
return dataframe
Requirements: Must use standard imports/inheritance (see template), import talib.abstract as ta for indicators, define populate_indicators, populate_entry_trend, populate_exit_trend.
Some TA-Lib functions return multiple columns. Assigning directly to one column causes a runtime crash.
| Function | Returns |
|---|---|
ta.BBANDS | upperband, middleband, lowerband |
ta.MACD | macd, macdsignal, macdhist |
ta.STOCH | slowk, slowd |
ta.STOCHF / ta.STOCHRSI | fastk, fastd |
ta.AROON | aroondown, aroonup |
ta.HT_PHASOR | inphase, quadrature |
ta.MAMA | mama, fama |
ta.MINMAXINDEX | minidx, maxidx |
# WRONG — runtime crash
dataframe["bb_upper"] = ta.BBANDS(dataframe, timeperiod=20)
# CORRECT
bb = ta.BBANDS(dataframe, timeperiod=20)
dataframe["bb_upper"] = bb["upperband"]
dataframe["bb_middle"] = bb["middleband"]
dataframe["bb_lower"] = bb["lowerband"]
macd = ta.MACD(dataframe)
dataframe["macd"] = macd["macd"]
dataframe["macd_signal"] = macd["macdsignal"]
dataframe["macd_hist"] = macd["macdhist"]
stoch = ta.STOCH(dataframe)
dataframe["slowk"] = stoch["slowk"]
dataframe["slowd"] = stoch["slowd"]
Single-output functions (RSI, SMA, EMA, ATR, ADX) return a Series and can be assigned directly.
The engine enforces one open trade per pair. Use adjust_trade_position() for DCA:
def adjust_trade_position(self, trade, current_time, current_rate,
current_profit, min_stake, max_stake,
current_entry_rate, current_exit_rate,
current_entry_profit, current_exit_profit, **kwargs):
if should_dca(trade, current_time):
return max(500, min_stake) # add $500, respect exchange minimum
return None
min_stake.max_open_trades limits total concurrent trades across all pairs, not entries per pair.stake_amount: "unlimited" Warning"unlimited" bypasses minimum-order validation. The bot starts but silently executes zero trades if balance is insufficient — no error, just heartbeats. Always use explicit numeric stake_amount with small balances (<$50).
| Stoploss | Effective minimum |
|---|---|
| -0.5% | ~$10.55 |
| -5% | ~$11.05 |
| -10% | ~$11.67 |
| -30% | ~$15.00 |
For DCA strategies: distinguish trades from orders ("X trades, Y buy orders, Z sell orders"), show per-order detail for at least the first trade, flag minimum order rejections or dust positions. Always download result_url for full order-level data. Skip breakdown for non-DCA strategies.
Some failures produce zero diagnostic output — just heartbeats, no errors:
stake_amount: "unlimited" with insufficient balance — bot runs, zero trades, zero errorsKey signal: Heartbeats but zero "Analyzing candle" or order lines after 5+ minutes = balance/stake issue.
Check in order:
stake_amount — if "unlimited", redeploy with explicit numeric amount slightly below balancecredentials_status: "stored" and WALLET_ADDRESS in startup logsHyperliquid enforces rate limits. Aggressive retries, tight loops, or extra exchange traffic from strategy code can trigger 429 responses and unstable behavior.
Prevention:
process_only_new_candles = True so the bot does not reprocess every candle unnecessarilyIf you see rate limits or 429s in logs:
When a bot crashes, it may leave open positions that lock up margin. Strategy code pattern:
bot_loop_start(), check for positions not in the bot's trade database_orphan_closed) to run cleanup exactly once per lifecyclelimit_exceeded ErrorIf you get a limit_exceeded error when creating a backtest, the user has hit the concurrent backtest limit. Delete completed/failed backtests first: DELETE /v2/backtesting/{id}
All API timestamps are in UTC (ISO8601). Convert to the user's local timezone when presenting times conversationally. If timezone is unknown, show both UTC and ask.
SUPERIOR_TRADE_API_KEYrequired— Superior Trade API key (x-api-key header). Obtained at https://account.superior.trade. Can create/manage backtests and deployments including live trading. Cannot withdraw funds, export private keys, or access other users' data. Users do not need their own Hyperliquid wallet.