量化喵是独立第三方信息站,不是欧易(OKX)官方。站内含推广链接。 完整披露 →

欧易 · API 实操

欧易 API 常见报错与排查清单:照着这张表修

写量化脚本时,可能还没轮到琢磨策略,就先卡在一行红字报错上:脚本跑起来,终端弹出一串看不懂的 code 和英文,人就懵了。好消息是,欧易 API 的报错就那么几种高频款,搞清楚每种长什么样、对应哪个原因,排查会快得多。

这篇把欧易 API 的常见报错整理成一份清单,核心是一张错误码对照表——出了问题,先到表里按错误码或关键词定位,再看下面对应的逐条排查。读完你应该能把大多数报错在几分钟内自己解决,而不是对着红字干瞪眼。

先学会读报错:code + msg

排错的第一步,是看懂报错本身。欧易接口出错时,会返回三样信息:

  • HTTP 状态码:最粗的一层,比如 401(鉴权问题)、429(请求太多)、400(请求本身有问题)。
  • code:欧易自己的数字错误码,最精确地指向问题类型。这是你排查的主要依据。
  • msg:一段文字说明,帮你确认方向,有时还会直接点出哪个字段出错。

如果你用 ccxt,它会把这些原始报错包装成更易读的异常类型,比如鉴权问题抛 AuthenticationError、限频抛 RateLimitExceeded、余额不够抛 InsufficientFunds。异常信息里一般也带着欧易的原始 code 和 msg。一个好习惯是用 try/except 把它们打印清楚:

import ccxt

okx = ccxt.okx({
    'apiKey':   '你的_apiKey',
    'secret':   '你的_secret',
    'password': '你的_Passphrase',
    'enableRateLimit': True,
})

try:
    balance = okx.fetch_balance()
    print('USDT 可用:', balance['USDT']['free'])
except ccxt.InvalidNonce as e:
    print('时间戳过期(50102),先校准本机时间再重试:', e)
except ccxt.AuthenticationError as e:
    print('鉴权失败,先看报错里的 code 再决定查什么:', e)
except ccxt.RateLimitExceeded as e:
    print('触发限频,放慢请求:', e)
except ccxt.BaseError as e:
    print('其他报错,看原始 code/msg:', e)

把异常里那串 code 和 msg 原样记下来,对照下面这张表,基本就能定位到底是哪一类问题。

高频报错对照表

下面这张表覆盖了新手容易撞上的几种报错。表里的错误码含义核于 2026-10,以欧易 API v5 文档 Error Code 一节为准(欧易偶尔会调整码值,遇到对不上的就以 msg 文字和官方文档为准),重点是把「原因→怎么修」对上号。鉴权这一类尤其要按 code 分支走:同样是「连不上」,50113 和 50105 要查的是完全不同的东西。

报错(code / 关键词)大概率原因怎么修
50011
Too Many Requests / 限频
请求太密集,触发接口限频保护 打开 enableRateLimit;还撞就加指数退避重试,别用无延时的 while 循环
50113
Invalid signature
签名本身没通过校验,问题出在签名这一步,不一定是凭证填错 核对签名原文的拼接方式(请求方法、请求路径、请求体)、用来做 HMAC 的是不是 secret、有没有按 HMAC-SHA256 算完再 Base64;用 ccxt 一般不用自己签,先确认 secret 没复制错
50111
Invalid OK-ACCESS-KEY
apiKey 本身无效:复制错(首尾带空格、漏字符)或已被删 重新从后台复制 apiKey;确认这个 Key 还在、没被删
50101
APIKey does not match current environment
Key 与环境对不上:模拟盘 Key 没开 set_sandbox_mode(True),或实盘 Key 开了它 让 Key 与开关对齐:模拟盘 Key 配 set_sandbox_mode(True),实盘 Key 不开;自检 okx.headers.get('x-simulated-trading'),模拟盘下应打印 1
50105
OK-ACCESS-PASSPHRASE incorrect
(50104 = 这一项为空)
口令对不上:ccxt 的 password 字段填成了登录密码,而不是建 Key 时设的 Passphrase 把 password 改成你建那个 Key 时设的 Passphrase;记不清只能删 Key 重建
余额不足
Insufficient balance
下单金额超过账户可用余额,或资金在别的账户(如资金账户 vs 交易账户) 减小下单量;确认资金在用于交易的账户里;模拟盘可重置虚拟资金
50102 Timestamp request expired
50112 Invalid OK-ACCESS-TIMESTAMP
请求里的时间戳和服务器时间对不上:按官方文档,相差超过 30 秒就直接拒绝(50112 则是这个字段本身格式不对) 开启 NTP 自动校时,把系统时间同步准;云服务器一般默认已开
50120
API key 没有该功能的权限
这个 Key 没有所需权限(常见:只勾了读取,没勾交易);它返回的是 HTTP 200,不像别的鉴权错那样报 401,要读 body 里的 code 才看得见 回 API 管理给该 Key 补勾「交易」权限,不用重建
50110
Your IP is not included in your API key's IP whitelist
给 Key 设了 IP 白名单,但当前出口 IP 不在名单里(换网络/开代理/宽带 IP 变了) 先查清自己当前的出口 IP,再把它加进该 Key 的白名单(每把 Key 最多绑 20 个 IP,支持网段);出口 IP 不稳定的处置见下文,别拿「取消白名单」当常规解法
交易对不存在
instrument does not exist
symbol 格式写错,或用了合约格式去下现货单 现货写成 BTC/USDT(大写带斜杠);先 load_markets() 看可用交易对
数量/精度不符
size too small
下单量小于该交易对最小下单量,或精度位数不对 用 load_markets() 查该交易对的 limits 和 precision,按要求取整

