作为一名在加密货币量化交易领域摸爬滚打超过 3 年的开发者,我接入过超过 10 家交易所的 API,其中 Bybit 是我使用频率最高的平台之一。说实话,Bybit 的 API 文档质量在业内算是中上水平,但错误码体系分散在各个接口文档中,真正遇到 40029 或 10002 这类错误时,翻文档能让人翻到怀疑人生。

今天这篇文章,我把自己踩过的坑和排查经验全部整理出来,做成一张可以直接复制使用的速查表。建议收藏,用时 Ctrl+F。

为什么 Bybit API 错误码让人头疼

在我正式写 Bybit 之前,先算一笔账——这直接关系到你愿不愿意花时间把 API 对接做对。

主流大模型 Token 成本对比(output 价格):

以每月 100 万 output token 为例:

模型官方价($8/MTok基准折算)实际费用/月
GPT-4.1$8/MTok × 100万$800
Claude Sonnet 4.5$15/MTok × 100万$1500
Gemini 2.5 Flash$2.50/MTok × 100万$250
DeepSeek V3.2$0.42/MTok × 100万$42

而通过 HolySheep AI 中转,按 ¥1=$1 的无损汇率结算,DeepSeek V3.2 百万 Token 仅需 ¥42,换算回来相当于节省超过 85%。如果你每月在 AI API 上花费超过 $50,选对一个中转站,月底账单会让你明显感受到差距。

Bybit API 错误码速查表(按分类)

认证与权限类(10000-10999)

错误码错误信息含义解决方案
10001System error系统内部错误,通常是 Bybit 服务端问题等待 5-10 秒重试,检查 Bybit 状态页
10002Operation not allowed due to restriction操作受限,可能是账户被限制交易检查账户状态、KYC 认证状态、是否被冻结
10003Invalid API keyAPI Key 格式错误或已被禁用重新在 Bybit 后台生成 API Key
10004Invalid sign签名验证失败,这是最常见的认证错误检查 timestamp 参数、recv_window 是否超时、签名算法是否正确
10005Invalid timestamp请求时间戳无效或超过 recv_window确保本地时间与 UTC 时间误差在 30 秒内,recv_window 建议设 5000-10000ms
10006Invalid request header请求头格式不合法检查 Content-Type、X-BAPI-API-KEY 等请求头是否完整
10007Invalid currency交易对或币种不支持核实 symbol 参数格式,如 BTCUSDT 而非 BTC/USDT
10008Permission denied for current api keyAPI Key 权限不足在 Bybit 后台给 Key 开启对应权限(读取/交易/提币)
10009Too many visits触发 API 限速减少请求频率,WebSocket 实时订阅替代轮询
10010Api key not foundAPI Key 不存在确认 Key 是否已正确配置,检查空格或隐藏字符

订单操作类(11000-12999)

错误码错误信息含义解决方案
11001Category is invalid产品类别参数错误(spot/linear/inverse 等)确认 category 参数值是否与接口匹配
11003Symbol is invalid or not specified交易对不存在或未指定用 GET /v5/market/instruments-info 查询可用 symbol
11007Qty is invalid数量不符合规则(精度、最小值、最大值)先查 /v5/market/instruments-info 获取 qtyStep、minQty
11010Price is invalid价格不符合步进精度或超出限制检查 pricePrecision,限价单价格需为 tickSize 的整数倍
11011OrderId is invalid订单 ID 格式错误使用 orderLinkId(自定义 ID)替代系统 orderId
11020Position not found持仓不存在(平仓时报)确认持仓是否有仓位再做操作
11021Not enough balance余额不足检查账户可用余额(可用余额 ≠ 总余额)
11022Order price is beyond the limit订单价格超出交易所限价范围市价单改限价单,或检查 price 是否在 priceLimit 范围内
11023Order price is too close to market限价单价格过于接近市场价价格偏离市场至少 1 个 tickSize
11024Reduce only is not allowed该交易对不支持只减仓模式永续合约大部分支持,交割合约部分不支持
11025Time in force is not allowed该 timeInForce 对此订单类型不可用止盈止损单仅支持 GTC,其他请用 GTX

合约专用错误码(20000-29999)

