简繁
ESC
↑↓ 选择↵ 打开站内全文搜索
注册币安 ↗

交易所 API 报错怎么解决?时间戳、签名、频率限制与下单精度

大多数 API 报错只有四类原因:本机时间不准、签名或密钥不对、请求太频繁、下单数量和价格不符合交易对规则。本文整理币安 -1021、-1022、-2015、-1013、-1003 与欧易 50102、50113、51008 等常见错误码的含义和排查顺序,并用 CCXT 实测时间校准、异常捕获和精度处理。

识途编辑部更新 阅读 约 30 分钟来源 4 个官方资料
目录本文共 6 节
  1. 01币安和欧易常见 API 错误码速查表
  2. 02币安 -1021、欧易 50102:时间戳错误怎么解决?
  3. 03币安 -2015、-1022,欧易 50111、50113:密钥和签名错误怎么排查?
  4. 04币安 -1003、429、418 和欧易 50011:频率限制怎么处理?
  5. 05下单报 LOT_SIZE、NOTIONAL、51121:数量和价格精度怎么处理?
  6. 06遇到 API 报错,按什么顺序排查最快?

交易所 API 的报错看起来五花八门,但绝大多数只有四类原因:本机时间不准、签名或 API Key 不对、请求太频繁、下单数量和价格不符合交易对规则。排查时先看错误码属于哪一类,再按「时间 → 密钥与权限 → 频率 → 订单参数」的顺序逐项检查,通常几分钟就能定位。下面的错误码含义全部核对过币安和欧易的官方 API 文档(截至 2026 年 10 月),代码在 CCXT 4.5.89 上实际运行过。

如果你还没有创建 API Key,先看 币安 API Key 创建与权限设置 和 欧易 API Key 创建教程;还没装 CCXT,先看 CCXT Python 入门。

币安和欧易常见 API 错误码速查表

先对照这张表判断你的报错属于哪一类。「CCXT 异常」一列是 CCXT 4.5.89 内置映射表里的实际类型,用 CCXT 时你捕获到的就是它。

交易所 错误码 官方提示(节选) 含义 CCXT 异常
币安 -1021 Timestamp for this request is outside of the recvWindow 时间戳超出接收窗口 InvalidNonce
币安 -1022 Signature for this request is not valid 签名无效 AuthenticationError
币安 -2014 API-key format invalid Key 格式不对,多半复制错了 AuthenticationError
币安 -2015 Invalid API-key, IP, or permissions for action Key、IP 白名单或权限不对 AuthenticationError
币安 -1111 Parameter has too much precision 小数位数超过精度 BadRequest
币安 -1013 Filter failure: LOT_SIZE / NOTIONAL / PRICE_FILTER 数量、金额或价格不符合过滤器 BadRequest
币安 -2010 Account has insufficient balance for requested action 余额不足 InsufficientFunds
币安 -1003 / HTTP 429 Too much request weight used 请求权重超限 RateLimitExceeded
币安 HTTP 418 无 限频后仍继续请求,IP 被自动封禁 DDoSProtection
欧易 50102 Timestamp request expired 时间戳过期 InvalidNonce
欧易 50113 Invalid signature 签名无效 AuthenticationError
欧易 50111 Invalid OK-ACCESS-KEY Key 无效 AuthenticationError
欧易 50110 Your IP is not included in your API key’s IP whitelist IP 不在白名单 PermissionDenied
欧易 50101 APIKey does not match current environment 模拟盘 Key 连了实盘,或反过来 AuthenticationError
欧易 51008 Order failed. Insufficient balance in account 余额或保证金不足 InsufficientFunds
欧易 51020 / 51121 低于最小下单量 / 数量不是 lot size 的整数倍 下单数量不合规 InvalidOrder
欧易 50011 Rate limit reached 请求频率超限 RateLimitExceeded