逐条排查怎么修

表格给方向,这一节给细节。挑你撞上的那条往下看。

鉴权类(50101 / 50102 / 50105 / 50110 / 50111 / 50112 / 50113)与权限类(50120)

鉴权失败在 HTTP 层统统是 401,ccxt 里多数抛 AuthenticationError(50110 抛的 PermissionDenied 也是它的子类)。例外是 50102「时间戳过期」:按 ccxt 主分支 2026-09 的源码,它被映射成 InvalidNonce,归在 NetworkError 那一支,只写 except AuthenticationError 接不住它,得单独写一个分支。所以别照着「最常见的原因」挨个试——先把 code 抠出来,再按 code 走对应的那一条。50120「权限不足」要单独摘出来:它不在 401 那一堆里,按官方错误码表走的是 HTTP 200、靠 body 里的 code 判断,请求在协议层是「成功」的,只凭状态码你根本看不出它出了错。

  • 50113 Invalid signature:查签名这一步。签名原文的拼接(请求方法、请求路径、请求体)、用来做 HMAC 的密钥是不是 secret、有没有按 HMAC-SHA256 算完再 Base64。用 ccxt 的话签名是库做的,这时先怀疑 secret 复制错了。
  • 50105 Passphrase 不对(50104 是没填):只查口令。ccxt 里的 password 字段填的必须是你建 Key 时设的那串 Passphrase,不是登录密码,也不是 secret;记不清了只能删 Key 重建。
  • 50102 / 50112 时间戳问题:只查时间。按官方文档,请求时间戳与服务器时间相差超过 30 秒就会被拒。开 NTP 自动校时,长期跑的机器定期确认它真的在同步。用 ccxt 的话,50102 抛的是 InvalidNonce,在它的分支里校完时间再重试;最后留一个 BaseError 兜底。
  • 50111 Invalid OK-ACCESS-KEY:查 apiKey 本身——复制时首尾带了空格、漏了字符,或者 Key 已被删。
  • 50101 APIKey 与当前环境不匹配:Key 本身没错,是环境对不上——模拟盘 Key 没开 set_sandbox_mode(True)(请求不带模拟盘标记头,按实盘处理),或实盘 Key 开了它。把 Key 和开关对齐,再打印 okx.headers.get('x-simulated-trading') 自检,模拟盘下应为 1。ccxt 里它抛的也是 AuthenticationError。
  • 50110 IP 不在白名单:查网络出口,不是查凭证。见下面「IP 白名单」一节。
  • 50120 权限不够(HTTP 200):凭证都对,只是这个 Key 没勾上对应权限。它不会以 401 的形式出现,只能读 body 里的 code——所以判断逻辑别只写 if status == 401。见下面「权限不足」。

顺带说一句:欧易的 msg 文字有时会直接点名是哪个 header 出的问题,把它和 code 一起原样记下来,比凭印象猜快得多。

权限不足

