StreamBboBook gRPC Method
Please note that this method is metered based on data consumption at 0.00165 MB = 10 API credits.
参数
coins
repeated string
正在加载...
退货
流
stream<BboBookUpdate>
正在加载...
硬币
字符串
正在加载...
时间
uint64
正在加载...
区块号
uint64
正在加载...
bid
L2Level
正在加载...
ask
L2Level
正在加载...
请求
1// StreamBboBook Example - Stream top-of-book best bid/ask changes via gRPC2包 main34import (5"上下文"6“flag”7"fmt"8"io"9“日志”10"数学"11“字符串”12“时间”1314"google.golang.grpc"15"google.golang.grpc"16"google.golang.grpc"17"google.golang.grpc"18"google.golang.grpc"1920pb "hyperliquid"21)2223const (24grpcEndpoint = "endpoint.mainnet.quiknode.pro:10000"25authToken = "您的认证令牌"26maxRetries = 1027baseDelay = 2 * time.秒28)2930func streamBboBook(coins []string) error {31fmt.PrintlnPrintln字符串.重复("=", 60))32fmt.Printf("Streaming BBO Book for %s\n", strings.Join(coins, ", "))33fmt.Println("自动重连:true")34fmt.PrintlnPrintln字符串.重复("=", 60) + "\n")3536retryCount := 03738for retryCount < maxRetries {39creds := 凭证.NewClientTLSFromCert(nil, "")40conn, err := grpc.Dial(grpcEndpoint,41grpc.WithTransportCredentials(creds),42grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)))43如果 err != nil {44返回 fmt.Errorf("连接失败:%w", err)45}4647client := pb.NewOrderBookStreamingClient(conn)48ctx := 元数据.AppendToOutgoingContext(context.背景(), “x-token”, authToken)4950request := &pb.BboBookRequest{51Coins: coins,52}5354if retryCount > 0 {55fmt.Printf("\n🔄 正在重新连接(尝试 %d/%d)...\n", retryCount+1, maxRetries)56} else {57fmt.Printf("正在连接到 %s...\n", grpcEndpoint)58}5960stream, err := client.StreamBboBook(ctx, request)61如果 err != nil {62conn.关闭()63返回 fmt.Errorf("启动流失败:%w", err)64}6566msgCount := 067shouldRetry := false6869用于 {70更新, err := 流.Recv()71如果 err == io.EOF {72换行73}74如果 err != nil {75st, 好的 := 状态.FromError(err)76如果 好的 && st.代码() == 代码.DataLoss {77fmt.Printf("\n⚠️ 服务器已重新初始化:%s\n", st.消息())78retryCount++79if retryCount < maxRetries {80延迟 := baseDelay * time.Duration(数学.Pow(2, float64(重试次数-1)))81fmt.Printf("⏳ 等待 %v 后再重新连接……\n", 延迟)82时间.睡眠(延迟)83shouldRetry = true84换行85} else {86fmt.Printf("\n❌ 达到最大重试次数 (%d)。放弃。\n", maxRetries)87conn.关闭()88返回 nil89}90}91conn.关闭()92返回 fmt.Errorf("流错误:%w", err)93}9495msgCount++96如果 msgCount == 1 {97fmt.Println("✓ First BBO update received!\n")98retryCount = 0 // 成功后重置99}100101// Display BBO update102fmt.Println("\n" + 字符串.重复("─", 60))103fmt.Printf("方块:%d | 时间:%d | 金币:%s\n", update.区块号, 更新.Time, 更新.硬币)104fmt.PrintlnPrintln字符串.重复("─", 60))105106// Display best ask107if update.Ask != nil {108fmt.Printf(" BEST ASK: %12s | %12s | (%d orders)\n", update.Ask.Px, update.Ask.Sz, update.Ask.N)109} else {110fmt.Println(" BEST ASK: (none)")111}112113// Display best bid114if update.Bid != nil {115fmt.Printf(" BEST BID: %12s | %12s | (%d orders)\n", update.Bid.Px, update.Bid.Sz, update.Bid.N)116} else {117fmt.Println(" BEST BID: (none)")118}119120// Display spread121if update.Bid != nil && update.Ask != nil {122fmt.Printf(" SPREAD: (best bid: %s, best ask: %s)\n", update.Bid.Px, update.Ask.Px)123}124125fmt.Printf("\n 已接收消息:%d\n", msgCount)126}127128conn.关闭()129130如果 !shouldRetry {131换行132}133}134135返回 nil136}137138func main() {139coinsFlag := flag.String("coins", "BTC", "Comma-separated coin symbols to stream (e.g., BTC,ETH)")140141flag.解析()142143coins := strings.Split(*coinsFlag, ",")144145fmt.Println("\n" + 字符串.重复("=", 60))146fmt.Println("Hyperliquid StreamBboBook Example")147fmt.Printf("Endpoint:%s\n", grpcEndpoint)148fmt.PrintlnPrintln字符串.重复("=", 60))149150if err := streamBboBook(coins); err != nil {151log.致命(err)152}153}154
1// StreamBboBook Example - Stream top-of-book best bid/ask changes via gRPC2包 main34import (5"上下文"6“flag”7"fmt"8"io"9“日志”10"数学"11“字符串”12“时间”1314"google.golang.grpc"15"google.golang.grpc"16"google.golang.grpc"17"google.golang.grpc"18"google.golang.grpc"1920pb "hyperliquid"21)2223const (24grpcEndpoint = "endpoint.mainnet.quiknode.pro:10000"25authToken = "您的认证令牌"26maxRetries = 1027baseDelay = 2 * time.秒28)2930func streamBboBook(coins []string) error {31fmt.PrintlnPrintln字符串.重复("=", 60))32fmt.Printf("Streaming BBO Book for %s\n", strings.Join(coins, ", "))33fmt.Println("自动重连:true")34fmt.PrintlnPrintln字符串.重复("=", 60) + "\n")3536retryCount := 03738for retryCount < maxRetries {39creds := 凭证.NewClientTLSFromCert(nil, "")40conn, err := grpc.Dial(grpcEndpoint,41grpc.WithTransportCredentials(creds),42grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)))43如果 err != nil {44返回 fmt.Errorf("连接失败:%w", err)45}4647client := pb.NewOrderBookStreamingClient(conn)48ctx := 元数据.AppendToOutgoingContext(context.背景(), “x-token”, authToken)4950request := &pb.BboBookRequest{51Coins: coins,52}5354if retryCount > 0 {55fmt.Printf("\n🔄 正在重新连接(尝试 %d/%d)...\n", retryCount+1, maxRetries)56} else {57fmt.Printf("正在连接到 %s...\n", grpcEndpoint)58}5960stream, err := client.StreamBboBook(ctx, request)61如果 err != nil {62conn.关闭()63返回 fmt.Errorf("启动流失败:%w", err)64}6566msgCount := 067shouldRetry := false6869用于 {70更新, err := 流.Recv()71如果 err == io.EOF {72换行73}74如果 err != nil {75st, 好的 := 状态.FromError(err)76如果 好的 && st.代码() == 代码.DataLoss {77fmt.Printf("\n⚠️ 服务器已重新初始化:%s\n", st.消息())78retryCount++79if retryCount < maxRetries {80延迟 := baseDelay * time.Duration(数学.Pow(2, float64(重试次数-1)))81fmt.Printf("⏳ 等待 %v 后再重新连接……\n", 延迟)82时间.睡眠(延迟)83shouldRetry = true84换行85} else {86fmt.Printf("\n❌ 达到最大重试次数 (%d)。放弃。\n", maxRetries)87conn.关闭()88返回 nil89}90}91conn.关闭()92返回 fmt.Errorf("流错误:%w", err)93}9495msgCount++96如果 msgCount == 1 {97fmt.Println("✓ First BBO update received!\n")98retryCount = 0 // 成功后重置99}100101// Display BBO update102fmt.Println("\n" + 字符串.重复("─", 60))103fmt.Printf("方块:%d | 时间:%d | 金币:%s\n", update.区块号, 更新.Time, 更新.硬币)104fmt.PrintlnPrintln字符串.重复("─", 60))105106// Display best ask107if update.Ask != nil {108fmt.Printf(" BEST ASK: %12s | %12s | (%d orders)\n", update.Ask.Px, update.Ask.Sz, update.Ask.N)109} else {110fmt.Println(" BEST ASK: (none)")111}112113// Display best bid114if update.Bid != nil {115fmt.Printf(" BEST BID: %12s | %12s | (%d orders)\n", update.Bid.Px, update.Bid.Sz, update.Bid.N)116} else {117fmt.Println(" BEST BID: (none)")118}119120// Display spread121if update.Bid != nil && update.Ask != nil {122fmt.Printf(" SPREAD: (best bid: %s, best ask: %s)\n", update.Bid.Px, update.Ask.Px)123}124125fmt.Printf("\n 已接收消息:%d\n", msgCount)126}127128conn.关闭()129130如果 !shouldRetry {131换行132}133}134135返回 nil136}137138func main() {139coinsFlag := flag.String("coins", "BTC", "Comma-separated coin symbols to stream (e.g., BTC,ETH)")140141flag.解析()142143coins := strings.Split(*coinsFlag, ",")144145fmt.Println("\n" + 字符串.重复("=", 60))146fmt.Println("Hyperliquid StreamBboBook Example")147fmt.Printf("Endpoint:%s\n", grpcEndpoint)148fmt.PrintlnPrintln字符串.重复("=", 60))149150if err := streamBboBook(coins); err != nil {151log.致命(err)152}153}154
1// StreamBboBook Example - Stream top-of-book best bid/ask changes via gRPC2const grpc = require(grpc);3const protoLoader = require(grpc);4const 路径 = require('path');56const GRPC = endpoint.mainnet.quiknode.pro:10000';7const AUTH_TOKEN = '您的认证令牌';8const PROTO_PATH = 路径.join(__dirname, 'proto', 'orderbook.proto');910const 包定义 = protoLoader.loadSync(PROTO_PATH, {11keepCase: true,12多头: 字符串,13枚举: 字符串,14默认值: true,15oneofs: true16});17const proto = grpc.loadPackageDefinition(packageDefinition).hyperliquid;1819函数 createClient() {20返回 new proto.OrderBookStreaming(21GRPC,22grpc.凭据.createSsl(),23{ 'grpc.max_receive_message_length': 100 * 1024 * 1024 }24);25}2627// Stream best bid/offer updates28async function streamBboBook(coins, autoReconnect = true, retryCount = 0) {29控制台.日志('='.重复(60));30console.log(`Streaming BBO Book for ${coins.length > 0 ? coins.join(', ') : 'all coins'}`);31console.log(`Auto-reconnect: ${autoReconnect}`);32控制台.日志('='.重复(60) + '\n');3334const maxRetries = 10;35const baseDelay = 2000;3637while (retryCount < maxRetries) {38const 客户端 = createClient();39const 元数据 = new grpc.元数据();40元数据.添加('x-token', AUTH_TOKEN);4142const 请求 = {43coins: coins44};4546试一试 {47如果 (retryCount > 0) {48console.log(`\n🔄 Reconnecting (attempt ${retryCount + 1}/${maxRetries})...`);49} else {50console.log(`Connecting to ${GRPC_ENDPOINT}...`);51}5253let msgCount = 0;54const call = client.StreamBboBook(request, metadata);5556call。在('data', (更新) => {57msgCount++;5859如果 (msgCount === 1) {60console.log('✓ First BBO update received!\n');61retryCount = 0; // 成功后重置62}6364控制台.日志('\n' + '─'.重复(60));65console.log(`Block: ${update.block_number} | Time: ${update.time} | Coin: ${update.coin}`);66控制台.日志('─'.重复(60));6768// Display best ask69if (update.ask) {70console.log(` BEST ASK: ${update.ask.px.padStart(12)} | ${update.ask.sz.padStart(12)} | (${update.ask.n} orders)`);71} else {72console.log(' BEST ASK: (none)');73}7475// Display best bid76if (update.bid) {77console.log(` BEST BID: ${update.bid.px.padStart(12)} | ${update.bid.sz.padStart(12)} | (${update.bid.n} orders)`);78} else {79console.log(' BEST BID: (none)');80}8182// Display spread83if (update.bid && update.ask) {84const bestBid = parseFloat(update.bid.px);85const bestAsk = parseFloat(update.ask.px);86const spread = bestAsk - 最佳买价;87const spreadBps = (spread / bestBid) * 10000;88console.log(` SPREAD: ${spread.toFixed(2)} (${spreadBps.toFixed(2)} bps)`);89}9091console.log(`\n Messages received: ${msgCount}`);92});9394call。在('error', (err) => {95如果 (err.代码 === grpc.状态.数据丢失 && 自动重连) {96console.log(`\n⚠️ Server reinitialized: ${err.message}`);97retryCount++;98if (retryCount < maxRetries) {99const 延迟 = baseDelay * Math.pow(2, retryCount - 1);100console.log(`⏳ Waiting ${delay / 1000}s before reconnecting...`);101setTimeout(() => streamBboBook(coins, autoReconnect, retryCount), delay);102} else {103console.log(`\n❌ Max retries (${maxRetries}) reached. Giving up.`);104}105} else {106控制台.错误('\ngRPC 错误:', err.code, '-', err.message);107}108});109110call。在('end', () => {111控制台.日志('\n流已结束');112});113114// Wait for stream to complete115等待 new Promise((决心) => {116call。在('end', resolve);117call。在('error', resolve);118});119120换行; // 成功后退出重试循环121122} catch (err) {123控制台.错误('错误:', err.message);124换行;125}126}127}128129// Parse command line args130const args = process.argv.slice(2);131const coins = (args.find(a => a.startsWith('--coins='))?.split('=')[1] || 'BTC').split(',');132133控制台.日志('\n' + '='.重复(60));134console.log('Hyperliquid StreamBboBook Example');135console.log(`Endpoint: ${GRPC_ENDPOINT}`);136控制台.日志('='.重复(60));137138streamBboBook(coins);139
1// StreamBboBook Example - Stream top-of-book best bid/ask changes via gRPC2const grpc = require(grpc);3const protoLoader = require(grpc);4const 路径 = require('path');56const GRPC = endpoint.mainnet.quiknode.pro:10000';7const AUTH_TOKEN = '您的认证令牌';8const PROTO_PATH = 路径.join(__dirname, 'proto', 'orderbook.proto');910const 包定义 = protoLoader.loadSync(PROTO_PATH, {11keepCase: true,12多头: 字符串,13枚举: 字符串,14默认值: true,15oneofs: true16});17const proto = grpc.loadPackageDefinition(packageDefinition).hyperliquid;1819函数 createClient() {20返回 new proto.OrderBookStreaming(21GRPC,22grpc.凭据.createSsl(),23{ 'grpc.max_receive_message_length': 100 * 1024 * 1024 }24);25}2627// Stream best bid/offer updates28async function streamBboBook(coins, autoReconnect = true, retryCount = 0) {29控制台.日志('='.重复(60));30console.log(`Streaming BBO Book for ${coins.length > 0 ? coins.join(', ') : 'all coins'}`);31console.log(`Auto-reconnect: ${autoReconnect}`);32控制台.日志('='.重复(60) + '\n');3334const maxRetries = 10;35const baseDelay = 2000;3637while (retryCount < maxRetries) {38const 客户端 = createClient();39const 元数据 = new grpc.元数据();40元数据.添加('x-token', AUTH_TOKEN);4142const 请求 = {43coins: coins44};4546试一试 {47如果 (retryCount > 0) {48console.log(`\n🔄 Reconnecting (attempt ${retryCount + 1}/${maxRetries})...`);49} else {50console.log(`Connecting to ${GRPC_ENDPOINT}...`);51}5253let msgCount = 0;54const call = client.StreamBboBook(request, metadata);5556call。在('data', (更新) => {57msgCount++;5859如果 (msgCount === 1) {60console.log('✓ First BBO update received!\n');61retryCount = 0; // 成功后重置62}6364控制台.日志('\n' + '─'.重复(60));65console.log(`Block: ${update.block_number} | Time: ${update.time} | Coin: ${update.coin}`);66控制台.日志('─'.重复(60));6768// Display best ask69if (update.ask) {70console.log(` BEST ASK: ${update.ask.px.padStart(12)} | ${update.ask.sz.padStart(12)} | (${update.ask.n} orders)`);71} else {72console.log(' BEST ASK: (none)');73}7475// Display best bid76if (update.bid) {77console.log(` BEST BID: ${update.bid.px.padStart(12)} | ${update.bid.sz.padStart(12)} | (${update.bid.n} orders)`);78} else {79console.log(' BEST BID: (none)');80}8182// Display spread83if (update.bid && update.ask) {84const bestBid = parseFloat(update.bid.px);85const bestAsk = parseFloat(update.ask.px);86const spread = bestAsk - 最佳买价;87const spreadBps = (spread / bestBid) * 10000;88console.log(` SPREAD: ${spread.toFixed(2)} (${spreadBps.toFixed(2)} bps)`);89}9091console.log(`\n Messages received: ${msgCount}`);92});9394call。在('error', (err) => {95如果 (err.代码 === grpc.状态.数据丢失 && 自动重连) {96console.log(`\n⚠️ Server reinitialized: ${err.message}`);97retryCount++;98if (retryCount < maxRetries) {99const 延迟 = baseDelay * Math.pow(2, retryCount - 1);100console.log(`⏳ Waiting ${delay / 1000}s before reconnecting...`);101setTimeout(() => streamBboBook(coins, autoReconnect, retryCount), delay);102} else {103console.log(`\n❌ Max retries (${maxRetries}) reached. Giving up.`);104}105} else {106控制台.错误('\ngRPC 错误:', err.code, '-', err.message);107}108});109110call。在('end', () => {111控制台.日志('\n流已结束');112});113114// Wait for stream to complete115等待 new Promise((决心) => {116call。在('end', resolve);117call。在('error', resolve);118});119120换行; // 成功后退出重试循环121122} catch (err) {123控制台.错误('错误:', err.message);124换行;125}126}127}128129// Parse command line args130const args = process.argv.slice(2);131const coins = (args.find(a => a.startsWith('--coins='))?.split('=')[1] || 'BTC').split(',');132133控制台.日志('\n' + '='.重复(60));134console.log('Hyperliquid StreamBboBook Example');135console.log(`Endpoint: ${GRPC_ENDPOINT}`);136控制台.日志('='.重复(60));137138streamBboBook(coins);139
1#!/usr/bin/env python32"""3StreamBboBook Example - Stream top-of-book best bid/ask changes via gRPC45设置:6pip install grpcio grpcio-tools protobuf zstandard7python -mgrpc.protoc -I../../proto --python_out=.grpc. ../../proto/orderbook.proto89用法:10python stream_bbo_example.py --coins BTC,ETH11"""1213import grpc14import sys15import 时间16import argparse1718试一试:19import orderbook_pb2 作为 pb20import orderbook_pb2_grpc 为 pb_grpc21except ImportError:22打印("错误:未生成 Proto 文件。请运行:")23打印(" python -mgrpc.protoc -I../../proto --python_out=.grpc. ../../proto/orderbook.proto")24sys.exit(1)2526# 配置27GRPC= "endpoint.mainnet.quiknode.pro:10000"28AUTH_TOKEN = "您的认证令牌"293031def stream_bbo_book(coins: list, auto_reconnect: bool = True):32"""33Stream best bid/offer (top-of-book) updates for one or more coins.3435参数:36coins: Symbols to stream (e.g., ["BTC", "ETH"]). Empty list means all coins37auto_reconnect:在发生 DATA_LOSS 错误时自动重新连接(默认值为 True)38"""39打印(f"\n{'='*60}")40print(f"Streaming BBO Book for {', '.join(coins) if coins else 'all coins'}")41print(f"Auto-reconnect: {auto_reconnect}")42打印(f"{'='*60}\n")4344retry_count = 045max_retries = 1046base_delay = 24748while retry_count < max_retries:49频道 = grpc.secure_channel(50GRPC,51grpc.ssl_channel_credentials(),52选项=[53(grpc.max_receive_message_length', 100 * 1024 * 1024),54(grpc.keepalive_time_ms', 30000),55]56)57占位符 = pb_grpc.订单流存根(channel)5859# 构建请求60request = pb.BboBookRequest(coins=coins)6162msg_count = 06364试一试:65如果 retry_count > 0:66打印(f"\n🔄 正在重新连接(尝试 {重试次数 + 1}/{最大重试次数})...")67else:68打印(f"正在连接到 {GRPC}...")6970for update in stub.StreamBboBook(request, metadata=[('x-token', AUTH_TOKEN)]):71msg_count += 17273如果 msg_count == 1:74print(f"✓ First BBO update received!\n")75retry_count = 0 # 连接成功后重置重试计数7677# Display the BBO update78打印(f"\n{'─'*60}")79print(f"Block: {update.block_number} | Time: {update.time} | Coin: {update.coin}")80打印(f"{'─'*60}")8182# Show best ask83if update.HasField('ask'):84print(f" BEST ASK: {update.ask.px:>12} | {update.ask.sz:>12} | ({update.ask.n} orders)")85else:86print(" BEST ASK: (none)")8788# Show best bid89if update.HasField('bid'):90print(f" BEST BID: {update.bid.px:>12} | {update.bid.sz:>12} | ({update.bid.n} orders)")91else:92print(" BEST BID: (none)")9394# 显示点差95if update.HasField('bid') and update.HasField('ask'):96best_bid = float(update.bid.px)97best_ask = float(update.ask.px)98spread = best_ask - best_bid99spread_bps = (spread / best_bid) * 10000 if best_bid > 0 else 0100print(f" SPREAD: {spread:.2f} ({spread_bps:.2f} bps)")101102print(f"\n Messages received: {msg_count}")103104除了 grpc。RpcError 作为 e:105如果 e.代码() == grpc.状态码.DATA_LOSS 和 auto_reconnect:106print(f"\n⚠️ Server reinitialized: {e.details()}")107retry_count += 1108if retry_count < max_retries:109延迟 = base_delay * (2 ** (重试次数 - 1)) # 指数退避110打印(f"⏳ 正在等待 {延迟}秒后重新连接...")111时间.sleep(延迟)112频道.关闭()113继续114else:115打印(f"\n❌ 最大重试次数 ({max_retries}) 已达到。放弃。")116换行117else:118print(f"\ngRPC error: {e.code()} - {e.details()}")119换行120除了 KeyboardInterrupt:121print("\nStopping BBO stream...")122换行123最后:124频道.关闭()125126# 如果在此处未出现错误,则退出重试循环127换行128129130def main():131parser = argparse.ArgumentParser(description='Stream Hyperliquid best bid/offer data via gRPC')132parser.add_argument('--coins', default='BTC', help='Comma-separated coin symbols to stream (e.g., BTC,ETH)')133134args = 解析器.parse_args()135coins = [c.strip() for c in args.coins.split(',') if c.strip()]136137打印(f"\n{'='*60}")138print("Hyperliquid StreamBboBook Example")139print(f"Endpoint: {GRPC_ENDPOINT}")140打印(f"{'='*60}")141142试一试:143stream_bbo_book(coins)144除 异常 作为 e:145print(f"\nError: {e}")146import traceback147回溯.print_exc()148sys.exit(1)149150151如果 __name__ == "__main__":152主()153
1#!/usr/bin/env python32"""3StreamBboBook Example - Stream top-of-book best bid/ask changes via gRPC45设置:6pip install grpcio grpcio-tools protobuf zstandard7python -mgrpc.protoc -I../../proto --python_out=.grpc. ../../proto/orderbook.proto89用法:10python stream_bbo_example.py --coins BTC,ETH11"""1213import grpc14import sys15import 时间16import argparse1718试一试:19import orderbook_pb2 作为 pb20import orderbook_pb2_grpc 为 pb_grpc21except ImportError:22打印("错误:未生成 Proto 文件。请运行:")23打印(" python -mgrpc.protoc -I../../proto --python_out=.grpc. ../../proto/orderbook.proto")24sys.exit(1)2526# 配置27GRPC= "endpoint.mainnet.quiknode.pro:10000"28AUTH_TOKEN = "您的认证令牌"293031def stream_bbo_book(coins: list, auto_reconnect: bool = True):32"""33Stream best bid/offer (top-of-book) updates for one or more coins.3435参数:36coins: Symbols to stream (e.g., ["BTC", "ETH"]). Empty list means all coins37auto_reconnect:在发生 DATA_LOSS 错误时自动重新连接(默认值为 True)38"""39打印(f"\n{'='*60}")40print(f"Streaming BBO Book for {', '.join(coins) if coins else 'all coins'}")41print(f"Auto-reconnect: {auto_reconnect}")42打印(f"{'='*60}\n")4344retry_count = 045max_retries = 1046base_delay = 24748while retry_count < max_retries:49频道 = grpc.secure_channel(50GRPC,51grpc.ssl_channel_credentials(),52选项=[53(grpc.max_receive_message_length', 100 * 1024 * 1024),54(grpc.keepalive_time_ms', 30000),55]56)57占位符 = pb_grpc.订单流存根(channel)5859# 构建请求60request = pb.BboBookRequest(coins=coins)6162msg_count = 06364试一试:65如果 retry_count > 0:66打印(f"\n🔄 正在重新连接(尝试 {重试次数 + 1}/{最大重试次数})...")67else:68打印(f"正在连接到 {GRPC}...")6970for update in stub.StreamBboBook(request, metadata=[('x-token', AUTH_TOKEN)]):71msg_count += 17273如果 msg_count == 1:74print(f"✓ First BBO update received!\n")75retry_count = 0 # 连接成功后重置重试计数7677# Display the BBO update78打印(f"\n{'─'*60}")79print(f"Block: {update.block_number} | Time: {update.time} | Coin: {update.coin}")80打印(f"{'─'*60}")8182# Show best ask83if update.HasField('ask'):84print(f" BEST ASK: {update.ask.px:>12} | {update.ask.sz:>12} | ({update.ask.n} orders)")85else:86print(" BEST ASK: (none)")8788# Show best bid89if update.HasField('bid'):90print(f" BEST BID: {update.bid.px:>12} | {update.bid.sz:>12} | ({update.bid.n} orders)")91else:92print(" BEST BID: (none)")9394# 显示点差95if update.HasField('bid') and update.HasField('ask'):96best_bid = float(update.bid.px)97best_ask = float(update.ask.px)98spread = best_ask - best_bid99spread_bps = (spread / best_bid) * 10000 if best_bid > 0 else 0100print(f" SPREAD: {spread:.2f} ({spread_bps:.2f} bps)")101102print(f"\n Messages received: {msg_count}")103104除了 grpc。RpcError 作为 e:105如果 e.代码() == grpc.状态码.DATA_LOSS 和 auto_reconnect:106print(f"\n⚠️ Server reinitialized: {e.details()}")107retry_count += 1108if retry_count < max_retries:109延迟 = base_delay * (2 ** (重试次数 - 1)) # 指数退避110打印(f"⏳ 正在等待 {延迟}秒后重新连接...")111时间.sleep(延迟)112频道.关闭()113继续114else:115打印(f"\n❌ 最大重试次数 ({max_retries}) 已达到。放弃。")116换行117else:118print(f"\ngRPC error: {e.code()} - {e.details()}")119换行120除了 KeyboardInterrupt:121print("\nStopping BBO stream...")122换行123最后:124频道.关闭()125126# 如果在此处未出现错误,则退出重试循环127换行128129130def main():131parser = argparse.ArgumentParser(description='Stream Hyperliquid best bid/offer data via gRPC')132parser.add_argument('--coins', default='BTC', help='Comma-separated coin symbols to stream (e.g., BTC,ETH)')133134args = 解析器.parse_args()135coins = [c.strip() for c in args.coins.split(',') if c.strip()]136137打印(f"\n{'='*60}")138print("Hyperliquid StreamBboBook Example")139print(f"Endpoint: {GRPC_ENDPOINT}")140打印(f"{'='*60}")141142试一试:143stream_bbo_book(coins)144除 异常 作为 e:145print(f"\nError: {e}")146import traceback147回溯.print_exc()148sys.exit(1)149150151如果 __name__ == "__main__":152主()153