两个容易踩的细节:

  • 币安的精度错误在 CCXT 里是 BadRequest,不是 InvalidOrder。 如果你只写了 except ccxt.InvalidOrder,-1013 和 -1111 会漏网,建议把两者一起捕获。
  • 欧易下单失败时外层 code 往往不是错误码本身。 下单接口返回的外层 code 可能是 "1",真正的原因在 data 数组里的 sCode 和 sMsg,例如 "sCode": "51008"。自己解析原始响应时别只看外层。

币安 -1021、欧易 50102:时间戳错误怎么解决?

签名请求必须带上发送时刻的时间戳,交易所用它防止请求被截获后重放。两家的规则不一样:

  • 币安:时间戳不能比服务器时间快 1 秒以上,也不能落后超过 recvWindow。recvWindow 不传时默认 5000 毫秒,最大 60000 毫秒,官方建议用 5000 或更小。CCXT 默认会替你带上 recvWindow=10000。
  • 欧易:请求头 OK-ACCESS-TIMESTAMP 必须是 UTC 时间的 ISO 8601 格式并带毫秒,例如 2020-12-08T09:08:57.715Z,和服务器时间相差超过 30 秒就会返回 50102。官方文档特别指出,本地时区偏移是 50102 最常见的原因。

第一步,先量一下你的电脑或服务器和交易所差多少:

import time
import ccxt

for exchange in [ccxt.binance(), ccxt.okx()]:
    local_before = int(time.time() * 1000)
    server = exchange.fetch_time()          # 交易所服务器时间(毫秒)
    local_after = int(time.time() * 1000)
    local_mid = (local_before + local_after) // 2
    print(f"{exchange.id:8s} 服务器时间 {exchange.iso8601(server)}  "
          f"本机偏差 {local_mid - server:+d} ms  往返耗时 {local_after - local_before} ms")

运行时的真实输出(2026 年 10 月 22 日):

binance  服务器时间 2026-10-22T09:30:14.791Z  本机偏差 -287 ms  往返耗时 285 ms
okx      服务器时间 2026-10-22T09:30:15.061Z  本机偏差 -270 ms  往返耗时 289 ms

偏差在几百毫秒以内都正常,这里的数值里还混着网络往返时间。如果偏差达到几秒甚至几分钟,问题就在本机:打开电脑的「自动设置时间」,云服务器检查 NTP 时间同步服务是否在运行。

第二步,在程序里让 CCXT 自动校准。开启 adjustForTimeDifference 后,load_markets() 会顺便查询一次服务器时间,后续签名都按校准后的时间生成:

binance = ccxt.binance({"options": {"adjustForTimeDifference": True}})
binance.load_markets()
print("timeDifference(ms) =", binance.options["timeDifference"])
timeDifference(ms) = -152

程序长时间运行时,时钟会慢慢漂移,可以每隔几小时调用一次 exchange.load_time_difference() 重新校准。不要靠把 recvWindow 调到 60000 来压住 -1021:窗口越大,请求在网络里被延迟或重放后依然有效的时间就越长。

币安 -2015、-1022,欧易 50111、50113:密钥和签名错误怎么排查?

这一类报错说明交易所不认你的身份。按下面的顺序检查,前一项没问题再看下一项:

  1. Key 本身:复制时有没有多带空格或换行?-2014 基本就是格式不对。确认 Key 没被删除或过期。
  2. 环境是否匹配:币安现货测试网和正式站的 Key 互不通用;欧易模拟盘 Key 只能配合模拟盘请求头使用,混用会报 50101。
  3. IP 白名单:绑定了白名单后,从别的 IP 发请求,币安报 -2015,欧易报 50110。家用宽带的公网 IP 会变,程序最好跑在固定 IP 的服务器上。
  4. 权限:读余额只要「读取」,下单还要「现货交易」。永远不要开提现权限。
  5. 签名本身(-1022 / 50113):用 CCXT 时签名由库生成,出错多半是 Secret 填错、欧易 Passphrase 填错。自己手写签名时,请对照 API 签名原理与官方示例复现 逐字节核对签名串。

