StreamL4Book gRPC Method
Parameters
coin
string
Loading...
Returns
stream
stream<L4BookUpdate>
Loading...
snapshot
L4BookSnapshot
Loading...
diff
L4BookDiff
Loading...
Request
1// StreamL4Book Example - Stream individual order data via gRPC2package main34import (5"context"6"encoding/json"7"flag"8"fmt"9"io"10"log"11"math"12"strings"13"time"1415"google.golang.org/grpc"16"google.golang.org/grpc/codes"17"google.golang.org/grpc/credentials"18"google.golang.org/grpc/metadata"19"google.golang.org/grpc/status"2021pb "hyperliquid-orderbook-example/proto"22)2324const (25grpcEndpoint = "your-endpoint.hype-mainnet.quiknode.pro:10000"26authToken = "your-auth-token"27maxRetries = 1028baseDelay = 2 * time.Second29)3031func streamL4Orderbook(coin string, maxMessages int) error {32fmt.Println(strings.Repeat("=", 60))33fmt.Printf("Streaming L4 Orderbook for %s\n", coin)34fmt.Println("Auto-reconnect: true")35fmt.Println(strings.Repeat("=", 60) + "\n")3637retryCount := 038totalMsgCount := 03940for retryCount < maxRetries {41creds := credentials.NewClientTLSFromCert(nil, "")42conn, err := grpc.Dial(grpcEndpoint,43grpc.WithTransportCredentials(creds),44grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)))45if err != nil {46return fmt.Errorf("failed to connect: %w", err)47}4849client := pb.NewOrderBookStreamingClient(conn)50ctx := metadata.AppendToOutgoingContext(context.Background(), "x-token", authToken)5152request := &pb.L4BookRequest{53Coin: coin,54}5556if retryCount > 0 {57fmt.Printf("\n🔄 Reconnecting (attempt %d/%d)...\n", retryCount+1, maxRetries)58} else {59fmt.Printf("Connecting to %s...\n", grpcEndpoint)60}6162stream, err := client.StreamL4Book(ctx, request)63if err != nil {64conn.Close()65return fmt.Errorf("failed to start stream: %w", err)66}6768snapshotReceived := false69shouldRetry := false7071for {72update, err := stream.Recv()73if err == io.EOF {74break75}76if err != nil {77st, ok := status.FromError(err)78if ok && st.Code() == codes.DataLoss {79fmt.Printf("\n⚠️ Server reinitialized: %s\n", st.Message())80retryCount++81if retryCount < maxRetries {82delay := baseDelay * time.Duration(math.Pow(2, float64(retryCount-1)))83fmt.Printf("⏳ Waiting %v before reconnecting...\n", delay)84time.Sleep(delay)85shouldRetry = true86break87} else {88fmt.Printf("\n❌ Max retries (%d) reached. Giving up.\n", maxRetries)89conn.Close()90return nil91}92}93conn.Close()94return fmt.Errorf("stream error: %w", err)95}9697totalMsgCount++9899if snapshot := update.GetSnapshot(); snapshot != nil {100snapshotReceived = true101retryCount = 0 // Reset on success102103fmt.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.Close()180return nil181}182}183184conn.Close()185186if !shouldRetry {187break188}189}190191return nil192}193194func main() {195coin := flag.String("coin", "BTC", "Coin symbol to stream")196maxMessages := flag.Int("max-messages", 0, "Maximum messages (0 = unlimited)")197198flag.Parse()199200fmt.Println("\n" + strings.Repeat("=", 60))201fmt.Println("Hyperliquid StreamL4Book Example")202fmt.Printf("Endpoint: %s\n", grpcEndpoint)203fmt.Println(strings.Repeat("=", 60))204205if err := streamL4Orderbook(*coin, *maxMessages); err != nil {206log.Fatal(err)207}208}209
1// StreamL4Book Example - Stream individual order data via gRPC2package main34import (5"context"6"encoding/json"7"flag"8"fmt"9"io"10"log"11"math"12"strings"13"time"1415"google.golang.org/grpc"16"google.golang.org/grpc/codes"17"google.golang.org/grpc/credentials"18"google.golang.org/grpc/metadata"19"google.golang.org/grpc/status"2021pb "hyperliquid-orderbook-example/proto"22)2324const (25grpcEndpoint = "your-endpoint.hype-mainnet.quiknode.pro:10000"26authToken = "your-auth-token"27maxRetries = 1028baseDelay = 2 * time.Second29)3031func streamL4Orderbook(coin string, maxMessages int) error {32fmt.Println(strings.Repeat("=", 60))33fmt.Printf("Streaming L4 Orderbook for %s\n", coin)34fmt.Println("Auto-reconnect: true")35fmt.Println(strings.Repeat("=", 60) + "\n")3637retryCount := 038totalMsgCount := 03940for retryCount < maxRetries {41creds := credentials.NewClientTLSFromCert(nil, "")42conn, err := grpc.Dial(grpcEndpoint,43grpc.WithTransportCredentials(creds),44grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)))45if err != nil {46return fmt.Errorf("failed to connect: %w", err)47}4849client := pb.NewOrderBookStreamingClient(conn)50ctx := metadata.AppendToOutgoingContext(context.Background(), "x-token", authToken)5152request := &pb.L4BookRequest{53Coin: coin,54}5556if retryCount > 0 {57fmt.Printf("\n 🔄 Reconnecting (attempt %d/%d)...\n", retryCount+1, maxRetries)58} else {59fmt.Printf("Connecting to %s...\n", grpcEndpoint)60}6162stream, err := client.StreamL4Book(ctx, request)63if err != nil {64conn.Close()65return fmt.Errorf("failed to start stream: %w", err)66}6768snapshotReceived := false69shouldRetry := false7071for {72update, err := stream.Recv()73if err == io.EOF {74break75}76if err != nil {77st, ok := status.FromError(err)78if ok && st.Code() == codes.DataLoss {79fmt.Printf("\n⚠️ Server reinitialized: %s\n", st.Message())80retryCount++81if retryCount < maxRetries {82delay := baseDelay * time.Duration(math.Pow(2, float64(retryCount-1)))83fmt.Printf("⏳ Waiting %v before reconnecting...\n", delay)84time.Sleep(delay)85shouldRetry = true86break87} else {88fmt.Printf("\n❌ Max retries (%d) reached. Giving up.\n", maxRetries)89conn.Close()90return nil91}92}93conn.Close()94return fmt.Errorf("stream error: %w", err)95}9697totalMsgCount++9899if snapshot := update.GetSnapshot(); snapshot != nil {100snapshotReceived = true101retryCount = 0 // Reset on success102103fmt.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.Close()180return nil181}182}183184conn.Close()185186if !shouldRetry {187break188}189}190191return nil192}193194func main() {195coin := flag.String("coin", "BTC", "Coin symbol to stream")196maxMessages := flag.Int("max-messages", 0, "Maximum messages (0 = unlimited)")197198flag.Parse()199200fmt.Println("\n" + strings.Repeat("=", 60))201fmt.Println("Hyperliquid StreamL4Book Example")202fmt.Printf("Endpoint: %s\n", grpcEndpoint)203fmt.Println(strings.Repeat("=", 60))204205if err := streamL4Orderbook(*coin, *maxMessages); err != nil {206log.Fatal(err)207}208}209
Don't have an account yet?
Create your Quicknode endpoint in seconds and start building
Get started for free