错误码错误信息含义解决方案
20001No such position没有可平仓位确认仓位方向和数量,确认是否已通过对冲锁仓
20003Cannot afford estimated fee账户余额不够付手续费充值或减少下单数量
20006Order does not exist订单不存在或已完全成交/撤销用 /v5/order/realtime 查询最新状态
20007Only partial of order is filled只进行了部分成交这是预期行为,非错误。需等待完全成交或手动撤单
20015Order already cancelled订单已被撤销确认 orderId 状态后再操作
20016Cannot cancel order due to state订单当前状态无法撤销(如已完全成交)只有 NEW、PARTIAL_FILLED 状态可撤销
20031Cannot modify order due to state订单状态不允许修改订单必须是 NEW 状态,且非 GTC 全成交
20035Market order is not supported市价单不支持(仅支持限价单)改用 Limit 订单或市价开关参数
20039Close order does not support market平仓单不支持市价改用限价平仓,设置一个合理的平仓价格
20084Leverage cannot be 0合约下单前未设置杠杆先调用 /v5/position/set-leverage 设置杠杆

WebSocket 专用错误码(WebSocket-XXX)

错误码错误信息含义解决方案
10006auth 签名验证失败WebSocket 连接鉴权失败使用正确的 expires、sign 生成算法重新连接
30002Topic not found or not supported订阅的主题不存在检查 topic 拼写,格式应为 "tickers.BTCUSDT"
30005Too many subscriptions订阅数量超过上限(每连接最多 10 个 topic)减少订阅数量或新建连接分散订阅
30018Ping timeout心跳超时,连接被服务器断开实现 ping/pong 心跳,建议每 20 秒发一次
30020UnauthorizedWebSocket 连接未鉴权就请求私有数据先发送 auth 消息,等待 success 后再订阅私有频道

通用业务错误码(40000-49999)

错误码错误信息含义解决方案
40001Auth not passed认证未通过检查 API Key 是否有效、是否过期
40005Invalid parameter参数格式或值非法对照文档检查每个参数的类型和范围
40006Invalid parameter range参数超出允许范围如 limit 参数最大 200,超过需分页处理
40008Request timeout请求超时Bybit 默认 recv_window=5000ms,可适当增大
40013Category invalid产品类别与交易对不匹配spot 类别用现货 symbol,linear 用合约 symbol
40014Too many parameters参数数量过多部分接口限制单次请求参数数量,需拆分为多次调用
40015Invalid account type账户类型不匹配统一账户(UTA)和经典账户接口不同
40017Account balance is not enough账户余额不足确认是可用余额而非总资产
40018Account status is abnormal账户状态异常联系 Bybit 客服,检查是否被风控
40029Request frequency limit请求频率超限(触发限速)降低请求频率,使用 WebSocket 替代轮询
40102Currency not found币种不存在核实币种代码大小写,Bybit 需大写(如 BTC 而非 btc)
40103No trading allowed当前不允许交易可能是节假日、维护时间或账户受限
40104Market is closed市场已关闭永续/交割合约在结算时段可能暂停交易
40105Cannot operate during data batching数据批量处理期间无法操作永续合约每 4 小时有一次结算(~2:00、8:00 等),避开此时段

Python SDK 签名实现(含错误处理)

在我对接 Bybit 的过程中,超过 60% 的调试时间都花在签名算法上。以下是经过生产验证的签名代码,直接可用:

import hmac
import hashlib
import time
import requests
from typing import Dict, Any, Optional

BYBIT_BASE_URL = "https://api.bybit.com"
REC_WINDOW_MS = 10000  # 10秒足够,建议不要设太长

