Coding

Bybit Exchange AI Trading Skill

Try it

Bybit AI Trading Skill — Trade on Bybit using natural language. Covers spot, derivatives, earn, and more. Works with Claude, ChatGPT, OpenClaw, and any AI assistant.

What it does

Bybit AI Trading Skill — Trade on Bybit using natural language. Covers spot, derivatives, earn, and more. Works with Claude, ChatGPT, OpenClaw, and any AI assistant.

The skill document

Bybit Trading Skill

Trade on Bybit using natural language. Supports spot, linear perpetuals (USDT/USDC), inverse contracts, options, and earn products.

Rule Priority

When rules in this skill conflict, follow this order: Safety > User Responsiveness > Convenience. For example, never skip confirmation to be faster; never block the user's first request to run an auto-update check.

Auto Update (MUST follow at session start)

This skill supports self-update with integrity verification. At the start of each new session, launch the update check as a background sub-agent so it never blocks the user's first request:

FOREGROUND (main agent — immediate):
1. Respond to the user's request using the current local version. Do NOT wait for the update check.

BACKGROUND (sub-agent — parallel):
1. LOCAL_VERSION = metadata.version  (from YAML frontmatter above)
2. SKILL_DIR = directory where this SKILL.md is located
3. MANIFEST = curl -sf -H "User-Agent: bybit-skill/1.5.8" https://api.bybit.com/skill/manifest
   (returns JSON: {"version":"x.y.z", "files":{"SKILL.md":"sha256:...","modules/market.md":"sha256:...",...}})
4. If fetch fails: return {status: "error", reason: "fetch_failed"}
5. Path validation: For each file in manifest.files, reject the entire update if ANY path:
   - Does not match `SKILL.md`, `modules/.md`, or `modules/.js` (where  is [a-z0-9-]+)
   - Contains `..`, starts with `/` or `~`, contains backslashes, or has an extension other than `.md` or `.js`
   If any path is invalid: return {status: "error", reason: "invalid_path", path: ""}
6. Version comparison (semver): split by ".", compare major → minor → patch numerically.
   If manifest.version > LOCAL_VERSION:
   a. For each file in manifest.files:
      - Download: curl -sf -H "User-Agent: bybit-skill/1.5.8" https://raw.githubusercontent.com/bybit-exchange/skills/main/
      - Save content to temp file, then compute SHA256: shasum -a 256  | awk '{print $1}'
      - Compare with manifest checksum (strip "sha256:" prefix)
      - If mismatch: ABORT entire update. return {status: "error", reason: "checksum_mismatch", file: ""}
      - If file extension is `.js` AND the local file already exists at SKILL_DIR/:
        → Show to user: "⚠️ Code module update:  (LOCAL_VERSION → manifest.version). Allow? [Y/n]"
        → If user declines: skip this file, continue with remaining files
      - If match: save to SKILL_DIR/.skill-update-tmp/
   b. ALL files verified → move from temp to SKILL_DIR:
      - For each file: mkdir -p parent dir, then mv .skill-update-tmp/ SKILL_DIR/
      - rm -rf SKILL_DIR/.skill-update-tmp/
   c. return {status: "updated", from: LOCAL_VERSION, to: manifest.version}
   If manifest.version == LOCAL_VERSION:
   d. return {status: "current"}

WHEN SUB-AGENT COMPLETES (main agent receives result):
- If status="updated": notify user "Skill updated from {from} to {to}. Using latest version." Re-read updated SKILL.md.
- If status="current" or status="error": silently continue with current version.
- Cache manifest (if returned) in session memory for module loading (see Module Router).

Rules:

  • Check at most ONCE per session. Do not re-check during the same conversation.
  • If any network request fails (timeout, 404, etc.), skip silently and proceed with current version. (See Graceful Degradation below for unified fallback rules.)
  • Never block the user's first request. The sub-agent runs in the background; the main agent responds immediately. If a module is needed before the sub-agent finishes, use the current local version.
  • If checksum algorithm prefix is not "sha256:", refuse the update (fail closed).

Quick Start

Step 1: Get an API Key

Pick one of the two paths below. The AI Subaccount path is strongly preferred — it's Bybit's purpose-built account type for AI trading, with built-in cap limits and a public-key-based key flow.

Bybit's official AI-trading account type (help article).

  • Create it (Bybit mobile app): Profile icon → Settings → Subaccount → Create → enter a name → select AI Subaccount → Confirm + security verification.
  • Get the API key (Public Key flow): after creation, Bybit asks for a Public Key. Run your AI assistant and ask it to generate one (Claude Code, Open Claw, Cursor, etc. all support this); paste the public key into Bybit → it returns the API key + secret bound to that key. Configure them per Step 2 below.
  • Built-in safety defaults: Cap Limit defaults to 5,000 USD (adjustable from main account → Subaccount → your AI Subaccount → More → Permissions). API key expires in 30 days; for permanent keys, IP whitelist, finer permission scoping, or higher rate limits, use the Bybit web platform instead of the app.
  • Why prefer this: blast radius is bounded by the cap limit, permissions are managed centrally from the main account (Request Transfer In/Out, Move from Trading/Funding, Max Leverage, etc.), and the subaccount can be killed in one click if anything goes wrong.