典型症状是「能查余额,不能下单」。查余额走读取权限,下单走交易权限,两者分开授权。回欧易后台 API 管理,找到这个 Key,补勾「交易」即可,不用重建。如果你顺手勾过提现——别留着,跑量化的 Key 永远别开提现权限。另外别把「交易权限」想得太窄:按欧易文档的定义,它除了下单撤单,还包含资金划转和一部分账户设置,所以为了做账户间划转去补勾提现是没必要的。

IP 白名单(50110)

这条报错说的是「你现在这个出口 IP 不在这把 Key 的名单里」,所以排查从网络出口开始,而不是从凭证开始:

  • 先把当前出口 IP 查出来,和你在后台给这把 Key 填的名单逐个对一遍。注意是出口 IP:开了代理、走了公司网关、家里宽带重拨过,出口都可能和你以为的不是同一个。
  • 出口 IP 不稳定,解决方向是把出口固定下来,而不是把锁拆掉:把策略挪到一台 IP 固定的机器上跑,或者在出口确实会变时有节奏地更新白名单。欧易这边每把 Key 最多绑 20 个 IP,支持 IPv4/IPv6 和网段,留出余量并不难。
  • 调试阶段用只读 Key 或模拟盘 Key,别拿那把有交易权限的主力 Key 反复试。
  • 不建议把「取消白名单」当常规排障动作。官方对绑 IP 的说法是强烈建议而非强制,但有一条规则要知道:没有绑定 IP、又带 trade 或 withdraw 权限的 Key,闲置 14 天后会被自动删除——所以不绑 IP 的 Key 除了风险更大,还可能哪天被删掉。模拟盘 Key 不受这条删除规则约束,这也是拿它做调试的一个理由。

余额不足

除了字面意义的钱不够,还有一个隐蔽原因:欧易有不同的账户(资金账户、交易账户等),你的钱可能不在用于下单的那个账户里。确认资金已经划转到交易账户。模拟盘的话,虚拟资金用完了在模拟盘界面重置即可——这也是 先在模拟盘练手 的好处,试错不花真钱。

symbol / 精度类

现货交易对在 ccxt 里统一是 大写/大写 带正斜杠,比如 BTC/USDT。写成 BTCUSDT、小写、或用合约格式都会报错。数量太小或精度不对,就用 load_markets() 查这个交易对的最小下单量和精度,按它要求来。这块在我们的 API 量化入门 里有完整的下单示例。

限频与退避重试

限频(50011 / Too Many Requests)是脚本党容易撞上、也最该提前防的一类。触发它通常不代表代码写错了,只是请求太密集,碰到了交易所的保护。处理它分两层:

第一层:打开 ccxt 自带的限速。初始化时加 'enableRateLimit': True,ccxt 会自动在请求之间插入合理间隔,大多数场景这一步就够了:

okx = ccxt.okx({
    'apiKey':   '你的_apiKey',
    'secret':   '你的_secret',
    'password': '你的_Passphrase',
    'enableRateLimit': True,   # 自动限速,先开上
})

第二层:加指数退避重试。如果你的策略在某些时刻请求确实很密(比如同时刷很多交易对),光靠自动限速可能还会偶尔撞。这时给关键请求包一层重试:撞一次等 1 秒再试,再撞等 2 秒、4 秒,逐步拉长,撞够几次就放弃报错。

import ccxt, time

def with_retry(fn, max_tries=5):
    delay = 1
    for i in range(max_tries):
        try:
            return fn()
        except ccxt.RateLimitExceeded:
            print(f'限频,第 {i+1} 次,等 {delay}s 再试')
            time.sleep(delay)
            delay *= 2          # 指数退避:1 → 2 → 4 → 8 ...
    raise RuntimeError('重试多次仍被限频,放弃')

# 用法:把会被限频的调用丢进去
ticker = with_retry(lambda: okx.fetch_ticker('BTC/USDT'))
print(ticker['last'])

一个反面教材:别写 while True: 里面紧接着打接口、中间不加任何延时。这种循环会在一秒内打出几十上百个请求,瞬间撞限频。任何高频循环里都要留间隔。

一个高频踩坑场景