class BybitClient:
    def __init__(self, api_key: str, api_secret: str, testnet: bool = False):
        self.api_key = api_key
        self.api_secret = api_secret
        self.base_url = "https://api-testnet.bybit.com" if testnet else "https://api.bybit.com"
    
    def _generate_signature(self, timestamp: str, payload: str) -> str:
        """生成 HMAC SHA256 签名"""
        param_str = timestamp + self.api_key + REC_WINDOW_MS.__str__() + payload
        return hmac.new(
            self.api_secret.encode('utf-8'),
            param_str.encode('utf-8'),
            hashlib.sha256
        ).hexdigest()
    
    def _request(self, method: str, endpoint: str, 
                 params: Optional[Dict] = None, 
                 data: Optional[Dict] = None) -> Dict[str, Any]:
        """统一请求方法,含完整错误处理"""
        timestamp = str(int(time.time() * 1000))
        url = self.base_url + endpoint
        
        # 处理请求体
        payload = ""
        if data:
            payload = requests.post(url, json=data).request.body or ""
        elif params:
            payload = str(params)
        
        headers = {
            "X-BAPI-API-KEY": self.api_key,
            "X-BAPI-SIGN": self._generate_signature(timestamp, payload),
            "X-BAPI-TIMESTAMP": timestamp,
            "X-BAPI-RECV-WINDOW": str(REC_WINDOW_MS),
            "Content-Type": "application/json"
        }
        
        if method == "GET":
            response = requests.get(url, params=params, headers=headers, timeout=10)
        else:
            response = requests.post(url, json=data, headers=headers, timeout=10)
        
        result = response.json()
        
        # 错误码速查判断
        ret_code = result.get("retCode", 0)
        if ret_code != 0:
            error_map = {
                10003: "🔑 API Key 无效,请检查 Key 是否正确或已禁用",
                10004: "🔐 签名失败,检查 timestamp 和 recv_window 是否一致",
                10005: "⏰ 时间戳错误,检查本地时间与 UTC 偏差是否 < 30秒",
                10008: "🚫 API Key 权限不足,需在后台开启交易/读取权限",
                10009: "⚡ 请求过于频繁,降低频率或改用 WebSocket",
                11021: "💰 余额不足,确认可用余额而非总资产",
                11020: "📭 持仓不存在,平仓前先确认是否有仓位",
                20035: "📋 该交易对不支持市价单,改用 Limit 订单",
                40029: "🚦 请求频率超限,参考 Bybit 限速规则减少调用",
                40105: "⏸ 数据批量处理期间(结算时段),请稍后重试",
            }
            msg = error_map.get(ret_code, f"未知错误 ({ret_code}): {result.get('retMsg', '')}")
            raise Exception(f"[Bybit API Error {ret_code}] {msg}")
        
        return result.get("result", {})


使用示例:查询账户余额

client = BybitClient( api_key="YOUR_API_KEY", api_secret="YOUR_API_SECRET" ) try: balance = client._request( "GET", "/v5/account/wallet-balance", params={"accountType": "UNIFIED"} ) print(f"账户余额: {balance}") except Exception as e: print(f"请求失败: {e}")

常见报错排查

以下是我在生产环境中遇到的 3 个高频报错,附完整排查路径。

① 错误码 10004 — Invalid sign(签名错误)

这是 Bybit API 调用中最常见的错误,我的排查顺序是:

  1. 检查 timestamp 是否与服务器时间同步(允许 ±30 秒)
  2. 检查 recv_window 是否在请求头和签名计算中使用同一个值
  3. 检查签名参数字符串拼接顺序是否严格正确:timestamp + api_key + recv_window + body
  4. 确认 body 为空时传的是空字符串 "" 而非 None
  5. GET 请求的 params 需要转换为稳定顺序的字符串(字典遍历顺序可能不一致)
# 签名计算最容易出错的地方 — 确保参数顺序稳定
import json

def build_payload(params: dict, data: dict) -> str:
    """统一处理 GET/POST 的签名 payload"""
    if data:
        # POST: 使用稳定顺序的 JSON 序列化
        return json.dumps(data, separators=(',', ':'), sort_keys=True)
    elif params:
        # GET: 手动按字母序拼接,保证每次结果一致
        sorted_params = sorted(params.items())
        return '&'.join(f"{k}={v}" for k, v in sorted_params)
    else:
        return ""

错误示例:字典直接转字符串,每次遍历顺序不确定

bad_payload = str({"symbol": "BTCUSDT", "qty": 1})

正确示例:确保顺序和格式稳定

good_payload = build_payload({"symbol": "BTCUSDT", "qty": "1"}, None)

结果: "qty=1&symbol=BTCUSDT"

② 错误码 40029 / 10009 — 请求频率超限

Bybit 的限速规则比较复杂,分为 IP 级别和 Key 级别。新手最容易在这里踩坑——限价不是平均速率,而是峰值限制。

import time
import threading
from collections import deque

class BybitRateLimiter:
    """基于滑动窗口的限流器,避免触发 40029"""
    
    def __init__(self, max_calls: int, window_seconds: int):
        self.max_calls = max_calls
        self.window_seconds = window_seconds
        self.timestamps = deque()
        self.lock = threading.Lock()
    
    def acquire(self) -> float:
        """获取许可,如果超限则等待并返回等待时间"""
        with self.lock:
            now = time.time()
            # 清理窗口外的请求
            while self.timestamps and self.timestamps[0] < now - self.window_seconds:
                self.timestamps.popleft()
            
            if len(self.timestamps) < self.max_calls:
                self.timestamps.append(now)
                return 0.0
            
            # 计算需要等待多久
            wait_time = self.window_seconds - (now - self.timestamps[0])
            time.sleep(wait_time)
            self.timestamps.popleft()
            self.timestamps.append(time.time())
            return wait_time


使用方式