用 CCXT 时,可以先在测试网上验证这套检查是否生效。下面这段代码按 CCXT 文档写法连接币安现货测试网,下一张远离市价的限价单,成功后立刻撤单,并把不同错误分门别类打印出来:

import os
import ccxt

exchange = ccxt.binance({
    "apiKey": os.environ["BINANCE_API_KEY"],
    "secret": os.environ["BINANCE_API_SECRET"],
    "options": {"adjustForTimeDifference": True},
})
exchange.set_sandbox_mode(True)      # 先连币安现货测试网,不动真钱
exchange.load_markets()

symbol = "BTC/USDT"
price = exchange.fetch_ticker(symbol)["last"] * 0.7   # 远离市价的限价,不会成交
amount = 0.0002

try:
    order = exchange.create_order(symbol, "limit", "buy", amount, price)
    print("下单成功", order["id"], order["status"])
    exchange.cancel_order(order["id"], symbol)          # 测试完立刻撤单
    print("已撤单")
except ccxt.PermissionDenied as e:
    print("权限或 IP 白名单问题:", e)
except ccxt.AuthenticationError as e:
    print("Key、Secret 或签名有问题:", e)
except ccxt.InsufficientFunds as e:
    print("余额不足:", e)
except (ccxt.InvalidOrder, ccxt.BadRequest) as e:
    print("订单参数不符合交易规则:", e)
except ccxt.InvalidNonce as e:
    print("时间戳超出接收窗口:", e)
except ccxt.RateLimitExceeded as e:
    print("请求太频繁:", e)

为了让你看到报错长什么样,我们故意用两个不存在的 Key 跑了这段代码:第一次填一串格式明显不对的字符,第二次填一串 64 位的随机字符。测试网返回的真实结果分别是:

