StreamL4Book gRPC Method
请注意,此方法的计费是根据数据消耗量计算的,按 0.0165 MB = 10 个 API 积分 进行计费。
参数
硬币
字符串
正在加载...
退货
流
stream<L4BookUpdate>
正在加载...
snapshot
L4BookSnapshot
正在加载...
diff
L4BookDiff
正在加载...
请求
1// StreamL4Book Example - Stream individual order data via gRPC2包 main34import (5"上下文"6"encoding/json"7“flag”8"fmt"9"io"10“日志”11"数学"12“字符串”13“时间”1415"google.golang.grpc"16"google.golang.grpc"17"google.golang.grpc"18"google.golang.grpc"19"google.golang.grpc"2021pb "hyperliquid"22)2324const (25grpcEndpoint = "endpoint.mainnet.quiknode.pro:10000"26authToken = "您的认证令牌"27maxRetries = 1028baseDelay = 2 * time.秒29)3031func streamL4Orderbook(coin string, maxMessages int) error {32fmt.PrintlnPrintln字符串.重复("=", 60))33fmt.Printf("Streaming L4 Orderbook for %s\n", coin)34fmt.Println("自动重连:true")35fmt.PrintlnPrintln字符串.重复("=", 60) + "\n")3637retryCount := 038totalMsgCount := 03940for retryCount < maxRetries {41creds := 凭证.NewClientTLSFromCert(nil, "")42conn, err := grpc.Dial(grpcEndpoint,43grpc.WithTransportCredentials(creds),44grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)))45如果 err != nil {46返回 fmt.Errorf("连接失败:%w", err)47}4849client := pb.NewOrderBookStreamingClient(conn)50ctx := 元数据.AppendToOutgoingContext(context.背景(), “x-token”, authToken)5152request := &pb.L4BookRequest{53Coin: coin,54}5556if retryCount > 0 {57fmt.Printf("\n🔄 正在重新连接(尝试 %d/%d)...\n", retryCount+1, maxRetries)58} else {59fmt.Printf("正在连接到 %s...\n", grpcEndpoint)60}6162stream, err := client.StreamL4Book(ctx, request)63如果 err != nil {64conn.关闭()65返回 fmt.Errorf("启动流失败:%w", err)66}6768snapshotReceived := false69shouldRetry := false7071用于 {72更新, err := 流.Recv()73如果 err == io.EOF {74换行75}76如果 err != nil {77st, 好的 := 状态.FromError(err)78如果 好的 && st.代码() == 代码.DataLoss {79fmt.Printf("\n⚠️ 服务器已重新初始化:%s\n", st.消息())80retryCount++81if retryCount < maxRetries {82延迟 := baseDelay * time.Duration(数学.Pow(2, float64(重试次数-1)))83fmt.Printf("⏳ 等待 %v 后再重新连接……\n", 延迟)84时间.睡眠(延迟)85shouldRetry = true86换行87} else {88fmt.Printf("\n❌ 达到最大重试次数 (%d)。放弃。\n", maxRetries)89conn.关闭()90返回 nil91}92}93conn.关闭()94返回 fmt.Errorf("流错误:%w", err)95}9697totalMsgCount++9899if snapshot := update.GetSnapshot(); snapshot != nil {100snapshotReceived = true101retryCount = 0 // 成功后重置102103fmt.Println("\n✓ L4 Snapshot Received!")104fmt.Println(strings.Repeat("─", 60))105fmt.Printf("Coin: %s\n", snapshot.Coin)106fmt.Printf("Height: %d\n", snapshot.Height)107fmt.Printf("Time: %d\n", snapshot.Time)108fmt.Printf("Bids: %d orders\n", len(snapshot.Bids))109fmt.Printf("Asks: %d orders\n", len(snapshot.Asks))110fmt.Println(strings.Repeat("─", 60))111112// Sample bids113if len(snapshot.Bids) > 0 {114fmt.Println("\nSample Bids (first 5):")115bidCount := len(snapshot.Bids)116if bidCount > 5 {117bidCount = 5118}119for i := 0; i < bidCount; i++ {120order := snapshot.Bids[i]121userShort := order.User122if len(userShort) > 10 {123userShort = userShort[:10] + "..."124}125fmt.Printf(" OID: %d | Price: %s | Size: %s | User: %s\n",126order.Oid, order.LimitPx, order.Sz, userShort)127}128}129130// Sample asks131if len(snapshot.Asks) > 0 {132fmt.Println("\nSample Asks (first 5):")133askCount := len(snapshot.Asks)134if askCount > 5 {135askCount = 5136}137for i := 0; i < askCount; i++ {138order := snapshot.Asks[i]139userShort := order.User140if len(userShort) > 10 {141userShort = userShort[:10] + "..."142}143fmt.Printf(" OID: %d | Price: %s | Size: %s | User: %s\n",144order.Oid, order.LimitPx, order.Sz, userShort)145}146}147148} else if diff := update.GetDiff(); diff != nil {149if !snapshotReceived {150fmt.Println("\n⚠ Received diff before snapshot")151}152153var diffData map[string]interface{}154if err := json.Unmarshal([]byte(diff.Data), &diffData); err == nil {155orderStatuses := []interface{}{}156bookDiffs := []interface{}{}157158if os, ok := diffData["order_statuses"].([]interface{}); ok {159orderStatuses = os160}161if bd, ok := diffData["book_diffs"].([]interface{}); ok {162bookDiffs = bd163}164165fmt.Printf("\n[Block %d] L4 Diff:\n", diff.Height)166fmt.Printf(" Time: %d\n", diff.Time)167fmt.Printf(" Order Statuses: %d\n", len(orderStatuses))168fmt.Printf(" Book Diffs: %d\n", len(bookDiffs))169170if len(bookDiffs) > 0 && len(bookDiffs) <= 5 {171pretty, _ := json.MarshalIndent(bookDiffs, " ", " ")172fmt.Printf(" Diffs: %s\n", pretty)173}174}175}176177if maxMessages > 0 && totalMsgCount >= maxMessages {178fmt.Printf("\nReached max messages (%d), stopping...\n", maxMessages)179conn.关闭()180return nil181}182}183184conn.关闭()185186如果 !shouldRetry {187换行188}189}190191返回 nil192}193194func main() {195coin := 标志.字符串("coin", "BTC", "要直播的币种代码")196maxMessages := flag.Int("max-messages", 0, "Maximum messages (0 = unlimited)")197198flag.解析()199200fmt.Println("\n" + 字符串.重复("=", 60))201fmt.Println("Hyperliquid StreamL4Book Example")202fmt.Printf("Endpoint:%s\n", grpcEndpoint)203fmt.PrintlnPrintln字符串.重复("=", 60))204205if err := streamL4Orderbook(*coin, *maxMessages); err != nil {206log.致命(err)207}208}209
1// StreamL4Book Example - Stream individual order data via gRPC2包 main34import (5"上下文"6"encoding/json"7“flag”8"fmt"9"io"10“日志”11"数学"12“字符串”13“时间”1415"google.golang.grpc"16"google.golang.grpc"17"google.golang.grpc"18"google.golang.grpc"19"google.golang.grpc"2021pb "hyperliquid"22)2324const (25grpcEndpoint = "endpoint.mainnet.quiknode.pro:10000"26authToken = "您的认证令牌"27maxRetries = 1028baseDelay = 2 * time.秒29)3031func streamL4Orderbook(coin string, maxMessages int) error {32fmt.PrintlnPrintln字符串.重复("=", 60))33fmt.Printf("Streaming L4 Orderbook for %s\n", coin)34fmt.Println("自动重连:true")35fmt.PrintlnPrintln字符串.重复("=", 60) + "\n")3637retryCount := 038totalMsgCount := 03940for retryCount < maxRetries {41creds := 凭证.NewClientTLSFromCert(nil, "")42conn, err := grpc.Dial(grpcEndpoint,43grpc.WithTransportCredentials(creds),44grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)))45如果 err != nil {46返回 fmt.Errorf("连接失败:%w", err)47}4849client := pb.NewOrderBookStreamingClient(conn)50ctx := 元数据.AppendToOutgoingContext(context.背景(), “x-token”, authToken)5152request := &pb.L4BookRequest{53Coin: coin,54}5556if retryCount > 0 {57fmt.Printf("\n🔄 正在重新连接(尝试 %d/%d)...\n", retryCount+1, maxRetries)58} else {59fmt.Printf("正在连接到 %s...\n", grpcEndpoint)60}6162stream, err := client.StreamL4Book(ctx, request)63如果 err != nil {64conn.关闭()65返回 fmt.Errorf("启动流失败:%w", err)66}6768snapshotReceived := false69shouldRetry := false7071用于 {72更新, err := 流.Recv()73如果 err == io.EOF {74换行75}76如果 err != nil {77st, 好的 := 状态.FromError(err)78如果 好的 && st.代码() == 代码.DataLoss {79fmt.Printf("\n⚠️ 服务器已重新初始化:%s\n", st.消息())80retryCount++81if retryCount < maxRetries {82延迟 := baseDelay * time.Duration(数学.Pow(2, float64(重试次数-1)))83fmt.Printf("⏳ 等待 %v 后再重新连接……\n", 延迟)84时间.睡眠(延迟)85shouldRetry = true86换行87} else {88fmt.Printf("\n❌ 达到最大重试次数 (%d)。放弃。\n", maxRetries)89conn.关闭()90返回 nil91}92}93conn.关闭()94返回 fmt.Errorf("流错误:%w", err)95}9697totalMsgCount++9899if snapshot := update.GetSnapshot(); snapshot != nil {100snapshotReceived = true101retryCount = 0 // 成功后重置102103fmt.Println("\n✓ L4 Snapshot Received!")104fmt.Println(strings.Repeat("─", 60))105fmt.Printf("Coin: %s\n", snapshot.Coin)106fmt.Printf("Height: %d\n", snapshot.Height)107fmt.Printf("Time: %d\n", snapshot.Time)108fmt.Printf("Bids: %d orders\n", len(snapshot.Bids))109fmt.Printf("Asks: %d orders\n", len(snapshot.Asks))110fmt.Println(strings.Repeat("─", 60))111112// Sample bids113if len(snapshot.Bids) > 0 {114fmt.Println("\nSample Bids (first 5):")115bidCount := len(snapshot.Bids)116if bidCount > 5 {117bidCount = 5118}119for i := 0; i < bidCount; i++ {120order := snapshot.Bids[i]121userShort := order.User122if len(userShort) > 10 {123userShort = userShort[:10] + "..."124}125fmt.Printf(" OID: %d | Price: %s | Size: %s | User: %s\n",126order.Oid, order.LimitPx, order.Sz, userShort)127}128}129130// Sample asks131if len(snapshot.Asks) > 0 {132fmt.Println("\nSample Asks (first 5):")133askCount := len(snapshot.Asks)134if askCount > 5 {135askCount = 5136}137for i := 0; i < askCount; i++ {138order := snapshot.Asks[i]139userShort := order.User140if len(userShort) > 10 {141userShort = userShort[:10] + "..."142}143fmt.Printf(" OID: %d | Price: %s | Size: %s | User: %s\n",144order.Oid, order.LimitPx, order.Sz, userShort)145}146}147148} else if diff := update.GetDiff(); diff != nil {149if !snapshotReceived {150fmt.Println("\n⚠ Received diff before snapshot")151}152153var diffData map[string]interface{}154if err := json.Unmarshal([]byte(diff.Data), &diffData); err == nil {155orderStatuses := []interface{}{}156bookDiffs := []interface{}{}157158if os, ok := diffData["order_statuses"].([]interface{}); ok {159orderStatuses = os160}161if bd, ok := diffData["book_diffs"].([]interface{}); ok {162bookDiffs = bd163}164165fmt.Printf("\n[Block %d] L4 Diff:\n", diff.Height)166fmt.Printf(" Time: %d\n", diff.Time)167fmt.Printf(" Order Statuses: %d\n", len(orderStatuses))168fmt.Printf(" Book Diffs: %d\n", len(bookDiffs))169170if len(bookDiffs) > 0 && len(bookDiffs) <= 5 {171pretty, _ := json.MarshalIndent(bookDiffs, " ", " ")172fmt.Printf(" Diffs: %s\n", pretty)173}174}175}176177if maxMessages > 0 && totalMsgCount >= maxMessages {178fmt.Printf("\nReached max messages (%d), stopping...\n", maxMessages)179conn.关闭()180return nil181}182}183184conn.关闭()185186如果 !shouldRetry {187换行188}189}190191返回 nil192}193194func main() {195coin := 标志.字符串("coin", "BTC", "要直播的币种代码")196maxMessages := flag.Int("max-messages", 0, "Maximum messages (0 = unlimited)")197198flag.解析()199200fmt.Println("\n" + 字符串.重复("=", 60))201fmt.Println("Hyperliquid StreamL4Book Example")202fmt.Printf("Endpoint:%s\n", grpcEndpoint)203fmt.PrintlnPrintln字符串.重复("=", 60))204205if err := streamL4Orderbook(*coin, *maxMessages); err != nil {206log.致命(err)207}208}209
1// StreamL4Book Example - Stream individual order data 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 L4 (individual orders) orderbook28async function streamL4Orderbook(coin, maxMessages = null, autoReconnect = true, retryCount = 0) {29控制台.日志('='.重复(60));30console.log(`Streaming L4 Orderbook for ${coin}`);31console.log(`Auto-reconnect: ${autoReconnect}`);32控制台.日志('='.重复(60) + '\n');3334const maxRetries = 10;35const baseDelay = 2000;36let totalMsgCount = 0;3738while (retryCount < maxRetries) {39const 客户端 = createClient();40const 元数据 = new grpc.元数据();41元数据.添加('x-token', AUTH_TOKEN);4243const request = { coin: coin };4445试一试 {46如果 (retryCount > 0) {47console.log(`\n🔄 Reconnecting (attempt ${retryCount + 1}/${maxRetries})...`);48} else {49console.log(`Connecting to ${GRPC_ENDPOINT}...`);50}5152let snapshotReceived = false;53const call = client.StreamL4Book(request, metadata);5455call。在('data', (更新) => {56totalMsgCount++;5758if (update.snapshot) {59const snapshot = update.snapshot;60snapshotReceived = true;61retryCount = 0; // 成功后重置6263console.log('\n✓ L4 Snapshot Received!');64console.log('─'.repeat(60));65console.log(`Coin: ${snapshot.coin}`);66console.log(`Height: ${snapshot.height}`);67console.log(`Time: ${snapshot.time}`);68console.log(`Bids: ${snapshot.bids.length} orders`);69console.log(`Asks: ${snapshot.asks.length} orders`);70console.log('─'.repeat(60));7172// Sample bids73if (snapshot.bids.length > 0) {74console.log('\nSample Bids (first 5):');75snapshot.bids.slice(0, 5).forEach(order => {76console.log(` OID: ${order.oid} | Price: ${order.limit_px} | Size: ${order.sz} | User: ${order.user.substring(0, 10)}...`);77});78}7980// Sample asks81if (snapshot.asks.length > 0) {82console.log('\nSample Asks (first 5):');83snapshot.asks.slice(0, 5).forEach(order => {84console.log(` OID: ${order.oid} | Price: ${order.limit_px} | Size: ${order.sz} | User: ${order.user.substring(0, 10)}...`);85});86}8788} else if (update.diff) {89const diff = update.diff;9091if (!snapshotReceived) {92console.log('\n⚠ Received diff before snapshot');93}9495try {96const diffData = JSON.parse(diff.data);97const orderStatuses = diffData.order_statuses || [];98const bookDiffs = diffData.book_diffs || [];99100console.log(`\n[Block ${diff.height}] L4 Diff:`);101console.log(` Time: ${diff.time}`);102console.log(` Order Statuses: ${orderStatuses.length}`);103console.log(` Book Diffs: ${bookDiffs.length}`);104105if (bookDiffs.length > 0 && bookDiffs.length <= 5) {106console.log(` Diffs: ${JSON.stringify(bookDiffs, null, 2)}`);107}108} catch (e) {109console.log(` Error parsing diff: ${e.message}`);110}111}112113if (maxMessages && totalMsgCount >= maxMessages) {114console.log(`\nReached max messages (${maxMessages}), stopping...`);115call.cancel();116}117});118119call。在('error', (err) => {120如果 (err.代码 === grpc.状态.数据丢失 && 自动重连) {121console.log(`\n⚠️ Server reinitialized: ${err.message}`);122retryCount++;123if (retryCount < maxRetries) {124const 延迟 = baseDelay * Math.pow(2, retryCount - 1);125console.log(`⏳ Waiting ${delay / 1000}s before reconnecting...`);126setTimeout(() => streamL4Orderbook(coin, maxMessages, autoReconnect, retryCount), delay);127} else {128console.log(`\n❌ Max retries (${maxRetries}) reached. Giving up.`);129}130} else if (err.code !== grpc.status.CANCELLED) {131控制台.错误('\ngRPC 错误:', err.code, '-', err.message);132}133});134135call。在('end', () => {136控制台.日志('\n流已结束');137});138139// Wait for stream to complete140等待 new Promise((决心) => {141call。在('end', resolve);142call。在('error', resolve);143});144145换行; // 成功后退出重试循环146147} catch (err) {148控制台.错误('错误:', err.message);149换行;150}151}152}153154// Parse command line args155const args = process.argv.slice(2);156const 硬币 = args.find(a => a.startsWith('--coin='))?.split('=')[1] || 'BTC';157const maxMessages = parseInt(args.find(a => a.startsWith('--max-messages='))?.split('=')[1]) || null;158159控制台.日志('\n' + '='.重复(60));160console.log('Hyperliquid StreamL4Book Example');161console.log(`Endpoint: ${GRPC_ENDPOINT}`);162控制台.日志('='.重复(60));163164streamL4Orderbook(coin, maxMessages);165
1// StreamL4Book Example - Stream individual order data 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 L4 (individual orders) orderbook28async function streamL4Orderbook(coin, maxMessages = null, autoReconnect = true, retryCount = 0) {29控制台.日志('='.重复(60));30console.log(`Streaming L4 Orderbook for ${coin}`);31console.log(`Auto-reconnect: ${autoReconnect}`);32控制台.日志('='.重复(60) + '\n');3334const maxRetries = 10;35const baseDelay = 2000;36let totalMsgCount = 0;3738while (retryCount < maxRetries) {39const 客户端 = createClient();40const 元数据 = new grpc.元数据();41元数据.添加('x-token', AUTH_TOKEN);4243const request = { coin: coin };4445试一试 {46如果 (retryCount > 0) {47console.log(`\n🔄 Reconnecting (attempt ${retryCount + 1}/${maxRetries})...`);48} else {49console.log(`Connecting to ${GRPC_ENDPOINT}...`);50}5152let snapshotReceived = false;53const call = client.StreamL4Book(request, metadata);5455call。在('data', (更新) => {56totalMsgCount++;5758if (update.snapshot) {59const snapshot = update.snapshot;60snapshotReceived = true;61retryCount = 0; // 成功后重置6263console.log('\n✓ L4 Snapshot Received!');64console.log('─'.repeat(60));65console.log(`Coin: ${snapshot.coin}`);66console.log(`Height: ${snapshot.height}`);67console.log(`Time: ${snapshot.time}`);68console.log(`Bids: ${snapshot.bids.length} orders`);69console.log(`Asks: ${snapshot.asks.length} orders`);70console.log('─'.repeat(60));7172// Sample bids73if (snapshot.bids.length > 0) {74console.log('\nSample Bids (first 5):');75snapshot.bids.slice(0, 5).forEach(order => {76console.log(` OID: ${order.oid} | Price: ${order.limit_px} | Size: ${order.sz} | User: ${order.user.substring(0, 10)}...`);77});78}7980// Sample asks81if (snapshot.asks.length > 0) {82console.log('\nSample Asks (first 5):');83snapshot.asks.slice(0, 5).forEach(order => {84console.log(` OID: ${order.oid} | Price: ${order.limit_px} | Size: ${order.sz} | User: ${order.user.substring(0, 10)}...`);85});86}8788} else if (update.diff) {89const diff = update.diff;9091if (!snapshotReceived) {92console.log('\n⚠ Received diff before snapshot');93}9495try {96const diffData = JSON.parse(diff.data);97const orderStatuses = diffData.order_statuses || [];98const bookDiffs = diffData.book_diffs || [];99100console.log(`\n[Block ${diff.height}] L4 Diff:`);101console.log(` Time: ${diff.time}`);102console.log(` Order Statuses: ${orderStatuses.length}`);103console.log(` Book Diffs: ${bookDiffs.length}`);104105if (bookDiffs.length > 0 && bookDiffs.length <= 5) {106console.log(` Diffs: ${JSON.stringify(bookDiffs, null, 2)}`);107}108} catch (e) {109console.log(` Error parsing diff: ${e.message}`);110}111}112113if (maxMessages && totalMsgCount >= maxMessages) {114console.log(`\nReached max messages (${maxMessages}), stopping...`);115call.cancel();116}117});118119call。在('error', (err) => {120如果 (err.代码 === grpc.状态.数据丢失 && 自动重连) {121console.log(`\n⚠️ Server reinitialized: ${err.message}`);122retryCount++;123if (retryCount < maxRetries) {124const 延迟 = baseDelay * Math.pow(2, retryCount - 1);125console.log(`⏳ Waiting ${delay / 1000}s before reconnecting...`);126setTimeout(() => streamL4Orderbook(coin, maxMessages, autoReconnect, retryCount), delay);127} else {128console.log(`\n❌ Max retries (${maxRetries}) reached. Giving up.`);129}130} else if (err.code !== grpc.status.CANCELLED) {131控制台.错误('\ngRPC 错误:', err.code, '-', err.message);132}133});134135call。在('end', () => {136控制台.日志('\n流已结束');137});138139// Wait for stream to complete140等待 new Promise((决心) => {141call。在('end', resolve);142call。在('error', resolve);143});144145换行; // 成功后退出重试循环146147} catch (err) {148控制台.错误('错误:', err.message);149换行;150}151}152}153154// Parse command line args155const args = process.argv.slice(2);156const 硬币 = args.find(a => a.startsWith('--coin='))?.split('=')[1] || 'BTC';157const maxMessages = parseInt(args.find(a => a.startsWith('--max-messages='))?.split('=')[1]) || null;158159控制台.日志('\n' + '='.重复(60));160console.log('Hyperliquid StreamL4Book Example');161console.log(`Endpoint: ${GRPC_ENDPOINT}`);162控制台.日志('='.重复(60));163164streamL4Orderbook(coin, maxMessages);165
1#!/usr/bin/env python32"""3StreamL4Book Example - Stream individual order data via gRPC45设置:6pip install grpcio grpcio-tools protobuf zstandard7python -mgrpc.protoc -I../../proto --python_out=.grpc. ../../proto/orderbook.proto89用法:10python stream_l4_example.py --coin BTC --max-messages 10011"""1213import grpc14导入 json15import sys16import 时间17import argparse18来自 输入 import Optional1920试一试:21import orderbook_pb2 作为 pb22import orderbook_pb2_grpc 为 pb_grpc23except ImportError:24打印("错误:未生成 Proto 文件。请运行:")25打印(" python -mgrpc.protoc -I../../proto --python_out=.grpc. ../../proto/orderbook.proto")26sys.exit(1)2728# 配置29GRPC= "endpoint.mainnet.quiknode.pro:10000"30AUTH_TOKEN = "您的认证令牌"313233def stream_l4_orderbook(coin: str, max_messages: Optional[int] = None, auto_reconnect: bool = True):34"""35Stream L4 (individual orders) orderbook updates for a coin.3637参数:38币种:要直播的币种符号(例如,“BTC”、“ETH”)39max_messages: Maximum number of messages to receive (None for unlimited)40auto_reconnect:在发生 DATA_LOSS 错误时自动重新连接(默认值为 True)41"""42打印(f"\n{'='*60}")43print(f"Streaming L4 Orderbook for {coin}")44print(f"Auto-reconnect: {auto_reconnect}")45打印(f"{'='*60}\n")4647retry_count = 048max_retries = 1049base_delay = 250total_msg_count = 05152while retry_count < max_retries:53频道 = grpc.secure_channel(54GRPC,55grpc.ssl_channel_credentials(),56选项=[57(grpc.max_receive_message_length', 100 * 1024 * 1024),58(grpc.keepalive_time_ms', 30000),59]60)61占位符 = pb_grpc.订单流存根(channel)6263request = pb.L4BookRequest(coin=coin)6465msg_count = 066snapshot_received = False6768试一试:69如果 retry_count > 0:70打印(f"\n🔄 正在重新连接(尝试 {重试次数 + 1}/{最大重试次数})...")71else:72打印(f"正在连接到 {GRPC}...")7374for update in stub.StreamL4Book(request, metadata=[('x-token', AUTH_TOKEN)]):75msg_count += 176total_msg_count += 17778if update.HasField('snapshot'):79snapshot = update.snapshot80snapshot_received = True81retry_count = 0 # 连接成功后重置重试计数8283print(f"\n✓ L4 Snapshot Received!")84print(f"{'─'*60}")85print(f"Coin: {snapshot.coin}")86print(f"Height: {snapshot.height}")87print(f"Time: {snapshot.time}")88print(f"Bids: {len(snapshot.bids)} orders")89print(f"Asks: {len(snapshot.asks)} orders")90print(f"{'─'*60}")9192# Show sample of orders93if snapshot.bids:94print(f"\nSample Bids (first 5):")95for order in snapshot.bids[:5]:96print(f" OID: {order.oid} | Price: {order.limit_px} | Size: {order.sz} | User: {order.user[:10]}...")9798if snapshot.asks:99print(f"\nSample Asks (first 5):")100for order in snapshot.asks[:5]:101print(f" OID: {order.oid} | Price: {order.limit_px} | Size: {order.sz} | User: {order.user[:10]}...")102103elif update.HasField('diff'):104diff = update.diff105106if not snapshot_received:107print(f"\n⚠ Received diff before snapshot")108109# Parse the JSON diff data110try:111diff_data = json.loads(diff.data)112order_statuses = diff_data.get('order_statuses', [])113book_diffs = diff_data.get('book_diffs', [])114115print(f"\n[Block {diff.height}] L4 Diff:")116print(f" Time: {diff.time}")117print(f" Order Statuses: {len(order_statuses)}")118print(f" Book Diffs: {len(book_diffs)}")119120# Show sample diffs121if book_diffs and len(book_diffs) <= 5:122print(f" Diffs: {json.dumps(book_diffs, indent=4)}")123124except json.JSONDecodeError as e:125print(f" Error parsing diff data: {e}")126print(f" Raw data: {diff.data[:200]}...")127128if max_messages and total_msg_count >= max_messages:129print(f"\nReached max messages ({max_messages}), stopping...")130频道.关闭()131返回132133除了 grpc。RpcError 作为 e:134如果 e.代码() == grpc.状态码.DATA_LOSS 和 auto_reconnect:135print(f"\n⚠️ Server reinitialized: {e.details()}")136retry_count += 1137if retry_count < max_retries:138延迟 = base_delay * (2 ** (重试次数 - 1)) # 指数退避139打印(f"⏳ 正在等待 {延迟}秒后重新连接...")140时间.sleep(延迟)141频道.关闭()142继续143else:144打印(f"\n❌ 最大重试次数 ({max_retries}) 已达到。放弃。")145换行146else:147print(f"\ngRPC error: {e.code()} - {e.details()}")148换行149除了 KeyboardInterrupt:150print("\nStopping L4 stream...")151换行152最后:153频道.关闭()154155# 如果在此处未出现错误,则退出重试循环156换行157158159def main():160parser = argparse.ArgumentParser(description='Stream Hyperliquid L4 orderbook data via gRPC')161解析器.add_argument('--coin', 默认='BTC', 帮助='要直播的币种代码')162parser.add_argument('--max-messages', type=int, default=None, help='Maximum number of messages to receive')163164args = 解析器.parse_args()165166打印(f"\n{'='*60}")167print("Hyperliquid StreamL4Book Example")168print(f"Endpoint: {GRPC_ENDPOINT}")169打印(f"{'='*60}")170171试一试:172stream_l4_orderbook(args.coin, max_messages=args.max_messages)173除 异常 作为 e:174print(f"\nError: {e}")175import traceback176回溯.print_exc()177sys.exit(1)178179180如果 __name__ == "__main__":181主()182
1#!/usr/bin/env python32"""3StreamL4Book Example - Stream individual order data via gRPC45设置:6pip install grpcio grpcio-tools protobuf zstandard7python -mgrpc.protoc -I../../proto --python_out=.grpc. ../../proto/orderbook.proto89用法:10python stream_l4_example.py --coin BTC --max-messages 10011"""1213import grpc14导入 json15import sys16import 时间17import argparse18来自 输入 import Optional1920试一试:21import orderbook_pb2 作为 pb22import orderbook_pb2_grpc 为 pb_grpc23except ImportError:24打印("错误:未生成 Proto 文件。请运行:")25打印(" python -mgrpc.protoc -I../../proto --python_out=.grpc. ../../proto/orderbook.proto")26sys.exit(1)2728# 配置29GRPC= "endpoint.mainnet.quiknode.pro:10000"30AUTH_TOKEN = "您的认证令牌"313233def stream_l4_orderbook(coin: str, max_messages: Optional[int] = None, auto_reconnect: bool = True):34"""35Stream L4 (individual orders) orderbook updates for a coin.3637参数:38币种:要直播的币种符号(例如,“BTC”、“ETH”)39max_messages: Maximum number of messages to receive (None for unlimited)40auto_reconnect:在发生 DATA_LOSS 错误时自动重新连接(默认值为 True)41"""42打印(f"\n{'='*60}")43print(f"Streaming L4 Orderbook for {coin}")44print(f"Auto-reconnect: {auto_reconnect}")45打印(f"{'='*60}\n")4647retry_count = 048max_retries = 1049base_delay = 250total_msg_count = 05152while retry_count < max_retries:53频道 = grpc.secure_channel(54GRPC,55grpc.ssl_channel_credentials(),56选项=[57(grpc.max_receive_message_length', 100 * 1024 * 1024),58(grpc.keepalive_time_ms', 30000),59]60)61占位符 = pb_grpc.订单流存根(channel)6263request = pb.L4BookRequest(coin=coin)6465msg_count = 066snapshot_received = False6768试一试:69如果 retry_count > 0:70打印(f"\n🔄 正在重新连接(尝试 {重试次数 + 1}/{最大重试次数})...")71else:72打印(f"正在连接到 {GRPC}...")7374for update in stub.StreamL4Book(request, metadata=[('x-token', AUTH_TOKEN)]):75msg_count += 176total_msg_count += 17778if update.HasField('snapshot'):79snapshot = update.snapshot80snapshot_received = True81retry_count = 0 # 连接成功后重置重试计数8283print(f"\n✓ L4 Snapshot Received!")84print(f"{'─'*60}")85print(f"Coin: {snapshot.coin}")86print(f"Height: {snapshot.height}")87print(f"Time: {snapshot.time}")88print(f"Bids: {len(snapshot.bids)} orders")89print(f"Asks: {len(snapshot.asks)} orders")90print(f"{'─'*60}")9192# Show sample of orders93if snapshot.bids:94print(f"\nSample Bids (first 5):")95for order in snapshot.bids[:5]:96print(f" OID: {order.oid} | Price: {order.limit_px} | Size: {order.sz} | User: {order.user[:10]}...")9798if snapshot.asks:99print(f"\nSample Asks (first 5):")100for order in snapshot.asks[:5]:101print(f" OID: {order.oid} | Price: {order.limit_px} | Size: {order.sz} | User: {order.user[:10]}...")102103elif update.HasField('diff'):104diff = update.diff105106if not snapshot_received:107print(f"\n⚠ Received diff before snapshot")108109# Parse the JSON diff data110try:111diff_data = json.loads(diff.data)112order_statuses = diff_data.get('order_statuses', [])113book_diffs = diff_data.get('book_diffs', [])114115print(f"\n[Block {diff.height}] L4 Diff:")116print(f" Time: {diff.time}")117print(f" Order Statuses: {len(order_statuses)}")118print(f" Book Diffs: {len(book_diffs)}")119120# Show sample diffs121if book_diffs and len(book_diffs) <= 5:122print(f" Diffs: {json.dumps(book_diffs, indent=4)}")123124except json.JSONDecodeError as e:125print(f" Error parsing diff data: {e}")126print(f" Raw data: {diff.data[:200]}...")127128if max_messages and total_msg_count >= max_messages:129print(f"\nReached max messages ({max_messages}), stopping...")130频道.关闭()131返回132133除了 grpc。RpcError 作为 e:134如果 e.代码() == grpc.状态码.DATA_LOSS 和 auto_reconnect:135print(f"\n⚠️ Server reinitialized: {e.details()}")136retry_count += 1137if retry_count < max_retries:138延迟 = base_delay * (2 ** (重试次数 - 1)) # 指数退避139打印(f"⏳ 正在等待 {延迟}秒后重新连接...")140时间.sleep(延迟)141频道.关闭()142继续143else:144打印(f"\n❌ 最大重试次数 ({max_retries}) 已达到。放弃。")145换行146else:147print(f"\ngRPC error: {e.code()} - {e.details()}")148换行149除了 KeyboardInterrupt:150print("\nStopping L4 stream...")151换行152最后:153频道.关闭()154155# 如果在此处未出现错误,则退出重试循环156换行157158159def main():160parser = argparse.ArgumentParser(description='Stream Hyperliquid L4 orderbook data via gRPC')161解析器.add_argument('--coin', 默认='BTC', 帮助='要直播的币种代码')162parser.add_argument('--max-messages', type=int, default=None, help='Maximum number of messages to receive')163164args = 解析器.parse_args()165166打印(f"\n{'='*60}")167print("Hyperliquid StreamL4Book Example")168print(f"Endpoint: {GRPC_ENDPOINT}")169打印(f"{'='*60}")170171试一试:172stream_l4_orderbook(args.coin, max_messages=args.max_messages)173除 异常 作为 e:174print(f"\nError: {e}")175import traceback176回溯.print_exc()177sys.exit(1)178179180如果 __name__ == "__main__":181主()182