欧易 · API 进阶
用 WebSocket 接欧易实时行情:进阶策略为什么要换掉 REST 轮询
策略跑久了,你大概会遇到这种尴尬:明明逻辑没错,实盘成交却总慢半拍。盯着代码看,问题往往不在策略本身,而在你拿行情的方式——还在用 REST 一遍遍地问「现在多少钱」。这种轮询天生有延迟,频率一高还撞限频。要让策略反应更快,通常该把行情接入从轮询换成 WebSocket 推送。
这篇我们(量化喵编辑组)讲清楚 WebSocket 在欧易上怎么用:它和 REST 轮询差在哪、为什么进阶策略要用它、欧易有哪些频道、怎么用 ccxt.pro 的 watch_ticker 和 watch_orders 写推送、断线重连和心跳怎么处理,以及——很重要的一句——它适合谁。提前说结论:这是进阶内容,新手的简单策略用 REST 就够,别为了「看起来专业」过早上 WS。
REST 轮询 vs WebSocket 推送
两者的区别,用一个生活类比就清楚了。REST 轮询像你每隔几秒就打个电话问对方「有新消息吗」,大多数时候得到的回答是「没有」,白打;WebSocket 像你和对方接通了一条不挂断的线,他一有消息就直接说给你听,你什么都不用问。
落到技术上:
| 维度 | REST 轮询(fetch_) | WebSocket 推送(watch_) |
|---|---|---|
| 取数方式 | 你主动一遍遍发请求 | 建一条长连接,交易所主动推 |
| 延迟 | 受轮询间隔限制,天生滞后 | 数据一变就推,延迟低 |
| 请求消耗 | 高频轮询易撞限频 | 一条连接,几乎不消耗请求额度 |
| 自己的订单/账户 | 得反复查才知道成没成 | 私有频道实时推订单成交、账户变动 |
| 实现复杂度 | 同步、直观、好调试 | 异步、要处理断线重连和心跳 |
| 适合 | 新手、低频策略 | 进阶、对时效敏感的策略 |
简而言之:REST 简单但慢,WebSocket 快但要多写些代码。选哪个,取决于你的策略对「快」有多在意。
为什么策略要用 WS
把上面的对比浓缩成三个让策略受益的点:
- 延迟低,反应快。价格一变就推到你手里,策略能更早做出反应。对吃震荡、抢价差的策略,这点延迟差距可能就是赚和不赚的分界。
- 省请求,不撞限频。WS 是一条长连接,不像轮询那样反复发请求,自然不容易触发限频。想盯很多个交易对时,这个优势尤其明显。
- 实时知道自己的状态。私有频道会把你的订单成交、持仓变动、余额变化主动推给你,不用一遍遍
fetch_open_orders去查。策略据此调整更及时,也更省接口。
但请注意「受益」是有前提的:你的策略得真的对时效敏感。如果你跑的是一小时检查一次的低频网格,WS 那点延迟优势对你毫无意义,反而平白引入了复杂度。
欧易 WS 的频道
欧易的 WebSocket(API v5)频道大致分两类,理解这个划分,后面写代码就顺了:
公有频道(Public)。推的是公开的市场数据,任何人都能订阅,不需要鉴权。常用的有:
- 行情(tickers):最新成交价、买一卖一、24 小时涨跌等。
- K 线(candles):各周期的 K 线更新。
- 盘口深度(books):买卖盘挂单深度。
- 逐笔成交(trades):市场上发生的每一笔成交。
私有频道(Private)。推的是你自己账户相关的数据,订阅前需要用 API Key 鉴权(同样是 apiKey、secret、Passphrase 三件套)。常用的有:
- 订单(orders):你的委托单状态变化、成交回报。
- 持仓(positions):合约持仓的变动。
- 账户(account):余额、保证金等变化。
一句话记:公有频道看市场,私有频道看自己。你既可以只订公有频道做行情驱动的策略,也可以同时订私有频道,实时跟踪自己的下单结果。
用 ccxt.pro 接行情(watch_ticker)
接 WS 最省事的方式还是走 ccxt——它的 WebSocket 扩展叫 ccxt.pro,如今已并入 ccxt 主包。普通 ccxt 走 REST,用 fetch_ 系列;ccxt.pro 走 WS,用 watch_ 系列。因为底层是长连接,代码要写成异步(async)的循环。
下面这段订阅 BTC/USDT 的行情,价格一更新就打印:
import asyncio
import ccxt.pro as ccxtpro # WS 版,watch_ 系列
async def main():
okx = ccxtpro.okx() # 公有行情不需要鉴权
symbol = 'BTC/USDT'
try:
while True:
ticker = await okx.watch_ticker(symbol) # 有新行情才返回
print(ticker['symbol'], ticker['last'])
finally:
await okx.close() # 退出时关掉长连接
asyncio.run(main())
和 REST 的关键区别在 await okx.watch_ticker(...):它不是你主动去拉,而是「挂在那儿等推送」,有新行情才返回。把它放在 while True 循环里,就成了一个持续接收行情的流。注意结尾的 await okx.close()——长连接用完要主动关,别让它悬着。
接私有订单频道(watch_orders)
公有行情之外,进阶玩法是同时盯自己的订单。watch_orders 会在你的委托单状态一有变化(部分成交、完全成交、撤单)就推给你,比反复 fetch_open_orders 及时得多。它属于私有频道,所以要带上凭证:
import asyncio
import ccxt.pro as ccxtpro
async def main():
okx = ccxtpro.okx({
'apiKey': '你的_apiKey',
'secret': '你的_secret',
'password': '你的_Passphrase', # 私有频道需鉴权
})
try:
while True:
orders = await okx.watch_orders() # 你的订单一有变化就推
for o in orders:
print(o['symbol'], o['side'], o['status'], o.get('filled'))
finally:
await okx.close()
asyncio.run(main())
有了这个,你的策略就能在订单一成交的瞬间拿到回报,据此立刻挂下一单或调整仓位,而不是等下一轮轮询才发现「哦,刚才那单成了」。这对网格、做市这类需要快速接力下单的策略很关键。私有频道用的还是你那把实盘 API Key(建 Key 见 API 量化入门),权限只勾「读取」和「交易」,别勾「提现」。
OK30001 注册欧易,手续费有减免,API 下的单同样适用这个减免。点这里注册欧易并开 API →
断线重连与心跳
长连接最大的现实问题是:它会断。网络抖一下、交易所例行重启,连接就没了。WS 策略写得稳不稳,很大程度看你怎么处理断线。两件事必须做:
心跳 / 保活。WebSocket 协议靠定期的 ping/pong 来确认连接还活着。如果一段时间没动静,交易所会把这条连接当成死连接掐掉。好在 ccxt.pro 内部一般帮你处理了保活,你主要确保别让程序长时间阻塞、卡住消息收发即可。
断线重连 + 重新订阅。连接断了要能自动重连,而且重连后要重新订阅频道、并补查一次当前真实状态(比如重新拉一遍当前挂单和持仓),因为断线期间发生的推送你是收不到的。常见写法是把 watch_ 调用包在 try/except 里,捕获连接类异常后重连重订:
import asyncio
import ccxt.pro as ccxtpro
async def main():
okx = ccxtpro.okx()
symbol = 'BTC/USDT'
while True:
try:
ticker = await okx.watch_ticker(symbol)
print(ticker['last'])
except ccxtpro.NetworkError as e:
print('连接异常,稍后重连重订:', e)
await asyncio.sleep(2) # 退一步再重连,别狂撞
# 重连后视情况补查一次当前持仓/挂单的真实状态
except Exception as e:
print('其他异常:', e)
await asyncio.sleep(2)
asyncio.run(main())
这里的重点不是代码多漂亮,而是那条原则:断线之后别假设状态没变,先补查再继续。这和我们在 量化风控 里讲的「重连后先查状态、再动作」是同一回事——失联期间市场可能已经动了,盲目接着跑容易出乱子。
实测:延迟对比
fetch_ticker 轮询一次,一个用 ccxt.pro 的 watch_ticker 接推送。结果很直观——轮询那边的价格更新明显「一格一格」地跳,两次更新之间最多差了接近 3 秒(因为它就是 3 秒问一次);WS 那边价格几乎是连续刷新的,行情一动就推过来,体感上快得多。我们没去精确卡毫秒(模拟盘环境也不代表实盘网络),但「轮询滞后于推送」这件事一目了然。对低频策略这点差距无所谓,但要是做吃震荡、抢价差的策略,这几秒就是实打实的劣势。这次对比也让我们确认:该上 WS 的策略,早点上;用不上的,REST 反而更省心。
它适合谁
说回最该想清楚的问题:你需不需要 WebSocket。我们的判断标准很简单——
建议先用 REST 的情况:你是新手;策略是低频的(几分钟甚至几小时检查一次);逻辑简单、对延迟不敏感。REST 同步、直观、好调试,这些场景它完全够用,而且少了异步和断线重连的坑,你能把精力放在策略本身。
值得上 WS 的情况:策略对延迟敏感(吃震荡、做市、价差套利);你要同时盯很多交易对,轮询开始撞限频;你需要订单成交的实时回报来接力下单。到了这些场景,WS 带来的实时性和效率,值得你多写那些异步和重连的代码。
一句话总结:别为了显得专业而过早上 WS。先用 REST 把策略跑通跑顺,等你真的撞上轮询的天花板——慢了、或撞限频了——再升级到 WebSocket,这个顺序最省力,也最不容易在还没搞懂策略时就被技术复杂度绊住。无论用哪种,新代码都先丢 模拟盘 验证。
常见问题
REST 轮询和 WebSocket 推送有什么区别?
REST 轮询是你主动一遍遍去问交易所「现在价格多少」,每次都要发一个请求、等一个响应,既有延迟又容易撞限频。WebSocket 是建立一条长连接,交易所有新数据就主动推给你,你不用反复发问。对要快速反应行情的策略,推送的实时性和效率都明显优于轮询。
为什么策略要用 WebSocket?
三个原因:一是延迟低,价格一变就推过来,反应更快;二是省请求,不用高频轮询,自然不容易撞限频;三是私有频道能实时收到你自己的订单成交、账户变动推送,不用反复查。对网格、做市、高频这类对时效敏感的策略,WS 几乎是标配。但新手阶段的简单策略,REST 轮询通常就够用。
欧易 WebSocket 有哪些频道?
大致分两类。公有频道推公开的市场数据,比如行情(ticker)、K 线、盘口深度、成交,任何人都能订阅,不需要鉴权。私有频道推你自己账户相关的数据,比如订单更新、持仓变动、账户余额,订阅前需要用 API Key 鉴权。公有看行情,私有看自己。
ccxt.pro 和普通 ccxt 是一回事吗?
ccxt.pro 是 ccxt 的 WebSocket 扩展,把各交易所的 WS 也封装成了统一接口。普通 ccxt 走 REST(fetch_ 系列),ccxt.pro 走 WS(watch_ 系列,比如 watch_ticker、watch_orders)。如今 ccxt.pro 已并入 ccxt 主包,装好 ccxt 后用异步的 watch_ 方法即可。底层是长连接,所以代码要写成异步循环。
WebSocket 断线了怎么办?
长连接难免会断——网络抖动、交易所重启都可能。两件事要做:一是心跳/保活,定期发 ping 或依赖库的保活机制,让连接不被判定为死连接;二是断线重连,捕获连接异常后自动重连,并在重连后重新订阅频道、补查一次当前真实状态。用 ccxt.pro 的 watch_ 方法时,把它放在 try/except 的循环里,断了就重连重订,是常见写法。
新手该先用 REST 还是 WebSocket?
先用 REST。REST 同步、直观、好调试,新手的简单策略(比如低频网格、定时检查)用它完全够。WebSocket 引入了异步、长连接、断线重连这些复杂度,等你的策略真的对延迟敏感、或者轮询开始撞限频时,再升级到 WS 也不迟。别为了「看起来专业」而过早上 WS。
WebSocket 是个好工具,但它是给「已经知道自己为什么需要它」的人准备的。如果你还在打基础,先把 API 量化入门 跑通,把 风控 装好,这些比换成 WS 重要得多。等策略真的快不起来了,再回来看这篇。
策略要提速了?先把账户和 API 备齐
WebSocket、私有频道、实时订单推送,前提都是一把权限设好的 API Key。用邀请码注册的新账户,手续费有减免,API 下的单一样适用——先把基础打好,再谈进阶。
加密资产价格波动剧烈,合约与杠杆可能导致本金全部亏损。量化与自动化交易不保证盈利,请只用你能承受损失的资金。