Key、Secret 或签名有问题: binance {"code":-2014,"msg":"API-key format invalid."}
Key、Secret 或签名有问题: binance {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."}

欧易模拟盘的写法类似,多一个 "password": os.environ["OKX_API_PASSPHRASE"],同样调用 set_sandbox_mode(True),CCXT 会自动加上 x-simulated-trading: 1 请求头。用假 Key 请求余额,返回的是 {"msg":"Invalid OK-ACCESS-KEY","code":"50111"}。

注意 except 的顺序:PermissionDenied 是 AuthenticationError 的子类,必须写在前面,否则永远走不到。

币安 -1003、429、418 和欧易 50011:频率限制怎么处理?

截至 2026 年 10 月,币安现货的限频按 IP 计算,不按 API Key。我们实际调用 exchangeInfo 读取到的限额是:

import ccxt

binance = ccxt.binance()
info = binance.publicGetExchangeInfo({"symbol": "BTCUSDT"})
for limit in info["rateLimits"]:
    print(limit)
headers = binance.last_response_headers
print({k: v for k, v in headers.items() if k.lower().startswith("x-mbx-used-weight")})
{'rateLimitType': 'REQUEST_WEIGHT', 'interval': 'MINUTE', 'intervalNum': 1, 'limit': 6000}
{'rateLimitType': 'ORDERS', 'interval': 'SECOND', 'intervalNum': 10, 'limit': 100}
{'rateLimitType': 'ORDERS', 'interval': 'DAY', 'intervalNum': 1, 'limit': 200000}
{'rateLimitType': 'RAW_REQUESTS', 'interval': 'MINUTE', 'intervalNum': 5, 'limit': 300000}
{'x-mbx-used-weight': '131', 'x-mbx-used-weight-1m': '131'}

也就是每分钟 6000 请求权重、每 10 秒 100 笔订单、每天 20 万笔订单。每个接口的权重不同,响应头 X-MBX-USED-WEIGHT-1M 告诉你这一分钟已经用了多少。超限后返回 HTTP 429;收到 429 还继续请求,会被自动封 IP 并返回 418,封禁时长对屡犯者从 2 分钟逐步增加到 3 天。429 和 418 的响应头都带 Retry-After,单位是秒。

欧易的限频按接口分别规定,例如截至 2026 年 10 月,下单接口是每 2 秒 60 次(按用户和交易产品计),K 线接口是每 2 秒 40 次(按 IP 计)。超限返回 50011,账户级下单限速超限返回 50061。

处理原则:

  • 保持 CCXT 的 enableRateLimit 开启(默认就是开启),它会在请求之间自动留出间隔。
  • 能用 WebSocket 推送就别轮询,行情和订单状态都有对应的推送频道。
  • 收到限频错误要退避,等待时间逐次加倍,不要立刻重试。

下面是一个只对「可以重试」的错误重试的小工具,签名、权限、参数错误直接抛出,因为重试也不会好:

import time
import ccxt

def call_with_retry(fn, *args, retries=3, **kwargs):
    """只对“可以重试”的错误重试;签名、权限、参数错误直接抛出"""
    for attempt in range(1, retries + 1):
        try:
            return fn(*args, **kwargs)
        except ccxt.InvalidNonce:
            # 时间戳问题:重新校准时间差后再试(-1021 / 50102)
            fn.__self__.load_time_difference()
        except (ccxt.RateLimitExceeded, ccxt.DDoSProtection):
            # 频率限制:退避等待,等待时间逐次加倍
            time.sleep(2 ** attempt)
        except (ccxt.RequestTimeout, ccxt.ExchangeNotAvailable):
            # 网络超时 / 交易所繁忙:稍等再试。注意下单超时要先查单,不要直接重下
            time.sleep(1)
        print(f"第 {attempt} 次失败,准备重试")
    raise RuntimeError("重试次数用完")

binance = ccxt.binance({"options": {"adjustForTimeDifference": True}})
binance.load_markets()
ticker = call_with_retry(binance.fetch_ticker, "BTC/USDT")
print(ticker["symbol"], ticker["last"])
BTC/USDT 81770.02

(价格为运行时的行情。)

下单报 LOT_SIZE、NOTIONAL、51121:数量和价格精度怎么处理?

每个交易对都有自己的下单规则。币安把它们叫做过滤器:

  • PRICE_FILTER:价格的最小变动单位(tickSize)。
  • LOT_SIZE:数量的最小值、最大值和步长(stepSize)。
  • NOTIONAL / MIN_NOTIONAL:价格乘以数量后的订单金额范围。

欧易对应的字段是 tickSz(价格步长)、lotSz(数量步长)和 minSz(最小下单量)。违反规则时,币安报 -1111(小数位太多)或 -1013 加具体的 Filter failure,欧易报 51121(不是 lot size 的整数倍)或 51020(低于最小下单量)。

CCXT 会把这些规则统一整理到 market["precision"] 和 market["limits"] 里。下面的函数先修正精度,再检查最小数量和最小金额:

import ccxt

def prepare_limit_order(exchange, symbol, amount, price):
    """下单前自检:按交易对规则修正精度,再检查最小数量和最小金额"""
    market = exchange.market(symbol)
    amount_str = exchange.amount_to_precision(symbol, amount)  # 数量:按步长截断
    price_str = exchange.price_to_precision(symbol, price)     # 价格:按最小变动价位取整
    cost = float(amount_str) * float(price_str)
    limits = market["limits"]
    problems = []
    if limits["amount"]["min"] and float(amount_str) < limits["amount"]["min"]:
        problems.append(f"数量小于最小下单量 {limits['amount']['min']}")
    if limits["cost"]["min"] and cost < limits["cost"]["min"]:
        problems.append(f"金额 {cost:.2f} 小于最小下单金额 {limits['cost']['min']}")
    return amount_str, price_str, round(cost, 2), problems

symbol = "BTC/USDT"
for exchange in [ccxt.binance(), ccxt.okx()]:
    exchange.load_markets()
    market = exchange.market(symbol)
    print(exchange.id, "precision =", market["precision"])
    print(exchange.id, "limits.amount =", market["limits"]["amount"],
          "limits.cost =", market["limits"]["cost"])
    last = exchange.fetch_ticker(symbol)["last"]
    far_price = last * 0.7            # 远离市价的限价,仅用于演示
    print(" 原始输入 0.0123456789 BTC @", far_price)
    print(" 修正结果", prepare_limit_order(exchange, symbol, 0.0123456789, far_price))
    print(" 小额测试", prepare_limit_order(exchange, symbol, 0.00005, far_price))

运行时的真实输出(节选,价格为运行时行情的 70%):

binance precision = {'amount': 1e-05, 'price': 0.01, 'base': 1e-08, 'quote': 1e-08}
binance limits.amount = {'min': 1e-05, 'max': 9000.0} limits.cost = {'min': 5.0, 'max': 9000000.0}
 原始输入 0.0123456789 BTC @ 57251.747
 修正结果 ('0.01234', '57251.75', 706.49, [])
 小额测试 ('0.00005', '57251.75', 2.86, ['金额 2.86 小于最小下单金额 5.0'])
okx precision = {'amount': 1e-08, 'price': 0.1}
okx limits.amount = {'min': 1e-05, 'max': 9999999999.0} limits.cost = {'min': None, 'max': 1000000.0}
 原始输入 0.0123456789 BTC @ 57256.57
 修正结果 ('0.01234567', '57256.6', 706.87, [])
 小额测试 ('0.00005', '57256.6', 2.86, [])

从输出可以读出几件事:

  • 同一个 BTC/USDT,两家规则不同。 截至 2026 年 10 月实测,币安数量步长 0.00001、价格步长 0.01、最小下单金额 5 USDT;欧易数量步长 0.00000001、价格步长 0.1、最小下单量 0.00001 BTC。代码里不要写死精度,每次启动都从 load_markets() 读取。
  • 数量是截断,价格是四舍五入。 amount_to_precision 把 0.0123456789 截成 0.01234,不会向上凑,保证你不会因为进位而余额不足。
  • 精度对了不代表能下单。 币安那笔 2.86 USDT 的小单精度完全合规,但低于 5 USDT 的最小金额,真发出去会收到 Filter failure: NOTIONAL。欧易这里没有给出最小金额,但仍受最小下单量约束。

CCXT 本身也会提前拦下一部分明显不合规的输入,不用发请求就能看到异常:

binance = ccxt.binance()
binance.load_markets()
try:
    binance.market("ABCXYZ/USDT")
except ccxt.BadSymbol as e:
    print("不存在的交易对 -> BadSymbol:", e)
try:
    binance.amount_to_precision("BTC/USDT", 0.000001)
except ccxt.InvalidOrder as e:
    print("数量小于步长 -> InvalidOrder:", e)
不存在的交易对 -> BadSymbol: binance does not have market symbol ABCXYZ/USDT
数量小于步长 -> InvalidOrder: binance amount of BTC/USDT must be greater than minimum amount precision of 0.00001

另外,CCXT 的 create_order 在发送前会自动调用 amount_to_precision 和 price_to_precision,所以用 CCXT 时 -1111 很少见,更常见的是最小金额和最小数量问题。自己手写请求时,数量和价格要用字符串传递,避免浮点数产生 0.30000000000000004 这样的多余小数位。

遇到 API 报错,按什么顺序排查最快?

把上面的内容压缩成一张排查流程表。拿到报错后从第一行往下对照:

顺序 检查项 典型错误 怎么确认 怎么修
1 网络和交易所状态 超时、HTTP 5xx、-1007、50001 公开接口(如 fetch_time)能否正常返回 稍后重试;下单类请求先查单
2 时间 -1021、50102 对比本机时间和 fetch_time() 开启自动对时和 adjustForTimeDifference
3 环境 -2015、50101 Key 是在测试网或模拟盘创建,还是在正式站 测试 Key 配 set_sandbox_mode(True)
4 Key、IP 和权限 -2014、-2015、50110、50111 在交易所 API 管理页面核对 重新复制 Key,补充白名单 IP,开对权限
5 签名 -1022、50113 用官方示例参数复现签名 检查 Secret、Passphrase 和签名串拼接
6 频率 -1003、429、418、50011 查看 X-MBX-USED-WEIGHT-1M 等响应头 退避等待,改用 WebSocket
7 订单参数 -1013、-1111、51020、51121 对照 market["limits"] 与 market["precision"] 修正精度,提高订单金额
8 余额 -2010、51008 fetch_balance() 看可用余额,挂单会冻结资金 撤掉多余挂单或减少数量

写程序时,建议把每次报错的错误码、时间和请求参数(去掉签名和 Key)记到日志里。同一个错误反复出现时,回头看日志比临时猜测快得多。手续费也会影响「余额刚好够」的订单,费率细节见 交易手续费怎么算。所有测试请先在币安现货测试网或欧易模拟盘完成,确认无误后再用小金额连接正式账户。更多 API 与量化教程见 识途量化专栏。

常见问题

币安 API 报 -1021 Timestamp for this request is outside of the recvWindow 怎么办?

说明请求到达服务器时,时间戳和服务器时间相差超过了接收窗口。先打开系统自动对时,再在程序里用服务器时间校准,CCXT 可开启 adjustForTimeDifference。不建议把 recvWindow 调到很大来掩盖问题,币安官方建议 5000 毫秒或更小。

币安 API 报 -2015 Invalid API-key, IP, or permissions for action 是什么原因?

这个错误同时覆盖三种情况:Key 填错或已删除、当前服务器 IP 不在白名单内、Key 没开对应权限(例如没开现货交易就去下单)。还有一种常见情况是把测试网的 Key 拿去连正式环境,两边的 Key 不通用。

欧易 API 报 50113 Invalid signature 怎么排查?

欧易签名串是 时间戳 + 请求方法 + 请求路径 + 请求体,用 SecretKey 做 HMAC SHA256 后再 Base64。最常见的错误是请求路径漏了查询参数、POST 请求体和实际发送的 JSON 不一致、时间戳格式不是 UTC 毫秒 ISO 格式。用 CCXT 时多半是 Secret 或 Passphrase 填错。

下单报 Filter failure: LOT_SIZE 或 NOTIONAL 是什么意思?

LOT_SIZE 表示数量不符合该交易对的最小数量、最大数量或数量步长;NOTIONAL 表示价格乘以数量后的订单金额不在允许范围内,通常是金额太小。先用 load_markets 读取交易对规则,再用 amount_to_precision 修正数量并检查最小金额。

API 请求太频繁被封 IP 要多久才能恢复?

币安在你收到 429 后仍继续请求,会自动封禁 IP 并返回 418,封禁时长按重复次数递增,从 2 分钟到 3 天不等,响应头的 Retry-After 会告诉你还要等多少秒。欧易限频时返回 50011,按接口和账户分别计算,等待后降低请求速度即可。

准备好出发了吗?

币安邀请
币安

全球交易量最大的加密货币交易所之一,币种与流动性领先

邀请码
注册币安 ↗含推广链接 · 注册前请确认当地法规 · 币安评测
欧易邀请
欧易

老牌头部交易所,App 体验与 Web3 钱包整合出色

邀请码
注册欧易 ↗含推广链接 · 注册前请确认当地法规 · 欧易评测

参考来源

  1. Binance Developer Docs:Error codes for Binance(现货)
  2. Binance Developer Docs:General REST API Information(时间安全与频率限制)
  3. OKX API v5 文档:Error Code 与 REST 认证说明
  4. CCXT Manual:Error Handling 与 Precision

以上信息核实于 2026-10-22,交易所规则可能调整,请以官方最新说明为准。

本文仅供学习参考,不构成投资建议。交易所的费率、活动与功能可能随时调整,请以官方页面为准。文中部分链接为推广链接,详见推广披露。