StreamL2BookDiff 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...
n_levels
uint32
Loading...
n_sig_figs
uint32
Loading...
mantissa
uint64
Loading...
skip_initial_snapshot
bool
Loading...
Returns
stream
stream<L2BookDiffUpdate>
Loading...
time
uint64
Loading...
height
uint64
Loading...
snapshot
bool
Loading...
diffs
array<L2CoinDiff>
Loading...
Request
1// StreamL2BookDiff Example - Stream incremental L2 price-level 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 streamL2BookDiff(coins []string, nLevels uint32) error {31fmt.Println(strings.Repeat("=", 60))32fmt.Printf("Streaming L2 Book Diffs for %s\n", strings.Join(coins, ", "))33fmt.Printf("Levels: %d\n", nLevels)34fmt.Println("Auto-reconnect: true")35fmt.Println(strings.Repeat("=", 60) + "\n")3637retryCount := 03839// Track last seq per coin for gap detection40lastSeq := make(map[string]uint64)4142for retryCount < maxRetries {43creds := credentials.NewClientTLSFromCert(nil, "")44conn, err := grpc.Dial(grpcEndpoint,45grpc.WithTransportCredentials(creds),46grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)))47if err != nil {48return fmt.Errorf("failed to connect: %w", err)49}5051client := pb.NewOrderBookStreamingClient(conn)52ctx := metadata.AppendToOutgoingContext(context.Background(), "x-token", authToken)5354request := &pb.L2BookDiffRequest{55Coins: coins,56NLevels: nLevels,57}5859if retryCount > 0 {60fmt.Printf("\nš Reconnecting (attempt %d/%d)...\n", retryCount+1, maxRetries)61} else {62fmt.Printf("Connecting to %s...\n", grpcEndpoint)63}6465stream, err := client.StreamL2BookDiff(ctx, request)66if err != nil {67conn.Close()68return fmt.Errorf("failed to start stream: %w", err)69}7071msgCount := 072shouldRetry := false7374for {75update, err := stream.Recv()76if err == io.EOF {77break78}79if err != nil {80st, ok := status.FromError(err)81if ok && st.Code() == codes.DataLoss {82fmt.Printf("\nā ļø Server reinitialized: %s\n", st.Message())83retryCount++84if retryCount < maxRetries {85delay := baseDelay * time.Duration(math.Pow(2, float64(retryCount-1)))86fmt.Printf("ā³ Waiting %v before reconnecting...\n", delay)87time.Sleep(delay)88shouldRetry = true89break90} else {91fmt.Printf("\nā Max retries (%d) reached. Giving up.\n", maxRetries)92conn.Close()93return nil94}95}96conn.Close()97return fmt.Errorf("stream error: %w", err)98}99100msgCount++101if msgCount == 1 {102fmt.Println("ā First L2 diff update received!\n")103retryCount = 0 // Reset on success104}105106// Display diff update107fmt.Println("\n" + strings.Repeat("ā", 60))108snapshotLabel := ""109if update.Snapshot {110snapshotLabel = " | SNAPSHOT"111}112fmt.Printf("Block: %d | Time: %d%s\n", update.Height, update.Time, snapshotLabel)113fmt.Println(strings.Repeat("ā", 60))114115for _, diff := range update.Diffs {116// Check seq continuity per coin117if prev, ok := lastSeq[diff.Coin]; ok && diff.PrevSeq != 0 && diff.PrevSeq != prev {118fmt.Printf(" ā ļø Sequence gap for %s: expected prev_seq %d, got %d\n", diff.Coin, prev, diff.PrevSeq)119}120lastSeq[diff.Coin] = diff.Seq121122label := "DIFF"123if diff.Snapshot {124label = "SNAPSHOT"125}126fmt.Printf("\n %s [%s] seq: %d (prev: %d)\n", diff.Coin, label, diff.Seq, diff.PrevSeq)127128// Changed ask levels (sz "0" means level removed)129for _, level := range diff.Asks {130action := "SET"131if level.Sz == "0" {132action = "REMOVE"133}134fmt.Printf(" ASK %-6s %12s | %12s\n", action, level.Px, level.Sz)135}136137// Changed bid levels138for _, level := range diff.Bids {139action := "SET"140if level.Sz == "0" {141action = "REMOVE"142}143fmt.Printf(" BID %-6s %12s | %12s\n", action, level.Px, level.Sz)144}145}146147fmt.Printf("\n Messages received: %d\n", msgCount)148}149150conn.Close()151152if !shouldRetry {153break154}155}156157return nil158}159160func main() {161coinsFlag := flag.String("coins", "BTC", "Comma-separated coin symbols to stream (e.g., BTC,ETH)")162levels := flag.Uint("levels", 20, "Maximum price levels per side")163164flag.Parse()165166coins := strings.Split(*coinsFlag, ",")167168fmt.Println("\n" + strings.Repeat("=", 60))169fmt.Println("Hyperliquid StreamL2BookDiff Example")170fmt.Printf("Endpoint: %s\n", grpcEndpoint)171fmt.Println(strings.Repeat("=", 60))172173if err := streamL2BookDiff(coins, uint32(*levels)); err != nil {174log.Fatal(err)175}176}177
1// StreamL2BookDiff Example - Stream incremental L2 price-level 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 streamL2BookDiff(coins []string, nLevels uint32) error {31fmt.Println(strings.Repeat("=", 60))32fmt.Printf("Streaming L2 Book Diffs for %s\n", strings.Join(coins, ", "))33fmt.Printf("Levels: %d\n", nLevels)34fmt.Println("Auto-reconnect: true")35fmt.Println(strings.Repeat("=", 60) + "\n")3637retryCount := 03839// Track last seq per coin for gap detection40lastSeq := make(map[string]uint64)4142for retryCount < maxRetries {43creds := credentials.NewClientTLSFromCert(nil, "")44conn, err := grpc.Dial(grpcEndpoint,45grpc.WithTransportCredentials(creds),46grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)))47if err != nil {48return fmt.Errorf("failed to connect: %w", err)49}5051client := pb.NewOrderBookStreamingClient(conn)52ctx := metadata.AppendToOutgoingContext(context.Background(), "x-token", authToken)5354request := &pb.L2BookDiffRequest{55Coins: coins,56NLevels: nLevels,57}5859if retryCount > 0 {60fmt.Printf("\nš Reconnecting (attempt %d/%d)...\n", retryCount+1, maxRetries)61} else {62fmt.Printf("Connecting to %s...\n", grpcEndpoint)63}6465stream, err := client.StreamL2BookDiff(ctx, request)66if err != nil {67conn.Close()68return fmt.Errorf("failed to start stream: %w", err)69}7071msgCount := 072shouldRetry := false7374for {75update, err := stream.Recv()76if err == io.EOF {77break78}79if err != nil {80st, ok := status.FromError(err)81if ok && st.Code() == codes.DataLoss {82fmt.Printf("\nā ļø Server reinitialized: %s\n", st.Message())83retryCount++84if retryCount < maxRetries {85delay := baseDelay * time.Duration(math.Pow(2, float64(retryCount-1)))86fmt.Printf("ā³ Waiting %v before reconnecting...\n", delay)87time.Sleep(delay)88shouldRetry = true89break90} else {91fmt.Printf("\nā Max retries (%d) reached. Giving up.\n", maxRetries)92conn.Close()93return nil94}95}96conn.Close()97return fmt.Errorf("stream error: %w", err)98}99100msgCount++101if msgCount == 1 {102fmt.Println("ā First L2 diff update received!\n")103retryCount = 0 // Reset on success104}105106// Display diff update107fmt.Println("\n" + strings.Repeat("ā", 60))108snapshotLabel := ""109if update.Snapshot {110snapshotLabel = " | SNAPSHOT"111}112fmt.Printf("Block: %d | Time: %d%s\n", update.Height, update.Time, snapshotLabel)113fmt.Println(strings.Repeat("ā", 60))114115for _, diff := range update.Diffs {116// Check seq continuity per coin117if prev, ok := lastSeq[diff.Coin]; ok && diff.PrevSeq != 0 && diff.PrevSeq != prev {118fmt.Printf(" ā ļø Sequence gap for %s: expected prev_seq %d, got %d\n", diff.Coin, prev, diff.PrevSeq)119}120lastSeq[diff.Coin] = diff.Seq121122label := "DIFF"123if diff.Snapshot {124label = "SNAPSHOT"125}126fmt.Printf("\n %s [%s] seq: %d (prev: %d)\n", diff.Coin, label, diff.Seq, diff.PrevSeq)127128// Changed ask levels (sz "0" means level removed)129for _, level := range diff.Asks {130action := "SET"131if level.Sz == "0" {132action = "REMOVE"133}134fmt.Printf(" ASK %-6s %12s | %12s\n", action, level.Px, level.Sz)135}136137// Changed bid levels138for _, level := range diff.Bids {139action := "SET"140if level.Sz == "0" {141action = "REMOVE"142}143fmt.Printf(" BID %-6s %12s | %12s\n", action, level.Px, level.Sz)144}145}146147fmt.Printf("\n Messages received: %d\n", msgCount)148}149150conn.Close()151152if !shouldRetry {153break154}155}156157return nil158}159160func main() {161coinsFlag := flag.String("coins", "BTC", "Comma-separated coin symbols to stream (e.g., BTC,ETH)")162levels := flag.Uint("levels", 20, "Maximum price levels per side")163164flag.Parse()165166coins := strings.Split(*coinsFlag, ",")167168fmt.Println("\n" + strings.Repeat("=", 60))169fmt.Println("Hyperliquid StreamL2BookDiff Example")170fmt.Printf("Endpoint: %s\n", grpcEndpoint)171fmt.Println(strings.Repeat("=", 60))172173if err := streamL2BookDiff(coins, uint32(*levels)); err != nil {174log.Fatal(err)175}176}177
Don't have an account yet?
Create your Quicknode endpoint in seconds and start building
Get started for free