簡繁
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,交易所規則可能調整,請以官方最新說明為準。

本文僅供學習參考,不構成投資建議。交易所的費率、活動與功能可能隨時調整,請以官方頁面為準。文中部分連結為推廣連結,詳見推廣披露。