limiter = BybitRateLimiter(max_calls=60, window_seconds=60) # 每分钟最多60次 def call_bybit_api(): wait = limiter.acquire() if wait > 0: print(f"限流等待 {wait:.2f}s") # 执行实际的 API 调用 return client._request("GET", "/v5/market/tickers", params={"category": "linear", "symbol": "BTCUSDT"})

如果需要更高频率,推荐改用 WebSocket 获取实时数据

import websocket import json def on_message(ws, message): data = json.loads(message) # 处理实时行情,完全不占用 REST API 限额 print(data) ws = websocket.WebSocketApp( "wss://stream.bybit.com/v5/public/linear", on_message=on_message ) ws.send(json.dumps({"op": "subscribe", "args": ["tickers.BTCUSDT"]})) ws.run_forever(ping_interval=20) # 每20秒心跳,避免 30018 错误

③ 错误码 11007 — Qty is invalid(数量错误)

这个错误特别容易出现在新手身上,Bybit 对每个交易对的数量精度要求都不一样。

def get_trading_rules(symbol: str) -> dict:
    """查询交易对规则,避免下单数量错误"""
    response = client._request(
        "GET",
        "/v5/market/instruments-info",
        params={"category": "linear", "symbol": symbol}
    )
    info = response["list"][0]
    return {
        "symbol": symbol,
        "lotSizeFilter": info["lotSizeFilter"],      # qtyStep, minQty, maxQty
        "priceFilter": info["priceFilter"],          # tickSize, minPrice, maxPrice
        "unifiedMarginTrade": info.get("unifiedMarginTrade"),
    }

