Full reference
Field definitions, proto messages, example updates, and comparisons for this stream live on the BBO Book dataset page. This page covers the method signature and client snippets.
Please note that this method is metered based on data consumption at 0.00165 MB = 10 API credits.
Parameters
- coinsrepeated string
List of symbols to subscribe to (e.g., 'BTC', 'ETH'). Empty means all coins
Returns
- streamstream<BboBookUpdate>
Stream of BboBookUpdate messages, one per coin whose best bid or ask changed
- coinstring
Trading pair symbol
- timeuint64
Block timestamp in milliseconds
- block_numberuint64
Block number
- bidL2Level
Best bid level containing px (price), sz (total size), and n (order count). Absent if there is no resting bid
- askL2Level
Best ask level containing px (price), sz (total size), and n (order count). Absent if there is no resting ask
Request
1// StreamBboBook Example - Stream top-of-book best bid/ask changes via gRPC2package main34import (5"context"6"flag"7"fmt"8"io"9"log"10"math"11"strings"12"time"1314"google.golang.org/grpc"15"google.golang.org/grpc/codes"16"google.golang.org/grpc/credentials"17"google.golang.org/grpc/metadata"18"google.golang.org/grpc/status"1920pb "hyperliquid-orderbook-example/proto"21)2223const (24grpcEndpoint = "your-endpoint.hype-mainnet.quiknode.pro:10000"25authToken = "your-auth-token"26maxRetries = 1027baseDelay = 2 * time.Second28)2930func streamBboBook(coins []string) error {31fmt.Println(strings.Repeat("=", 60))32fmt.Printf("Streaming BBO Book for %s\n", strings.Join(coins, ", "))33fmt.Println("Auto-reconnect: true")34fmt.Println(strings.Repeat("=", 60) + "\n")3536retryCount := 03738for retryCount < maxRetries {39creds := credentials.NewClientTLSFromCert(nil, "")40conn, err := grpc.Dial(grpcEndpoint,41grpc.WithTransportCredentials(creds),42grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)))43if err != nil {44return fmt.Errorf("failed to connect: %w", err)45}4647client := pb.NewOrderBookStreamingClient(conn)48ctx := metadata.AppendToOutgoingContext(context.Background(), "x-token", authToken)4950request := &pb.BboBookRequest{51Coins: coins,52}5354if retryCount > 0 {55fmt.Printf("\nš Reconnecting (attempt %d/%d)...\n", retryCount+1, maxRetries)56} else {57fmt.Printf("Connecting to %s...\n", grpcEndpoint)58}5960stream, err := client.StreamBboBook(ctx, request)61if err != nil {62conn.Close()63return fmt.Errorf("failed to start stream: %w", err)64}6566msgCount := 067shouldRetry := false6869for {70update, err := stream.Recv()71if err == io.EOF {72break73}74if err != nil {75st, ok := status.FromError(err)76if ok && st.Code() == codes.DataLoss {77fmt.Printf("\nā ļø Server reinitialized: %s\n", st.Message())78retryCount++79if retryCount < maxRetries {80delay := baseDelay * time.Duration(math.Pow(2, float64(retryCount-1)))81fmt.Printf("ā³ Waiting %v before reconnecting...\n", delay)82time.Sleep(delay)83shouldRetry = true84break85} else {86fmt.Printf("\nā Max retries (%d) reached. Giving up.\n", maxRetries)87conn.Close()88return nil89}90}91conn.Close()92return fmt.Errorf("stream error: %w", err)93}9495msgCount++96if msgCount == 1 {97fmt.Println("ā First BBO update received!\n")98retryCount = 0 // Reset on success99}100101// Display BBO update102fmt.Println("\n" + strings.Repeat("ā", 60))103fmt.Printf("Block: %d | Time: %d | Coin: %s\n", update.BlockNumber, update.Time, update.Coin)104fmt.Println(strings.Repeat("ā", 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 Messages received: %d\n", msgCount)126}127128conn.Close()129130if !shouldRetry {131break132}133}134135return nil136}137138func main() {139coinsFlag := flag.String("coins", "BTC", "Comma-separated coin symbols to stream (e.g., BTC,ETH)")140141flag.Parse()142143coins := strings.Split(*coinsFlag, ",")144145fmt.Println("\n" + strings.Repeat("=", 60))146fmt.Println("Hyperliquid StreamBboBook Example")147fmt.Printf("Endpoint: %s\n", grpcEndpoint)148fmt.Println(strings.Repeat("=", 60))149150if err := streamBboBook(coins); err != nil {151log.Fatal(err)152}153}154
1// StreamBboBook Example - Stream top-of-book best bid/ask changes via gRPC2package main34import (5"context"6"flag"7"fmt"8"io"9"log"10"math"11"strings"12"time"1314"google.golang.org/grpc"15"google.golang.org/grpc/codes"16"google.golang.org/grpc/credentials"17"google.golang.org/grpc/metadata"18"google.golang.org/grpc/status"1920pb "hyperliquid-orderbook-example/proto"21)2223const (24grpcEndpoint = "your-endpoint.hype-mainnet.quiknode.pro:10000"25authToken = "your-auth-token"26maxRetries = 1027baseDelay = 2 * time.Second28)2930func streamBboBook(coins []string) error {31fmt.Println(strings.Repeat("=", 60))32fmt.Printf("Streaming BBO Book for %s\n", strings.Join(coins, ", "))33fmt.Println("Auto-reconnect: true")34fmt.Println(strings.Repeat("=", 60) + "\n")3536retryCount := 03738for retryCount < maxRetries {39creds := credentials.NewClientTLSFromCert(nil, "")40conn, err := grpc.Dial(grpcEndpoint,41grpc.WithTransportCredentials(creds),42grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)))43if err != nil {44return fmt.Errorf("failed to connect: %w", err)45}4647client := pb.NewOrderBookStreamingClient(conn)48ctx := metadata.AppendToOutgoingContext(context.Background(), "x-token", authToken)4950request := &pb.BboBookRequest{51Coins: coins,52}5354if retryCount > 0 {55fmt.Printf("\nš Reconnecting (attempt %d/%d)...\n", retryCount+1, maxRetries)56} else {57fmt.Printf("Connecting to %s...\n", grpcEndpoint)58}5960stream, err := client.StreamBboBook(ctx, request)61if err != nil {62conn.Close()63return fmt.Errorf("failed to start stream: %w", err)64}6566msgCount := 067shouldRetry := false6869for {70update, err := stream.Recv()71if err == io.EOF {72break73}74if err != nil {75st, ok := status.FromError(err)76if ok && st.Code() == codes.DataLoss {77fmt.Printf("\nā ļø Server reinitialized: %s\n", st.Message())78retryCount++79if retryCount < maxRetries {80delay := baseDelay * time.Duration(math.Pow(2, float64(retryCount-1)))81fmt.Printf("ā³ Waiting %v before reconnecting...\n", delay)82time.Sleep(delay)83shouldRetry = true84break85} else {86fmt.Printf("\nā Max retries (%d) reached. Giving up.\n", maxRetries)87conn.Close()88return nil89}90}91conn.Close()92return fmt.Errorf("stream error: %w", err)93}9495msgCount++96if msgCount == 1 {97fmt.Println("ā First BBO update received!\n")98retryCount = 0 // Reset on success99}100101// Display BBO update102fmt.Println("\n" + strings.Repeat("ā", 60))103fmt.Printf("Block: %d | Time: %d | Coin: %s\n", update.BlockNumber, update.Time, update.Coin)104fmt.Println(strings.Repeat("ā", 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 Messages received: %d\n", msgCount)126}127128conn.Close()129130if !shouldRetry {131break132}133}134135return nil136}137138func main() {139coinsFlag := flag.String("coins", "BTC", "Comma-separated coin symbols to stream (e.g., BTC,ETH)")140141flag.Parse()142143coins := strings.Split(*coinsFlag, ",")144145fmt.Println("\n" + strings.Repeat("=", 60))146fmt.Println("Hyperliquid StreamBboBook Example")147fmt.Printf("Endpoint: %s\n", grpcEndpoint)148fmt.Println(strings.Repeat("=", 60))149150if err := streamBboBook(coins); err != nil {151log.Fatal(err)152}153}154
1// StreamBboBook Example - Stream top-of-book best bid/ask changes via gRPC2const grpc = require('@grpc/grpc-js');3const protoLoader = require('@grpc/proto-loader');4const path = require('path');56const GRPC_ENDPOINT = 'your-endpoint.hype-mainnet.quiknode.pro:10000';7const AUTH_TOKEN = 'your-auth-token';8const PROTO_PATH = path.join(__dirname, 'proto', 'orderbook.proto');910const packageDefinition = protoLoader.loadSync(PROTO_PATH, {11keepCase: true,12longs: String,13enums: String,14defaults: true,15oneofs: true16});17const proto = grpc.loadPackageDefinition(packageDefinition).hyperliquid;1819function createClient() {20return new proto.OrderBookStreaming(21GRPC_ENDPOINT,22grpc.credentials.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) {29console.log('='.repeat(60));30console.log(`Streaming BBO Book for ${coins.length > 0 ? coins.join(', ') : 'all coins'}`);31console.log(`Auto-reconnect: ${autoReconnect}`);32console.log('='.repeat(60) + '\n');3334const maxRetries = 10;35const baseDelay = 2000;3637while (retryCount < maxRetries) {38const client = createClient();39const metadata = new grpc.Metadata();40metadata.add('x-token', AUTH_TOKEN);4142const request = {43coins: coins44};4546try {47if (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.on('data', (update) => {57msgCount++;5859if (msgCount === 1) {60console.log('ā First BBO update received!\n');61retryCount = 0; // Reset on success62}6364console.log('\n' + 'ā'.repeat(60));65console.log(`Block: ${update.block_number} | Time: ${update.time} | Coin: ${update.coin}`);66console.log('ā'.repeat(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 - bestBid;87const spreadBps = (spread / bestBid) * 10000;88console.log(` SPREAD: ${spread.toFixed(2)} (${spreadBps.toFixed(2)} bps)`);89}9091console.log(`\n Messages received: ${msgCount}`);92});9394call.on('error', (err) => {95if (err.code === grpc.status.DATA_LOSS && autoReconnect) {96console.log(`\nā ļø Server reinitialized: ${err.message}`);97retryCount++;98if (retryCount < maxRetries) {99const delay = 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 {106console.error('\ngRPC error:', err.code, '-', err.message);107}108});109110call.on('end', () => {111console.log('\nStream ended');112});113114// Wait for stream to complete115await new Promise((resolve) => {116call.on('end', resolve);117call.on('error', resolve);118});119120break; // Exit retry loop on success121122} catch (err) {123console.error('Error:', err.message);124break;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(',');132133console.log('\n' + '='.repeat(60));134console.log('Hyperliquid StreamBboBook Example');135console.log(`Endpoint: ${GRPC_ENDPOINT}`);136console.log('='.repeat(60));137138streamBboBook(coins);139
1// StreamBboBook Example - Stream top-of-book best bid/ask changes via gRPC2const grpc = require('@grpc/grpc-js');3const protoLoader = require('@grpc/proto-loader');4const path = require('path');56const GRPC_ENDPOINT = 'your-endpoint.hype-mainnet.quiknode.pro:10000';7const AUTH_TOKEN = 'your-auth-token';8const PROTO_PATH = path.join(__dirname, 'proto', 'orderbook.proto');910const packageDefinition = protoLoader.loadSync(PROTO_PATH, {11keepCase: true,12longs: String,13enums: String,14defaults: true,15oneofs: true16});17const proto = grpc.loadPackageDefinition(packageDefinition).hyperliquid;1819function createClient() {20return new proto.OrderBookStreaming(21GRPC_ENDPOINT,22grpc.credentials.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) {29console.log('='.repeat(60));30console.log(`Streaming BBO Book for ${coins.length > 0 ? coins.join(', ') : 'all coins'}`);31console.log(`Auto-reconnect: ${autoReconnect}`);32console.log('='.repeat(60) + '\n');3334const maxRetries = 10;35const baseDelay = 2000;3637while (retryCount < maxRetries) {38const client = createClient();39const metadata = new grpc.Metadata();40metadata.add('x-token', AUTH_TOKEN);4142const request = {43coins: coins44};4546try {47if (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.on('data', (update) => {57msgCount++;5859if (msgCount === 1) {60console.log('ā First BBO update received!\n');61retryCount = 0; // Reset on success62}6364console.log('\n' + 'ā'.repeat(60));65console.log(`Block: ${update.block_number} | Time: ${update.time} | Coin: ${update.coin}`);66console.log('ā'.repeat(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 - bestBid;87const spreadBps = (spread / bestBid) * 10000;88console.log(` SPREAD: ${spread.toFixed(2)} (${spreadBps.toFixed(2)} bps)`);89}9091console.log(`\n Messages received: ${msgCount}`);92});9394call.on('error', (err) => {95if (err.code === grpc.status.DATA_LOSS && autoReconnect) {96console.log(`\nā ļø Server reinitialized: ${err.message}`);97retryCount++;98if (retryCount < maxRetries) {99const delay = 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 {106console.error('\ngRPC error:', err.code, '-', err.message);107}108});109110call.on('end', () => {111console.log('\nStream ended');112});113114// Wait for stream to complete115await new Promise((resolve) => {116call.on('end', resolve);117call.on('error', resolve);118});119120break; // Exit retry loop on success121122} catch (err) {123console.error('Error:', err.message);124break;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(',');132133console.log('\n' + '='.repeat(60));134console.log('Hyperliquid StreamBboBook Example');135console.log(`Endpoint: ${GRPC_ENDPOINT}`);136console.log('='.repeat(60));137138streamBboBook(coins);139
1#!/usr/bin/env python32"""3StreamBboBook Example - Stream top-of-book best bid/ask changes via gRPC45Setup:6pip install grpcio grpcio-tools protobuf zstandard7python -m grpc_tools.protoc -I../../proto --python_out=. --grpc_python_out=. ../../proto/orderbook.proto89Usage:10python stream_bbo_example.py --coins BTC,ETH11"""1213import grpc14import sys15import time16import argparse1718try:19import orderbook_pb2 as pb20import orderbook_pb2_grpc as pb_grpc21except ImportError:22print("Error: Proto files not generated. Run:")23print(" python -m grpc_tools.protoc -I../../proto --python_out=. --grpc_python_out=. ../../proto/orderbook.proto")24sys.exit(1)2526# Configuration27GRPC_ENDPOINT = "your-endpoint.hype-mainnet.quiknode.pro:10000"28AUTH_TOKEN = "your-auth-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.3435Args:36coins: Symbols to stream (e.g., ["BTC", "ETH"]). Empty list means all coins37auto_reconnect: Auto-reconnect on DATA_LOSS errors (default True)38"""39print(f"\n{'='*60}")40print(f"Streaming BBO Book for {', '.join(coins) if coins else 'all coins'}")41print(f"Auto-reconnect: {auto_reconnect}")42print(f"{'='*60}\n")4344retry_count = 045max_retries = 1046base_delay = 24748while retry_count < max_retries:49channel = grpc.secure_channel(50GRPC_ENDPOINT,51grpc.ssl_channel_credentials(),52options=[53('grpc.max_receive_message_length', 100 * 1024 * 1024),54('grpc.keepalive_time_ms', 30000),55]56)57stub = pb_grpc.OrderBookStreamingStub(channel)5859# Build request60request = pb.BboBookRequest(coins=coins)6162msg_count = 06364try:65if retry_count > 0:66print(f"\nš Reconnecting (attempt {retry_count + 1}/{max_retries})...")67else:68print(f"Connecting to {GRPC_ENDPOINT}...")6970for update in stub.StreamBboBook(request, metadata=[('x-token', AUTH_TOKEN)]):71msg_count += 17273if msg_count == 1:74print(f"ā First BBO update received!\n")75retry_count = 0 # Reset retry count on successful connection7677# Display the BBO update78print(f"\n{'ā'*60}")79print(f"Block: {update.block_number} | Time: {update.time} | Coin: {update.coin}")80print(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# Show spread95if 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}")103104except grpc.RpcError as e:105if e.code() == grpc.StatusCode.DATA_LOSS and auto_reconnect:106print(f"\nā ļø Server reinitialized: {e.details()}")107retry_count += 1108if retry_count < max_retries:109delay = base_delay * (2 ** (retry_count - 1)) # Exponential backoff110print(f"ā³ Waiting {delay}s before reconnecting...")111time.sleep(delay)112channel.close()113continue114else:115print(f"\nā Max retries ({max_retries}) reached. Giving up.")116break117else:118print(f"\ngRPC error: {e.code()} - {e.details()}")119break120except KeyboardInterrupt:121print("\nStopping BBO stream...")122break123finally:124channel.close()125126# If we get here without error, break the retry loop127break128129130def 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 = parser.parse_args()135coins = [c.strip() for c in args.coins.split(',') if c.strip()]136137print(f"\n{'='*60}")138print("Hyperliquid StreamBboBook Example")139print(f"Endpoint: {GRPC_ENDPOINT}")140print(f"{'='*60}")141142try:143stream_bbo_book(coins)144except Exception as e:145print(f"\nError: {e}")146import traceback147traceback.print_exc()148sys.exit(1)149150151if __name__ == "__main__":152main()153
1#!/usr/bin/env python32"""3StreamBboBook Example - Stream top-of-book best bid/ask changes via gRPC45Setup:6pip install grpcio grpcio-tools protobuf zstandard7python -m grpc_tools.protoc -I../../proto --python_out=. --grpc_python_out=. ../../proto/orderbook.proto89Usage:10python stream_bbo_example.py --coins BTC,ETH11"""1213import grpc14import sys15import time16import argparse1718try:19import orderbook_pb2 as pb20import orderbook_pb2_grpc as pb_grpc21except ImportError:22print("Error: Proto files not generated. Run:")23print(" python -m grpc_tools.protoc -I../../proto --python_out=. --grpc_python_out=. ../../proto/orderbook.proto")24sys.exit(1)2526# Configuration27GRPC_ENDPOINT = "your-endpoint.hype-mainnet.quiknode.pro:10000"28AUTH_TOKEN = "your-auth-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.3435Args:36coins: Symbols to stream (e.g., ["BTC", "ETH"]). Empty list means all coins37auto_reconnect: Auto-reconnect on DATA_LOSS errors (default True)38"""39print(f"\n{'='*60}")40print(f"Streaming BBO Book for {', '.join(coins) if coins else 'all coins'}")41print(f"Auto-reconnect: {auto_reconnect}")42print(f"{'='*60}\n")4344retry_count = 045max_retries = 1046base_delay = 24748while retry_count < max_retries:49channel = grpc.secure_channel(50GRPC_ENDPOINT,51grpc.ssl_channel_credentials(),52options=[53('grpc.max_receive_message_length', 100 * 1024 * 1024),54('grpc.keepalive_time_ms', 30000),55]56)57stub = pb_grpc.OrderBookStreamingStub(channel)5859# Build request60request = pb.BboBookRequest(coins=coins)6162msg_count = 06364try:65if retry_count > 0:66print(f"\nš Reconnecting (attempt {retry_count + 1}/{max_retries})...")67else:68print(f"Connecting to {GRPC_ENDPOINT}...")6970for update in stub.StreamBboBook(request, metadata=[('x-token', AUTH_TOKEN)]):71msg_count += 17273if msg_count == 1:74print(f"ā First BBO update received!\n")75retry_count = 0 # Reset retry count on successful connection7677# Display the BBO update78print(f"\n{'ā'*60}")79print(f"Block: {update.block_number} | Time: {update.time} | Coin: {update.coin}")80print(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# Show spread95if 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}")103104except grpc.RpcError as e:105if e.code() == grpc.StatusCode.DATA_LOSS and auto_reconnect:106print(f"\nā ļø Server reinitialized: {e.details()}")107retry_count += 1108if retry_count < max_retries:109delay = base_delay * (2 ** (retry_count - 1)) # Exponential backoff110print(f"ā³ Waiting {delay}s before reconnecting...")111time.sleep(delay)112channel.close()113continue114else:115print(f"\nā Max retries ({max_retries}) reached. Giving up.")116break117else:118print(f"\ngRPC error: {e.code()} - {e.details()}")119break120except KeyboardInterrupt:121print("\nStopping BBO stream...")122break123finally:124channel.close()125126# If we get here without error, break the retry loop127break128129130def 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 = parser.parse_args()135coins = [c.strip() for c in args.coins.split(',') if c.strip()]136137print(f"\n{'='*60}")138print("Hyperliquid StreamBboBook Example")139print(f"Endpoint: {GRPC_ENDPOINT}")140print(f"{'='*60}")141142try:143stream_bbo_book(coins)144except Exception as e:145print(f"\nError: {e}")146import traceback147traceback.print_exc()148sys.exit(1)149150151if __name__ == "__main__":152main()153
Don't have an account yet?
Create your Quicknode endpoint in seconds and start building
Get started for free