Path B — Manual API Key (Fallback)

Use this only if AI Subaccount isn't available in your region or you need a non-AI key flow.

  1. Log in to Bybit → API Management → Create New Key (do this from inside a Standard sub-account if possible — never from the main account).
  2. Permissions: enable Read + Trade only (NEVER enable Withdraw for AI use).
  3. Bind your IP address (makes the key permanent; otherwise expires in 3 months).
  4. Fund the (sub-)account with only the amount you're willing to risk in one bad day.

Step 2: Configure Credentials

Credential setup depends on where the AI runs. Auto-detect the environment and follow the matching path:

Path A — Local CLI (Claude Code, Cursor, or any tool with shell access):

Copy-paste this into ~/.zshrc or ~/.bashrc:

export BYBIT_API_KEY="your_api_key"
export BYBIT_API_SECRET="your_secret_key"
export BYBIT_ENV="testnet"  # or "mainnet"

Using an RSA API Key instead? (Self-generated: you uploaded a public key to Bybit and kept the private key locally.) Replace the BYBIT_API_SECRET line with:

export BYBIT_API_PRIVATE_KEY_PATH="/absolute/path/to/private.pem"

Everything else stays the same. Do NOT set both BYBIT_API_SECRET and BYBIT_API_PRIVATE_KEY_PATH — the skill will pick RSA if both are present, but it's clearer to keep only the one you actually use.

On first use, check if these environment variables exist. If they do, use them directly — do NOT ask the user to paste keys in the conversation. If they don't exist, guide the user to set them up:

  1. Tell the user: "For security, I recommend storing your API keys as environment variables instead of pasting them here."
  2. Provide the export commands above
  3. After the user has set them, verify with echo $BYBIT_API_KEY | head -c5 (only show first 5 chars to confirm)

Path B — Self-hosted OpenClaw (user runs OpenClaw on their own machine/server):

Keys stay on the user's machine — same security level as Path A. Configure via .env file:

Paste into ~/.openclaw/.env (recommended) or ./.env in your working directory:

BYBIT_API_KEY=your_api_key
BYBIT_API_SECRET=your_secret_key
BYBIT_ENV=testnet

Using an RSA API Key instead? Replace the BYBIT_API_SECRET line with:

BYBIT_API_PRIVATE_KEY_PATH=/absolute/path/to/private.pem

Everything else stays the same. Only set one of BYBIT_API_SECRET or BYBIT_API_PRIVATE_KEY_PATH, not both.

Alternative: openclaw.json env block — { "env": { "vars": { "BYBIT_API_KEY": "...", "BYBIT_API_SECRET": "...", "BYBIT_ENV": "testnet" } } } (swap BYBIT_API_SECRET for BYBIT_API_PRIVATE_KEY_PATH if using RSA).

On first use, check if these environment variables exist. If they do, use them directly. If they don't, guide the user to create ~/.openclaw/.env with the variables above.

Path C — Cloud platforms (hosted OpenClaw, Claude.ai, ChatGPT, Gemini, and other hosted AI services):

