StreamL4BookUpdates gRPC Method
Please note that this method is metered based on data consumption at 0.0165 MB = 10 API credits.
Parameters
coins
repeated string
Loading...
Returns
stream
stream<L4BookUpdatesUpdate>
Loading...
time
uint64
Loading...
height
uint64
Loading...
snapshot
bool
Loading...
diffs
array<L4OrderDiff>
Loading...
Request
1// StreamL4BookUpdates Example - Stream typed per-order book updates 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)2930type localOrder struct {31coin string32user string33side string34px string35sz string36}3738func streamL4BookUpdates(coins []string) error {39fmt.Println(strings.Repeat("=", 60))40fmt.Printf("Streaming L4 Book Updates for %s\n", strings.Join(coins, ", "))41fmt.Println("Auto-reconnect: true")42fmt.Println(strings.Repeat("=", 60) + "\n")4344retryCount := 04546// Simple local order map keyed by oid47orders := make(map[uint64]localOrder)4849for retryCount < maxRetries {50creds := credentials.NewClientTLSFromCert(nil, "")51conn, err := grpc.Dial(grpcEndpoint,52grpc.WithTransportCredentials(creds),53grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)))54if err != nil {55return fmt.Errorf("failed to connect: %w", err)56}5758client := pb.NewOrderBookStreamingClient(conn)59ctx := metadata.AppendToOutgoingContext(context.Background(), "x-token", authToken)6061request := &pb.L4BookUpdatesRequest{62Coins: coins,63}6465if retryCount > 0 {66fmt.Printf("\nš Reconnecting (attempt %d/%d)...\n", retryCount+1, maxRetries)67} else {68fmt.Printf("Connecting to %s...\n", grpcEndpoint)69}7071stream, err := client.StreamL4BookUpdates(ctx, request)72if err != nil {73conn.Close()74return fmt.Errorf("failed to start stream: %w", err)75}7677msgCount := 078shouldRetry := false7980for {81update, err := stream.Recv()82if err == io.EOF {83break84}85if err != nil {86st, ok := status.FromError(err)87if ok && st.Code() == codes.DataLoss {88fmt.Printf("\nā ļø Server reinitialized: %s\n", st.Message())89retryCount++90if retryCount < maxRetries {91delay := baseDelay * time.Duration(math.Pow(2, float64(retryCount-1)))92fmt.Printf("ā³ Waiting %v before reconnecting...\n", delay)93time.Sleep(delay)94shouldRetry = true95break96} else {97fmt.Printf("\nā Max retries (%d) reached. Giving up.\n", maxRetries)98conn.Close()99return nil100}101}102conn.Close()103return fmt.Errorf("stream error: %w", err)104}105106msgCount++107if msgCount == 1 {108fmt.Println("ā First L4 update received!\n")109retryCount = 0 // Reset on success110}111112if update.Snapshot {113// Full reset snapshot: rebuild local state114orders = make(map[uint64]localOrder)115}116117// Display update118fmt.Println("\n" + strings.Repeat("ā", 60))119snapshotLabel := ""120if update.Snapshot {121snapshotLabel = " | SNAPSHOT"122}123fmt.Printf("Block: %d | Time: %d%s | Diffs: %d\n", update.Height, update.Time, snapshotLabel, len(update.Diffs))124fmt.Println(strings.Repeat("ā", 60))125126for _, diff := range update.Diffs {127side := "ASK"128if diff.Side == "B" {129side = "BID"130}131132switch diff.DiffType {133case pb.L4OrderDiffType_L4_ORDER_DIFF_TYPE_NEW:134orders[diff.Oid] = localOrder{coin: diff.Coin, user: diff.User, side: diff.Side, px: diff.Px, sz: diff.Sz}135if !update.Snapshot {136fmt.Printf(" NEW %s oid: %d | %s %s x %s | %s\n", diff.Coin, diff.Oid, side, diff.Px, diff.Sz, diff.User)137}138case pb.L4OrderDiffType_L4_ORDER_DIFF_TYPE_UPDATE:139if existing, ok := orders[diff.Oid]; ok {140existing.sz = diff.Sz141orders[diff.Oid] = existing142}143fmt.Printf(" UPDATE %s oid: %d | %s %s x %s | %s\n", diff.Coin, diff.Oid, side, diff.Px, diff.Sz, diff.User)144case pb.L4OrderDiffType_L4_ORDER_DIFF_TYPE_REMOVE:145delete(orders, diff.Oid)146fmt.Printf(" REMOVE %s oid: %d | %s %s | %s\n", diff.Coin, diff.Oid, side, diff.Px, diff.User)147}148}149150fmt.Printf("\n Resting orders tracked: %d | Messages received: %d\n", len(orders), msgCount)151}152153conn.Close()154155if !shouldRetry {156break157}158}159160return nil161}162163func main() {164coinsFlag := flag.String("coins", "BTC", "Comma-separated coin symbols to stream (e.g., BTC,ETH)")165166flag.Parse()167168coins := strings.Split(*coinsFlag, ",")169170fmt.Println("\n" + strings.Repeat("=", 60))171fmt.Println("Hyperliquid StreamL4BookUpdates Example")172fmt.Printf("Endpoint: %s\n", grpcEndpoint)173fmt.Println(strings.Repeat("=", 60))174175if err := streamL4BookUpdates(coins); err != nil {176log.Fatal(err)177}178}179
1// StreamL4BookUpdates Example - Stream typed per-order book updates 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)2930type localOrder struct {31coin string32user string33side string34px string35sz string36}3738func streamL4BookUpdates(coins []string) error {39fmt.Println(strings.Repeat("=", 60))40fmt.Printf("Streaming L4 Book Updates for %s\n", strings.Join(coins, ", "))41fmt.Println("Auto-reconnect: true")42fmt.Println(strings.Repeat("=", 60) + "\n")4344retryCount := 04546// Simple local order map keyed by oid47orders := make(map[uint64]localOrder)4849for retryCount < maxRetries {50creds := credentials.NewClientTLSFromCert(nil, "")51conn, err := grpc.Dial(grpcEndpoint,52grpc.WithTransportCredentials(creds),53grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)))54if err != nil {55return fmt.Errorf("failed to connect: %w", err)56}5758client := pb.NewOrderBookStreamingClient(conn)59ctx := metadata.AppendToOutgoingContext(context.Background(), "x-token", authToken)6061request := &pb.L4BookUpdatesRequest{62Coins: coins,63}6465if retryCount > 0 {66fmt.Printf("\nš Reconnecting (attempt %d/%d)...\n", retryCount+1, maxRetries)67} else {68fmt.Printf("Connecting to %s...\n", grpcEndpoint)69}7071stream, err := client.StreamL4BookUpdates(ctx, request)72if err != nil {73conn.Close()74return fmt.Errorf("failed to start stream: %w", err)75}7677msgCount := 078shouldRetry := false7980for {81update, err := stream.Recv()82if err == io.EOF {83break84}85if err != nil {86st, ok := status.FromError(err)87if ok && st.Code() == codes.DataLoss {88fmt.Printf("\nā ļø Server reinitialized: %s\n", st.Message())89retryCount++90if retryCount < maxRetries {91delay := baseDelay * time.Duration(math.Pow(2, float64(retryCount-1)))92fmt.Printf("ā³ Waiting %v before reconnecting...\n", delay)93time.Sleep(delay)94shouldRetry = true95break96} else {97fmt.Printf("\nā Max retries (%d) reached. Giving up.\n", maxRetries)98conn.Close()99return nil100}101}102conn.Close()103return fmt.Errorf("stream error: %w", err)104}105106msgCount++107if msgCount == 1 {108fmt.Println("ā First L4 update received!\n")109retryCount = 0 // Reset on success110}111112if update.Snapshot {113// Full reset snapshot: rebuild local state114orders = make(map[uint64]localOrder)115}116117// Display update118fmt.Println("\n" + strings.Repeat("ā", 60))119snapshotLabel := ""120if update.Snapshot {121snapshotLabel = " | SNAPSHOT"122}123fmt.Printf("Block: %d | Time: %d%s | Diffs: %d\n", update.Height, update.Time, snapshotLabel, len(update.Diffs))124fmt.Println(strings.Repeat("ā", 60))125126for _, diff := range update.Diffs {127side := "ASK"128if diff.Side == "B" {129side = "BID"130}131132switch diff.DiffType {133case pb.L4OrderDiffType_L4_ORDER_DIFF_TYPE_NEW:134orders[diff.Oid] = localOrder{coin: diff.Coin, user: diff.User, side: diff.Side, px: diff.Px, sz: diff.Sz}135if !update.Snapshot {136fmt.Printf(" NEW %s oid: %d | %s %s x %s | %s\n", diff.Coin, diff.Oid, side, diff.Px, diff.Sz, diff.User)137}138case pb.L4OrderDiffType_L4_ORDER_DIFF_TYPE_UPDATE:139if existing, ok := orders[diff.Oid]; ok {140existing.sz = diff.Sz141orders[diff.Oid] = existing142}143fmt.Printf(" UPDATE %s oid: %d | %s %s x %s | %s\n", diff.Coin, diff.Oid, side, diff.Px, diff.Sz, diff.User)144case pb.L4OrderDiffType_L4_ORDER_DIFF_TYPE_REMOVE:145delete(orders, diff.Oid)146fmt.Printf(" REMOVE %s oid: %d | %s %s | %s\n", diff.Coin, diff.Oid, side, diff.Px, diff.User)147}148}149150fmt.Printf("\n Resting orders tracked: %d | Messages received: %d\n", len(orders), msgCount)151}152153conn.Close()154155if !shouldRetry {156break157}158}159160return nil161}162163func main() {164coinsFlag := flag.String("coins", "BTC", "Comma-separated coin symbols to stream (e.g., BTC,ETH)")165166flag.Parse()167168coins := strings.Split(*coinsFlag, ",")169170fmt.Println("\n" + strings.Repeat("=", 60))171fmt.Println("Hyperliquid StreamL4BookUpdates Example")172fmt.Printf("Endpoint: %s\n", grpcEndpoint)173fmt.Println(strings.Repeat("=", 60))174175if err := streamL4BookUpdates(coins); err != nil {176log.Fatal(err)177}178}179
Don't have an account yet?
Create your Quicknode endpoint in seconds and start building
Get started for free