You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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消息,并且只处理methodsubscription的推送消息,过滤掉其他类型的响应(比如授权结果、订阅确认)。
  • 精准提取数据:根据订阅的频道名称区分BTC和ETH的价格,直接提取last_price,还能顺便计算两者的差价。
  • 移除冗余全局变量:改用局部变量存储价格,让代码逻辑更清晰,避免全局变量带来的意外问题。

为什么原来的代码失效?

  1. 未认证会话限制:Deribit的未认证WebSocket会话只会推送一次订阅数据,之后就停止了,所以你移除授权后只能拿到一次价格。
  2. 消息处理逻辑混乱:原代码的recv()次数是硬编码的,后续循环只处理授权相关的消息,完全没处理订阅的实时推送,自然拿不到持续的last_price。

内容的提问来源于stack exchange,提问作者rctrading

火山引擎 最新活动