📋 常见踩坑场景
一个很典型的场景:在欧易模拟盘调试一个多交易对扫描脚本,一上来就在循环里对十几个交易对连着调 fetch_ticker,中间没加任何延时,也忘了开 enableRateLimit。这种写法会持续触发接口的限频保护,终端开始刷 RateLimitExceeded(对应 50011),后面的请求大批失败。修法分两步:先在初始化加上 'enableRateLimit': True,再把每个交易对的请求包进上面那个 with_retry 退避函数。改完再跑,请求之间就有了间隔,偶尔撞上限频也会按退避重试而不是直接报废。教训很直接:循环里打接口,限速和退避是标配,不是可选项。
风险提示:报错修好了,只说明脚本能跑通,不代表它能赚钱。比一行红字更可怕的,是脚本一个错都不报,却安安静静地一直下错单。加密资产价格波动剧烈,本金可能大幅缩水甚至归零;API 自动化会把错误的执行速度放大,合约与杠杆交易可能导致 100% 本金亏损。本文是技术排障整理,不构成任何投资建议。请只用你能承受全部损失的闲钱,并遵守所在地的法律法规。

常见问题

欧易 API 报错怎么读?

欧易的接口出错时会返回一个 code(数字错误码)和一段 msg(文字说明),还有 HTTP 状态码。先看 code,它最精确地指向问题类型;msg 帮你确认方向。在 ccxt 里,报错通常被包成对应的异常类型(比如 AuthenticationError、RateLimitExceeded、InsufficientFunds),异常信息里一般也带着欧易原始的 code 和 msg。把这串信息原样搜一下,基本就能定位。

为什么一直报鉴权失败 / Invalid sign?

别把鉴权失败当成一种错。它们在 HTTP 层都是 401,在 ccxt 里多数抛 AuthenticationError,只有 50102 时间戳过期抛的是 InvalidNonce(属于 NetworkError),要单独接;欧易返回的 code 指向的是不同的东西:50113 是签名没通过,查签名原文的拼接方式和 secret;50105 是 Passphrase 不对,ccxt 的 password 字段填的必须是建 Key 时设的那串口令;50102 与 50112 是时间戳问题,请求时间与服务器时间相差超过 30 秒就会被拒,开 NTP 校时;50111 是 apiKey 本身无效;50101 是 Key 与环境不匹配,模拟盘 Key 没开 set_sandbox_mode,或实盘 Key 开了它;50110 是当前出口 IP 不在白名单里。50120「权限不足」要单独摘出来:它不在 401 那一堆里,按官方错误码表走 HTTP 200、靠 body 里的 code 判断,凭证都没问题,只是这把 Key 没勾上对应权限。先把 code 抠出来,再决定查哪一样,比按经验挨个试快。

触发限频(50011 / Too Many Requests)怎么办?

限频是请求太密集触发的保护。最省事的办法是在初始化 ccxt 时打开 enableRateLimit,它会自动在请求间插入间隔。如果还撞,就在代码里加指数退避重试——撞一次等 1 秒,再撞等 2 秒、4 秒,逐步拉长。别用 while True 不加延时去打接口。

能查余额但下单报权限不足,为什么?

查余额属于读取权限,下单属于交易权限,两者在建 Key 时是分开授权的。能查不能下,基本就是只勾了读取没勾交易。回欧易后台 API 管理里给这个 Key 补勾交易权限即可,不用重建。

时间戳过期(timestamp expired)是什么意思?

欧易对请求里的时间戳有容差,如果你的电脑或服务器系统时间不准、偏差超过容差,签名就会因为时间戳过期被拒。解决办法是把系统时间同步到准确的网络时间,开启 NTP 自动校时。云服务器一般默认开了,本地机器偶尔会漂。

报「交易对不存在」是怎么回事?

先看报错里的 code 和 msg,这类报错指向的是 symbol 这个字段。ccxt 里现货交易对是大写带正斜杠,比如 BTC/USDT,写成 BTCUSDT、btc/usdt、或者用了合约格式去下现货单,都会报交易对不存在。msg 有时会直接点出哪个字段不合法,按它点的字段查最省事;拿不准就先 print(okx.load_markets().keys()) 看一眼可用的交易对到底长什么样。

把报错排查这关过了,你的脚本就不会动不动卡死了。接下来值得花时间的是把 风控写进代码——比报错更可怕的是脚本没报错却一直在下错单。也别忘了新代码先丢 模拟盘 里跑,排错不花真钱。