WebSocket订阅Deribit API获取BTC/ETH价格异常求助
解决Deribit测试API WebSocket授权后无法持续获取last_price的问题
我来帮你搞定这个Deribit WebSocket的问题!你遇到的情况其实是消息发送顺序和消息处理逻辑出了问题,咱们一步步来修复:
问题根源拆解
先看看你原来代码里的几个核心问题:
- 消息顺序搞反了:你先发送了订阅请求,再发授权消息,导致订阅的会话是未认证状态,Deribit对未认证会话的推送限制很多,要么只推一次,要么推送内容不符合预期。
- 硬编码接收次数:你用了固定的
await websocket.recv()来获取初始价格,这种方式只适合单次API请求,完全不适合持续的订阅流。 - 消息类型没区分:循环里只处理“授权”相关的消息,完全忽略了订阅频道推送的实时价格数据,自然拿不到持续的last_price。
修复后的完整代码
下面是调整后的代码,我加了详细注释,你替换自己的测试API密钥就能用:
import asyncio import json import websockets async def deribit_ws_subscribe(): # 替换为你的Deribit测试账户API密钥和密钥 TEST_API_KEY = "你的测试API_KEY" TEST_API_SECRET = "你的测试API_SECRET" # 连接Deribit测试环境WebSocket async with websockets.connect('wss://testapp.deribit.com/ws/api/v2') as ws: # 第一步:先发送授权消息,确保会话已认证 auth_message = json.dumps({ "jsonrpc": "2.0", "id": 1, "method": "public/auth", "params": { "grant_type": "client_credentials", "client_id": TEST_API_KEY, "client_secret": TEST_API_SECRET } }) await ws.send(auth_message) auth_response = await ws.recv() print("授权结果:", json.loads(auth_response)) # 第二步:发送订阅请求,订阅BTC和ETH永续合约的ticker流 subscribe_message = json.dumps({ "jsonrpc": "2.0", "id": 2, "method": "public/subscribe", "params": { "channels": ["ticker.BTC-PERPETUAL.raw", "ticker.ETH-PERPETUAL.raw"] } }) await ws.send(subscribe_message) sub_response = await ws.recv() print("订阅确认:", json.loads(sub_response)) # 第三步:持续接收实时推送,提取last_price print("\n开始接收实时价格流...") btc_last_price = None eth_last_price = None while True: try: raw_message = await ws.recv() message_data = json.loads(raw_message) # 只处理订阅推送的消息(过滤掉授权、订阅确认等响应) if message_data.get("method") == "subscription": channel_name = message_data["params"]["channel"] ticker_data = message_data["params"]["data"] current_last_price = ticker_data["last_price"] # 区分BTC和ETH的价格 if "BTC-PERPETUAL" in channel_name: btc_last_price = current_last_price print(f"BTC最新价格: {btc_last_price}") elif "ETH-PERPETUAL" in channel_name: eth_last_price = current_last_price print(f"ETH最新价格: {eth_last_price}") # 当两个价格都获取到后,计算差价 if btc_last_price and eth_last_price: print(f"BTC-ETH差价: {btc_last_price - eth_last_price}\n") except websockets.exceptions.ConnectionClosed: print("WebSocket连接已关闭,程序终止") break if __name__ == "__main__": loop = asyncio.get_event_loop() try: loop.run_until_complete(deribit_ws_subscribe()) except KeyboardInterrupt: print("\n用户手动中断程序") finally: loop.close()
关键改动说明
- 调整消息顺序:先授权再订阅,确保Deribit把后续的实时推送给已认证的会话,这样就能持续获取价格流了。
- 动态处理消息:用无限循环持续接收WebSocket消息,并且只处理
method为subscription的推送消息,过滤掉其他类型的响应(比如授权结果、订阅确认)。 - 精准提取数据:根据订阅的频道名称区分BTC和ETH的价格,直接提取
last_price,还能顺便计算两者的差价。 - 移除冗余全局变量:改用局部变量存储价格,让代码逻辑更清晰,避免全局变量带来的意外问题。
为什么原来的代码失效?
- 未认证会话限制:Deribit的未认证WebSocket会话只会推送一次订阅数据,之后就停止了,所以你移除授权后只能拿到一次价格。
- 消息处理逻辑混乱:原代码的
recv()次数是硬编码的,后续循环只处理授权相关的消息,完全没处理订阅的实时推送,自然拿不到持续的last_price。
内容的提问来源于stack exchange,提问作者rctrading