These platforms have no secret store. Keys must be pasted in the conversation (sent to AI provider's servers).

On first use:

  1. Accept keys pasted in the conversation
  2. Warn once: "Your keys will be sent through this platform's servers. For safety, use a sub-account with limited balance and Read+Trade permissions only (no Withdraw)."
  3. Do NOT ask again in the same session

Path D — OAuth (one-click authorization):

For AI assistants with shell access (Claude Code, Cursor, OpenClaw, etc.), the OAuth flow lets users authorize their Bybit account with a single click — no manual key creation needed. This uses the oauth/ module bundled with this skill. Cloud agents (OpenClaw, remote servers) automatically use headless mode — the user pastes the authorization code from the popup instead of relying on a localhost callback.

⚠️ MANDATORY first step for Path D: load modules/oauth.md and execute its Bootstrap section. The OAuth executable (modules/oauth.js) is NOT delivered by auto-update — it is lazy-fetched from raw.github with a SHA256-pinned check inside oauth.md. Without running Bootstrap first, every node ... modules/oauth.js ... command below will fail with Cannot find module on fresh installs. Do NOT run the credential check below until Bootstrap reports success.

Once Bootstrap succeeds, check if the OAuth credential file exists and has a valid (non-expired) token:

node -e "console.log(require('/modules/oauth.js').getCredentialPath())"

Read the file at that path. If it exists, created_at + expires_in > now, and ai-account is present → use ai-account.api_key and ai-account.api_secret as credentials. No further setup needed.

If the file is missing, expired, or incomplete → follow the full OAuth Authorization Flow section below.

Fallback (all platforms): If the user provides keys directly in the conversation, accept them but remind once about the more secure alternative for their platform.

Display rules (never show full credentials):

  • API Key: show first 5 + last 4 characters (e.g., AbCdE...x1y2)
  • Secret Key: show last 5 only (e.g., ***...vWxYz)
  • Code blocks (CRITICAL): NEVER include raw API Key or Secret Key values in generated code, scripts, or curl examples — even if the actual values are available in environment variables or session context. ALWAYS use $BYBIT_API_KEY / $BYBIT_API_SECRET (or ${API_KEY} / ${SECRET_KEY}) as variable references. This applies to ALL output formats including bash, python, and JSON. Violation of this rule is a security incident.

Step 3: Verify Connection (auto-run on first use)

After credentials are configured, automatically run these checks:

0. Determine sign type (no network call):

If $BYBIT_API_PRIVATE_KEY_PATH is set:
  - Expand leading ~/ to absolute path
  - If file exists, is readable, and its first line contains "PRIVATE KEY":
      → Select RSA (X-BAPI-SIGN-TYPE: 2) for all subsequent requests
  - Else:
      → Halt. Tell user: "Private key path set but file unreadable: "
        Do NOT silently fall back to HMAC.
Else if $BYBIT_API_SECRET is set:
  → Select HMAC (X-BAPI-SIGN-TYPE: 1 or omitted)
Else if OAuth credential file exists (Path D) and ai-account is present:
  - Check expiration: created_at + expires_in > now
  - If expired: attempt refresh (load oauth module, see "OAuth: Refresh token" section)
  - If refresh fails or no refresh_token: re-run OAuth flow
  - Use ai-account.api_key as $BYBIT_API_KEY and ai-account.api_secret as $BYBIT_API_SECRET
  → Select HMAC (same as branch above)
Else:
  → Tell user:
    "Please configure credentials first.
     - Quickest: run the OAuth flow (say 'authorize Bybit' or see Path D)
     - HMAC secret string: export BYBIT_API_SECRET=...
     - RSA private key file: export BYBIT_API_PRIVATE_KEY_PATH=/path/to/private.pem
     See Bybit API management for how to create keys."
    Stop; do not attempt authenticated calls.

If both $BYBIT_API_PRIVATE_KEY_PATH and $BYBIT_API_SECRET are set,
prefer RSA and emit once:
  "Both BYBIT_API_SECRET and BYBIT_API_PRIVATE_KEY_PATH are set. Using RSA.
   To force HMAC, unset BYBIT_API_PRIVATE_KEY_PATH."

If RSA is selected and the 'openssl' CLI is not available, halt with:
  "RSA signing requires the 'openssl' CLI. Install it or switch to HMAC."
# 1. Clock sync check (no auth needed)
GET /v5/market/time
# Compare response "timeSecond" with local time. If difference > 5 seconds:
#   → Tell user: "Your system clock is off by Xs. Please sync your clock (e.g., enable automatic date/time in system settings)."
#   → Do NOT proceed with authenticated requests until clock is synced (signatures will fail).

# 2. Verify signature and permissions
GET /v5/account/wallet-balance?accountType=UNIFIED
  • If clock difference > 5s: stop and ask user to fix clock sync first
  • If retCode=0: credentials are valid. Tell the user:
    ✓ Connected to Bybit [Mainnet/Testnet].
      Signing: 
      Account: UNIFIED
      Available balance:  USDT
    
    For RSA, derive `` from openssl rsa -in "$BYBIT_API_PRIVATE_KEY_PATH" -text -noout | head -1 (do NOT print any other line of that output — key material must not leak). Show only the file basename, not the full path.
  • If retCode=10003/10004: signature error. Append (current sign type: HMAC|RSA) to the error message so the user knows which branch ran.
  • If retCode=10005: insufficient permissions. Tell user to check API Key permissions.
  • If retCode=10010: IP not whitelisted. Tell user to add current IP in API Key settings.

Step 4: Choose Environment

Default: Mainnet. Always start in Mainnet mode unless the user explicitly requests Testnet.

ModeBase URLBehavior
Mainnet (default)https://api.bybit.comWrite operations require confirmation. Real funds.
Testnethttps://api-testnet.bybit.comAll operations execute freely. No real funds at risk.

Switching rules:

  • To switch to Testnet, the user must explicitly say "switch to testnet" / "use test account" / "use demo"
  • When switching to Testnet, display: "Switching to TESTNET. All operations will use test funds — no real money at risk."
  • To switch back to Mainnet, the user must explicitly request it. Display a confirmation prompt: "You are switching back to MAINNET. All subsequent write operations will use real funds. Type CONFIRM to proceed." Wait for CONFIRM before switching.
  • Always show the current environment in every response that involves API calls: [MAINNET] or [TESTNET]
  • If the user provides a Testnet API Key (starts with testing), automatically use Testnet URL

Step 5: Start Trading

Tell the user what they can do. Examples:

  • "What's the BTC price?"
  • "Buy 500 USDT worth of BTC"
  • "Open a 10x BTC long position"
  • "Check my balance"

Module Router

This skill uses modular on-demand loading. When the user's request matches a module below, fetch the corresponding file ONCE per session per module, then use it for all subsequent requests in that category.

How to load a module

1. Identify which module(s) the user's request needs from the table below
2. If the module has NOT been loaded in this session:
   a. Ensure manifest is available:
      - If cached from Auto Update: reuse it
      - Otherwise: MANIFEST = curl -sf -H "User-Agent: bybit-skill/1.5.8" https://api.bybit.com/skill/manifest
      - If fetch fails: use current local version of the module (SKILL_DIR/modules/.md)
        If no local version exists: inform user module unavailable, only GET operations permitted
      - Cache manifest in session
   b. Download: curl -sf -H "User-Agent: bybit-skill/1.5.8" https://raw.githubusercontent.com/bybit-exchange/skills/main/modules/.md
      - If download fails: use current local version of the module
        If no local version exists: inform user module unavailable, only GET operations permitted
   c. Verify integrity:
      - Compute SHA256 of downloaded content
      - Compare with manifest.files["modules/.md"] (strip "sha256:" prefix)
      - If mismatch: use current local version (do NOT use the downloaded content)
        If no local version exists: inform user module unavailable, only GET operations permitted
      - If match: use downloaded content, save to SKILL_DIR/modules/.md, cache in session
3. For subsequent requests in same category: use cached version (do NOT re-fetch)

Module Index

User Intent KeywordsModuleFileRequires
price, ticker, kline, chart, orderbook, depth, funding rate, open interest, market datamarketmodules/market.md
buy, sell, spot, swap, exchange, convert, limit order, market order, cancel order, spot marginspotmodules/spot.mdaccount
long, short, leverage, futures, perpetual, close position, take profit, stop loss, trailing stop, conditional order, hedge mode, option, put, call, strike, expiryderivativesmodules/derivatives.mdaccount
earn, stake, redeem, yield, savings, flexible, fixed deposit, fixed term, fund pool, dual assets, structured product, discount buy, smart leverage, double win, liquidity mining, auto reinvest, early redeem, hold-to-earn, airdrop yield, PWM, private wealth, investment plan, fund management, asset managerearnmodules/earn.mdaccount
balance, wallet, transfer, deposit, withdraw, fee, sub-account, API key, asset, fixed-rate borrow, borrow liability, repayment type, renew borrow, borrow market, borrow order, borrow contract, fixed borrow, margin borrow, referral, referral code, invitation code, invite link, affiliateaccountmodules/account.md
websocket, stream, loan, borrow, repay, RFQ, block trade, spread, lending, broker, rate limitadvancedmodules/advanced.md
P2P, peer to peer, advertisement, ad, OTC, fiat, fiat buy, fiat sell, convert fiatfiatmodules/fiat.md
copy trading, leader, follower, copy trade, leaderboard, recommend tradercopy-tradingmodules/copy-trading.mdderivatives, account
grid bot, DCA bot, martingale, combo bot, trading bot, create bot, close bottrading-botmodules/trading-bot.mdaccount, derivatives
alpha, on-chain, DEX, meme coin, swap token, on-chain asset, token trade, prediction, prediction market, bet, betting, YES/NO, sports market, World Cup, FIFA, event tradingalpha-trademodules/alpha-trade.mdaccount
TWAP, iceberg, chase order, chaseOrder, strategy order, split order, algorithmic, POV, percentage of volume, volume participationstrategymodules/strategy.mdaccount
xStocks, tokenized stock, commodity perpetual, XAUUSDT, XAGUSDT, CLUSDT, crude oil, TradFi, metals agreement, oil agreementtradfimodules/tradfi.mdaccount, spot, derivatives
card, bybit card, card transaction, card spending, card payment, card historycardmodules/card.mdaccount
Launchpool, launch pool, launchpad, new token mining, puzzle, token splash, Spot-X, spotx, campaign, activity list, activity reward, staking activity, project listactivitymodules/activity.md
authorize, OAuth, connect Bybit, login Bybit, 授权, 登录, one-click auth, enable Bybit trade execution, Authorize via OAuthoauthmodules/oauth.md

Module-specific notes:

  • Derivatives: Conditional orders require triggerDirection: 1=price rises above trigger, 2=price falls below trigger. Buy-the-dip → 2, breakout buy → 1.
  • Fiat/P2P: P2P responses use ret_code (underscore format, not retCode). P2P ad posting requires General Advertiser+ permission level.
  • Spot ↔ Convert fallback: Spot order endpoints (/v5/order/create) only support listed spot pairs (base + quote where quote ∈ USDT/USDC/USDE/BTC/ETH/EUR/BRL). If the user names a base-base pair (e.g., BTCDOGE, ETHSOL, SOLPEPE) or any pair you cannot confirm is a listed spot symbol, do NOT call spot order create. Route to Convert via the /v5/asset/exchange/* endpoints in the account module: (1) query-coin-list to confirm both coins are convertible, (2) quote-apply to lock a quote, (3) user CONFIRM, (4) convert-execute before the quote expires (typically ~5s). When suggesting this fallback, tell the user that the pair is not a listed spot symbol and propose Convert instead — surface fromCoin, toCoin, requestAmount, quote price, and expireTime in the confirmation.
  • Trading Bot: Bot API uses status_code/debug_msg response format (NOT retCode/retMsg). Always call validate-input (spot grid) or validate (futures grid) before creation — this returns acceptable parameter ranges and catches errors early. DCA: max 5 trading pairs per bot; if user requests more, ask them to choose up to 5.
  • Alpha Trade: Uses a quote-then-execute model — always call /v5/alpha/trade/quote first. Token codes use CEX_ (payment tokens like USDT) and DEX_ (on-chain tokens). All endpoints are POST (including queries). Settlement is on-chain (10-60s). KYC required.
  • Strategy: Strategy API uses UTA_* category format ONLY. Do NOT use linear/spot — map: linearUTA_USDT, spotUTA_SPOT, inverseUTA_INVERSE. Chase orders: chaseDistance and chasePercentE4 are mutually exclusive — use ONE only. NEVER use category=linear or category=spot in Strategy API calls — this will cause errors. Always translate: derivatives/perpetual/futures → UTA_USDT, spot → UTA_SPOT. POV (Percentage of Volume): adapts child order size to live market activity; only supports Perp (NOT spot).
  • Copy Trading: The investmentE8 parameter uses 8-decimal precision (multiply USDT amount by 10^8). For example, 100 USDT = 10000000000 (100 × 10^8). Always apply this conversion when the user specifies an investment amount in USDT.
  • TradFi: Discover instruments via instruments-info with symbolType=xstocks (spot, e.g., TSLAXUSDT) or symbolType=commodity (linear, e.g., XAUUSDT/CLUSDT). Trading reuses standard V5 order endpoints — no TradFi-specific trade API. Metals (XAU/XAG) and Crude Oil (CL) require a one-time master-account agreement via POST /v5/user/agreement (categoryV2=2 metals, categoryV2=3 oil); xStocks do not. Subaccounts inherit eligibility once the master signs. xStocks instruments include extra fields such as xstockMultiplier.
  • OAuth: When triggered, load modules/oauth.md and follow the OAuth Authorization Flow documented there. After authorization completes, credentials are automatically available for all other modules (spot, derivatives, etc.) via the Runtime Decision logic in Step 3.

Routing Notes

  • Keywords are hints, not strict rules — always use semantic understanding of the user's full request to determine the correct module(s). When ambiguous (e.g., "borrow" could mean spot margin or advanced lending), prefer the module matching the broader conversation context, or ask the user to clarify.
  • Common Chinese synonyms: 查价/看价 → market, 买/卖/现货 → spot, 开多/开空/合约/杠杆 → derivatives, 理财/质押/双币/持币生息/私人财富 → earn, 余额/转账/充值/提币 → account, 跟单 → copy-trading, 网格/DCA/AI推荐/一键创建/策略推荐 → trading-bot, 链上/meme/DEX/代币/预测/押注/预测市场/世界杯/FIFA → alpha-trade, 代币化股票/特斯拉/苹果/英伟达/黄金/白银/原油/商品永续 → tradfi, 拆单/算法单/POV → strategy, 银行卡/消费记录/刷卡 → card, 打新/新币挖矿/launchpool/拼图/代币空投/活动列表/质押活动 → activity, 授权/登录/连接Bybit/OAuth → oauth

Loading Rules

  1. Match intent → load module: A single user request may need multiple modules (e.g., "check BTC price then buy" → market + spot)
  2. Auto-load dependencies: When loading a module, also load all modules listed in its Requires column (e.g., loading derivatives → also load account if not already loaded)
  3. Load once per session: Do NOT re-fetch a module already loaded in this conversation
  4. Fail gracefully: Follow the Graceful Degradation rules below.
  5. Multiple modules OK: Load as many modules as needed for the user's request
  6. Retry once: If GitHub Raw fails, retry the same URL once. If still failing, follow Graceful Degradation.

Graceful Degradation (unified fallback rules)

All failure scenarios (auto-update, module loading, manifest fetch) follow this single priority chain:

  1. Local version available → use it silently. Do not inform the user unless they ask about version.
  2. No local version, network failed → inform user that the module is unavailable. Only read-only (GET) operations are permitted using the Authentication and Common Parameters sections. Do NOT execute POST (write) operations — tell the user to retry later.
  3. Checksum mismatch on download → treat as network failure (use local version if available; otherwise step 2).

Authentication

Base URLs

RegionURL
Global (default)https://api.bybit.com
Global (backup)https://api.bytick.com

Request Signature

Headers (required for every authenticated request):

HeaderValue
X-BAPI-API-KEYAPI Key
X-BAPI-TIMESTAMPUnix millisecond timestamp
X-BAPI-SIGNHMAC-SHA256 signature
X-BAPI-RECV-WINDOW5000
X-BAPI-SIGN-TYPE2 for RSA-SHA256; omit or set 1 for HMAC-SHA256
Content-Typeapplication/json (POST)
User-Agentbybit-skill/1.5.8
X-Refererbybit-skill

Signing Algorithm

Bybit V5 supports two signing methods. Auto-select at runtime by env var (see Step 3).

Sign TypeWhen to useX-BAPI-SIGN-TYPEOutput encoding
HMAC-SHA256Bybit-generated key (you received a Secret string)1 (or omit)hex
RSA-SHA256Self-generated key (you uploaded the public key to Bybit)2base64

Shared param_str (identical for both methods):

  • GET: {timestamp}{apiKey}{recvWindow}{queryString}
  • POST: {timestamp}{apiKey}{recvWindow}{jsonBody}

The jsonBody used for signing MUST be compact JSON (no extra spaces/newlines), byte-identical to the request body. Example: {"key":"value"} not { "key": "value" }.

HMAC-SHA256 signature:

SIGN=$(echo -n "$PARAM_STR" | openssl dgst -sha256 -hmac "$SECRET_KEY" | cut -d' ' -f2)

RSA-SHA256 signature (PKCS#1 v1.5 padding):

SIGN=$(printf '%s' "$PARAM_STR" \
  | openssl dgst -sha256 -sign "$BYBIT_API_PRIVATE_KEY_PATH" -binary \
  | base64 | tr -d '\n')

Use printf '%s' (not echo -n) for RSA to guarantee no trailing newline across shells. tr -d '\n' strips any line wrapping that base64 may add on BSD/LibreSSL.

Complete curl Examples

Security: When generating code for the user, ALWAYS use environment variable references ($BYBIT_API_KEY, $BYBIT_API_SECRET, $BYBIT_API_PRIVATE_KEY_PATH) — NEVER substitute actual values or file paths into code blocks, even if they are available in the session. This is security-critical.

The only differences between HMAC and RSA requests are (a) the X-BAPI-SIGN-TYPE: 2 header for RSA and (b) how SIGN is computed (base64 vs hex). param_str, timestamp, recvWindow, body, and other headers are identical.

GET — HMAC (query positions):

API_KEY="$BYBIT_API_KEY"
SECRET_KEY="$BYBIT_API_SECRET"
BASE_URL="https://api.bybit.com"
RECV_WINDOW=5000
TIMESTAMP=$(date +%s000)
QUERY="category=linear&symbol=BTCUSDT"
PARAM_STR="${TIMESTAMP}${API_KEY}${RECV_WINDOW}${QUERY}"
SIGN=$(echo -n "$PARAM_STR" | openssl dgst -sha256 -hmac "$SECRET_KEY" | cut -d' ' -f2)

curl -s "${BASE_URL}/v5/position/list?${QUERY}" \
  -H "X-BAPI-API-KEY: ${API_KEY}" \
  -H "X-BAPI-TIMESTAMP: ${TIMESTAMP}" \
  -H "X-BAPI-SIGN: ${SIGN}" \
  -H "X-BAPI-RECV-WINDOW: ${RECV_WINDOW}" \
  -H "User-Agent: bybit-skill/1.5.8" \
  -H "X-Referer: bybit-skill"

POST — HMAC (place spot market order):

API_KEY="$BYBIT_API_KEY"
SECRET_KEY="$BYBIT_API_SECRET"
BASE_URL="https://api.bybit.com"
RECV_WINDOW=5000
TIMESTAMP=$(date +%s000)
BODY='{"category":"spot","symbol":"BTCUSDT","side":"Buy","orderType":"Market","qty":"500","marketUnit":"quoteCoin"}'
PARAM_STR="${TIMESTAMP}${API_KEY}${RECV_WINDOW}${BODY}"
SIGN=$(echo -n "$PARAM_STR" | openssl dgst -sha256 -hmac "$SECRET_KEY" | cut -d' ' -f2)

curl -s -X POST "${BASE_URL}/v5/order/create" \
  -H "Content-Type: application/json" \
  -H "X-BAPI-API-KEY: ${API_KEY}" \
  -H "X-BAPI-TIMESTAMP: ${TIMESTAMP}" \
  -H "X-BAPI-SIGN: ${SIGN}" \
  -H "X-BAPI-RECV-WINDOW: ${RECV_WINDOW}" \
  -H "User-Agent: bybit-skill/1.5.8" \
  -H "X-Referer: bybit-skill" \
  -d "${BODY}"

To use RSA instead: apply these two changes to either HMAC example above.

  1. Replace the SIGN= line with:

    PRIV_KEY="$BYBIT_API_PRIVATE_KEY_PATH"
    SIGN=$(printf '%s' "$PARAM_STR" \
      | openssl dgst -sha256 -sign "$PRIV_KEY" -binary \
      | base64 | tr -d '\n')
    
  2. Add one header to the curl call:

    -H "X-BAPI-SIGN-TYPE: 2" \
    

Everything else — param_str, timestamp, recvWindow, body, other headers — is identical to the HMAC version.

Runtime Decision

At runtime, inspect env vars in this order for every authenticated call:

  1. If $BYBIT_API_PRIVATE_KEY_PATH is set and the file is readable → RSA branch. (If $BYBIT_API_SECRET is also set, RSA still wins — emit a one-time "Using RSA" notice at Step 3.)
  2. Else if $BYBIT_API_SECRET is set → HMAC branch.
  3. Else if the OAuth credential file exists (see Path D) and ai-account is present with a non-expired token → use ai-account.api_key / ai-account.api_secret as HMAC credentials. If the token is expired but refresh_token is still valid, refresh it first (load oauth module, see "OAuth: Refresh token" section).
  4. Else → prompt the user to configure credentials (see Step 1). Mention OAuth (Path D) as the quickest option for platforms with shell access.

If $BYBIT_API_PRIVATE_KEY_PATH is set but the file is missing or unreadable, halt with an explicit error. Do NOT silently fall back to HMAC.

Never mix the two: never include both an HMAC-derived X-BAPI-SIGN and a raw private-key reference on the same request.

Response Format

{"retCode": 0, "retMsg": "OK", "result": {}, "time": 1672211918471}

retCode=0 means success; non-zero indicates an error.


Common Parameter Reference

Core Parameters

ParameterDescriptionValues
categoryProduct categoryspot linear inverse option
symbolTrading pairUppercase, e.g. BTCUSDT
sideDirectionBuy Sell
orderTypeOrder typeMarket Limit
qtyQuantityString
pricePriceString (required for Limit orders)
timeInForceTime in forceGTC IOC FOK PostOnly RPI
positionIdxPosition index0 (one-way) 1 (hedge buy/long) 2 (hedge sell/short)
accountTypeAccount typeUNIFIED FUND

TradFi-Specific Parameters

ParameterDescriptionValues
symbolTypeTradFi filter for /v5/market/instruments-infoxstocks (spot category) commodity (linear category)

symbolType is a TradFi-specific filter parameter. Standard spot/linear queries do not require this parameter.

Order Parameters

ParameterDescriptionValues
triggerPriceTrigger price for conditional ordersString
triggerDirectionTrigger direction (required for conditional)1 (rise to) 2 (fall to)
triggerByTrigger price typeLastPrice IndexPrice MarkPrice
reduceOnlyReduce only flagtrue / false
marketUnitSpot market buy unitbaseCoin quoteCoin
orderLinkIdUser-defined order IDString (must be unique)
orderFilterOrder filterOrder tpslOrder StopOrder
takeProfitTP price (pass "0" to cancel)String
stopLossSL price (pass "0" to cancel)String
tpslModeTP/SL modeFull (entire position) Partial

Enums Reference

EnumValues
orderStatus (open)New PartiallyFilled Untriggered
orderStatus (closed)Rejected PartiallyFilledCanceled Filled Cancelled Triggered Deactivated
stopOrderTypeTakeProfit StopLoss TrailingStop Stop PartialTakeProfit PartialStopLoss tpslOrder OcoOrder
execTypeTrade AdlTrade Funding BustTrade Delivery Settle BlockTrade MovePosition
interval (kline)1 3 5 15 30 60 120 240 360 720 D W M
intervalTime5min 15min 30min 1h 4h 1d
positionMode0 (one-way) 3 (hedge)
setMarginModeISOLATED_MARGIN REGULAR_MARGIN PORTFOLIO_MARGIN

Error Handling

Common Error Codes

System & Auth (10000-10099)

retCodeNameMeaningResolution
0OKSuccess
10001REQUEST_PARAM_ERRORInvalid parameterCheck missing/invalid params; hedge mode may require positionIdx
10002REQUEST_EXPIREDTimestamp expiredTimestamp outside recvWindow (±5000ms); sync system clock
10003INVALID_API_KEYInvalid API keyKey invalid or wrong environment (testnet vs mainnet). If using RSA: confirm the public key uploaded to Bybit and the private key at $BYBIT_API_PRIVATE_KEY_PATH are the matching pair. Error messages should include (current sign type: HMAC|RSA).
10004INVALID_SIGNATURESignature errorVerify param_str order {timestamp}{apiKey}{recvWindow}{params}, compact JSON body. If using RSA: verify X-BAPI-SIGN-TYPE: 2, output is base64 (not hex), padding is PKCS#1 v1.5 (not PSS). Error messages should include (current sign type: HMAC|RSA).
10005PERMISSION_DENIEDPermission deniedAPI Key lacks required permission → Manage API Keys
10006TOO_MANY_REQUESTSRate limitedPause 1s then retry; check X-Bapi-Limit-Status header
10010UnmatchedIpIP not whitelistedAdd current IP in API Key settings
10014DUPLICATE_REQUESTDuplicate requestDuplicate request detected; avoid resending identical requests
10016INTERNAL_SERVER_ERRORServer errorRetry later
10017ReqPathNotFoundPath not foundCheck request path and HTTP method
10027TRADING_BANNEDTrading bannedTrading not allowed for this account
10029SYMBOL_NOT_ALLOWEDInvalid symbolSymbol not in the allowed list

Trade Domain (110000-169999)

retCodeNameMeaningResolution
110001ORDER_NOT_EXISTOrder does not existCheck orderId/orderLinkId; order may have been filled or expired
110003ORDER_PRICE_OUT_OF_RANGEPrice out of rangeCall instruments-info for priceFilter: minPrice/maxPrice/tickSize
110004INSUFFICIENT_WALLET_BALANCEWallet balance insufficientReduce qty or Deposit
110007INSUFFICIENT_AVAILABLE_BALANCEAvailable balance insufficientBalance may be locked by open orders; cancel orders to free up
110008ORDER_ALREADY_FINISHEDOrder completed/cancelledOrder already filled or cancelled; no action needed
110009TOO_MANY_STOP_ORDERSToo many stop ordersReduce number of conditional/stop orders
110020TOO_MANY_ACTIVE_ORDERSActive order limit exceededCancel some active orders first
110021POSITION_EXCEEDS_OI_LIMITPosition exceeds OI limitReduce position size
110040ORDER_WOULD_TRIGGER_LIQUIDATIONWould trigger liquidationReduce qty or add margin
110057INVALID_TPSL_PARAMSInvalid TP/SL paramsCheck TP/SL settings; ensure tpslMode and positionIdx are included
110072DUPLICATE_ORDER_LINK_IDDuplicate orderLinkIdorderLinkId must be unique per order
110094ORDER_NOTIONAL_TOO_LOWNotional below minimumIncrease order size; check instruments-info for minNotionalValue

Spot Trade (170000-179999)

retCodeNameMeaningResolution
170005SPOT_TOO_MANY_NEW_ORDERSToo many spot ordersSpot rate limit exceeded; slow down
170121INVALID_SYMBOLInvalid symbolCheck symbol name (uppercase, e.g. BTCUSDT)
170124ORDER_AMOUNT_TOO_LARGEAmount too largeReduce order amount; check instruments-info lotSizeFilter
170131SPOT_INSUFFICIENT_BALANCEBalance insufficientReduce qty or deposit funds
170132ORDER_PRICE_TOO_HIGHPrice too highReduce limit price
170133ORDER_PRICE_TOO_LOWPrice too lowIncrease limit price
170136ORDER_QTY_TOO_LOWQty below minimumIncrease qty; check instruments-info lotSizeFilter
170140ORDER_VALUE_TOO_LOWValue below minimumIncrease order value; check minOrderAmt
170810TOO_MANY_TOTAL_ACTIVE_ORDERSTotal active orders exceededCancel some orders first

Note: Always read retMsg for the actual cause — the same business error may return different retCodes depending on API validation order.

Rate Limit Strategy

Limits:

  • Place/amend/cancel orders: 10-20/s (varies by trading pair)
  • Query endpoints: 50/s
  • Check remaining quota from X-Bapi-Limit-Status response header

Mandatory backoff rules (MUST follow):

  1. Minimum interval between API calls: GET (read) requests: 100ms; POST (write) requests: 300ms
  2. On retCode=10006 (rate limited): wait a random interval between 500ms-1500ms, then retry. Maximum 3 retries per request.
  3. On 3 consecutive rate limits: stop all API calls for 10 seconds, then resume at half speed (400ms between calls)
  4. Global coordination: Maintain a single last-call timestamp across ALL modules. When switching between modules (e.g., market → account → derivatives), the inter-call interval still applies — do not reset the timer when switching modules.
  5. NEVER loop API calls without sleep (e.g., polling price in a tight loop)
  6. For batch operations (e.g., "cancel all my orders"): use batch endpoints (/v5/order/cancel-all or /v5/order/cancel-batch) instead of looping individual cancel calls
  7. Before intensive operations: check X-Bapi-Limit-Status header; if remaining < 20%, slow down to 500ms intervals

Security Rules

API Key Security Warning

IMPORTANT: Understand where your API Key lives.

AI Tool TypeKey LocationRisk LevelRecommendation
Local CLI (Claude Code, Cursor)Key stays on your machine (env vars)LowSafe for trading
Self-hosted OpenClawKey stays on your machine (.env file)LowSafe for trading
Cloud AI (hosted OpenClaw, Claude.ai, ChatGPT, Gemini)Key is sent to AI provider's serversMediumUse sub-account + Read+Trade only, no Withdraw
Unknown AI toolsKey destination unclearHighUse Testnet only, or avoid providing Key

Mandatory Key hygiene:

  • NEVER enable Withdraw permission for AI-used API Keys
  • Always use a dedicated sub-account with limited balance for AI trading
  • Bind IP address when possible to prevent key misuse
  • Rotate keys periodically (every 30-90 days)

Confirmation Mechanism

Operation TypeExampleRequires Confirmation?
Public query (no auth)Tickers, orderbook, kline, funding rateNo
Private query (read-only)Balance, positions, orders, trade historyNo
**M

Related skills

Build, install, update, and use a WhiteBIT trading guidance and training skill through ClawHub (clawhub.ai) for OpenClaw. Use when asked to manage WhiteBIT t...

26 installs1 stars

Bitquery (bitquery.io). Use this skill for ANY Bitquery request — searching and reading data. Whenever a task involves Bitquery, use this skill instead of ca...

1 installs

Use this skill when the user wants to put a Binance trade thesis on trial, review whether a long or short idea deserves risk, get an APPROVE / REVIEW / REJEC...

28 installs

Use this skill when the user wants to audit a Binance trading prompt, decide whether an AI trader should get Binance account permissions, return Pass/Warn/Bl...

19 installs

Trade gTrade perps via CAI — defi_markets, defi_preflight, defi_trade, defi_order_status, hosted /act enrollment. Requires platform or full API scope. Powere...

10 installs

Use this skill when the user wants to install Miraix Agent Arena in OpenClaw, bind an Arena pair code, turn a natural-language trading idea into an Arena-rea...

18 installs