def validate_and_round_qty(symbol: str, qty: float) -> str:
    """规范化下单数量,自动取整到允许的步进"""
    rules = get_trading_rules(symbol)
    step = float(rules["lotSizeFilter"]["qtyStep"])
    min_qty = float(rules["lotSizeFilter"]["minQty"])
    max_qty = float(rules["lotSizeFilter"]["maxQty"])
    
    # 步进取整:向下取整到最近的 qtyStep 倍数
    rounded = round(qty // step * step, len(str(step).split('.')[-1]))
    
    if rounded < min_qty:
        raise ValueError(f"数量 {qty} 小于最小值 {min_qty},请提高下单量")
    if rounded > max_qty:
        raise ValueError(f"数量 {qty} 超出最大值 {max_qty},请降低下单量")
    
    return str(rounded)

使用示例

qty = 0.013456 # 原始下单数量 try: valid_qty = validate_and_round_qty("BTCUSDT", qty) print(f"规范化后的数量: {valid_qty}") # 输出: 0.0134(假设 qtyStep=0.0001) except ValueError as e: print(f"数量校验失败: {e}")

完整订单下单流程(带全链路错误处理)

import time
from enum import Enum

class OrderType(Enum):
    MARKET = "Market"
    LIMIT = "Limit"

def place_order_with_retry(
    symbol: str,
    side: str,  # "Buy" 或 "Sell"
    qty: float,
    order_type: OrderType = OrderType.LIMIT,
    price: Optional[float] = None,
    max_retries: int = 3
) -> dict:
    """
    带重试机制的订单下单函数,覆盖常见错误码自动处理
    """
    params = {
        "category": "linear",
        "symbol": symbol,
        "side": side,
        "orderType": order_type.value,
        "qty": validate_and_round_qty(symbol, qty),
        "timeInForce": "GTC",
    }
    
    if order_type == OrderType.LIMIT and price:
        # 限价单需要先验证价格精度
        rules = get_trading_rules(symbol)
        tick = float(rules["priceFilter"]["tickSize"])
        params["price"] = str(round(price // tick * tick, 
                             len(str(tick).split('.')[-1])))
    elif order_type == OrderType.MARKET:
        params["timeInForce"] = "IOC"  # 市价单用 IOC
    
    for attempt in range(max_retries):
        try:
            result = client._request("POST", "/v5/order/create", data=params)
            order_id = result.get("orderId", "unknown")
            print(f"✅ 订单成功创建: {order_id}")
            return result
        
        except Exception as e:
            error_msg = str(e)
            
            if "40029" in error_msg or "10009" in error_msg:
                # 限速错误:指数退避重试
                wait = 2 ** attempt
                print(f"⏳ 触发限速,等待 {wait}s 后重试 ({attempt + 1}/{max_retries})")
                time.sleep(wait)
                
            elif "11021" in error_msg:
                raise Exception("❌ 余额不足,请充值后再试")
                
            elif "11020" in error_msg:
                raise Exception("❌ 持仓不存在,无法执行平仓操作")
                
            elif "20035" in error_msg:
                # 自动切换为限价单
                print("📋 市价单不支持,自动切换为限价单")
                params["orderType"] = "Limit"
                params["price"] = str(price or get_market_price(symbol) * 0.99)
                
            elif "40105" in error_msg:
                # 结算时段,等待后再试
                print("⏸ 结算时段,等待 5s...")
                time.sleep(5)
                
            elif "40005" in error_msg or "11007" in error_msg:
                # 参数错误:重新验证数量
                params["qty"] = validate_and_round_qty(symbol, qty)
                print(f"🔧 数量修正为: {params['qty']},重试")
                
            else:
                # 其他未知错误
                raise
    
    raise Exception(f"❌ 下单失败,已重试 {max_retries} 次")

推荐下单入口

result = place_order_with_retry( symbol="BTCUSDT", side="Buy", qty=0.01, order_type=OrderType.LIMIT, price=95000.0 )

适合谁与不适合谁

在正式开始使用 Bybit API 之前,你需要评估自己的场景是否适合:

适合使用 Bybit API 的场景不适合或需谨慎的场景
合约量化交易(U 本位永续/交割)无法接受极端行情下强平风险的用户
做市商、对冲策略对 API 稳定性要求 100% 零容错的场景
需要高频率行情数据订阅需要法币出入金的完整银行通道
有 Python/Node/Java 编程能力的开发者完全不懂代码、只想手动跟单的用户
低保证金需求(最低 $10 起)资金量大且需要 OTC 大宗交易

我的个人建议是:如果你要做合约策略,Bybit 的合约深度和流动性在业内是第一梯队的,但 API 对接的坑不少。这篇文章覆盖的错误码基本能覆盖 90% 以上的生产环境问题,剩下的 10% 往往和账户状态相关,需要直接联系 Bybit 客服。

价格与回本测算

Bybit API 本身是免费接入的,但你的开发时间有成本。让我来算一笔实际的账:

成本项无中转站使用 HolySheep 中转节省
DeepSeek V3.2 百万 Token$0.42(按官方汇率 $1=¥7.3)¥0.42(按 ¥1=$1)约 85%
Claude Sonnet 4.5 百万 Token$15(¥109.5)¥15约 86%
每月 AI API 费用 $500¥3,650¥500¥3,150/月
首年节省($500/月基准)¥43,800¥6,000¥37,800/年

也就是说,如果你每月 AI API 消耗超过 ¥100(约 $13.7),使用 HolySheep 中转站一个月就能回本。注册还送免费额度,零风险试用。

为什么选 HolySheep

国内开发者接入海外大模型 API,绕不过去三座大山:

  1. 支付墙 — 信用卡被拒、虚拟卡封号、PayPal 不支持
  2. 汇率损耗 — 官方 ¥7.3=$1,实际美元汇率仅 ~$1=¥7.1,中间损耗超过 85%
  3. 访问延迟 — 直连 OpenAI/Anthropic 从国内经常超时,延迟 500ms+

HolySheep 解决了这三件事:

# HolySheep API 接入示例(兼容 OpenAI SDK)
import openai

client = openai.OpenAI(
    api_key="YOUR_HOLYSHEEP_API_KEY",  # 从 https://www.holysheep.ai/register 获取
    base_url="https://api.holysheep.ai/v1"  # ← 核心:中转地址
)

调用 DeepSeek V3.2 — 百万 Token 仅 ¥0.42

response = client.chat.completions.create( model="deepseek-chat", messages=[{"role": "user", "content": "帮我分析 BTCUSDT 近期走势"}], temperature=0.7 ) print(response.choices[0].message.content)

总结与购买建议

Bybit API 的错误码体系虽然看起来复杂,但只要掌握了本文的速查表和 3 个核心代码模板,你可以在 10 分钟内定位任何生产环境的 API 错误。记住优先级:

  1. 遇到签名错误(10004/10005)→ 先检查时间同步和 recv_window
  2. 遇到余额不足(11021)→ 确认是可用余额而非总资产
  3. 遇到限速(40029/10009)→ 立即上 WebSocket,REST 轮询不适合高频场景
  4. 遇到持仓错误(11020/20001)→ 先用 GET 接口查实仓位状态

对于 AI API 调用,我强烈建议通过 HolySheep 中转。官方 $1=¥7.3 的汇率对于月消耗 $100 以上的用户来说,每年白白多付 ¥7,500+。用这笔钱给自己换个显示器不香吗?

👉 免费注册 HolySheep AI,获取首月赠额度