StreamL4Book - Stream Full L4 Order Book
Subscribe to a typed Hyperliquid L4 opening snapshot followed by native per-block order-book diffs over V3 gRPC.
Hyperliquid RPC endpoint: endpoint URLs, plans and pricing.
StreamL4Book exposes the full per-order book for one coin. The first frame is a typed snapshot; later frames carry the node-native JSON diff object in data.
Request and opening behavior
coin is required and validated case-sensitively. Omitted mirror defaults to true, enabling HIP-4 binary-sibling projection. Mirrored orders set synthetic: true and have bit 52 set in oid.
The snapshot contains typed L4Order rows. Each later diff contains JSON-encoded {order_statuses, book_diffs} plus its block time and sequential block number.
Large opening snapshot
The opening snapshot can exceed the client inbound message limit. The Go example sets a 64 MiB receive allowance as a practical starting point; tune it for the selected coin and workload while keeping memory use bounded.
package main
import (
"context"
"crypto/tls"
"errors"
"io"
"log"
"os"
"os/signal"
"syscall"
pb "example.com/hyperliquid-v3-client/gen/v3"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
"google.golang.org/protobuf/proto"
)
func main() {
endpoint := os.Getenv("HYPERLIQUID_GRPC_ENDPOINT")
apiKey := os.Getenv("DWELLIR_API_KEY")
if endpoint == "" || apiKey == "" {
log.Fatal("set HYPERLIQUID_GRPC_ENDPOINT and DWELLIR_API_KEY")
}
conn, err := grpc.NewClient(
endpoint,
grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12})),
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(64 * 1024 * 1024)),
)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
ctx = metadata.AppendToOutgoingContext(ctx, "x-api-key", apiKey)
stream, err := pb.NewMarketStreamingClient(conn).StreamL4Book(ctx, &pb.L4BookRequest{Coin: "BTC", Mirror: proto.Bool(true)})
if err != nil {
log.Fatal(err)
}
for {
update, err := stream.Recv()
if errors.Is(err, io.EOF) {
return
}
if err != nil {
log.Fatal(err)
}
if snapshot := update.GetSnapshot(); snapshot != nil {
log.Printf("snapshot coin=%s block=%d bids=%d asks=%d", snapshot.GetCoin(), snapshot.GetBlockNumber(), len(snapshot.GetBids()), len(snapshot.GetAsks()))
continue
}
diff := update.GetDiff()
log.Printf("diff block=%d json_bytes=%d", diff.GetBlockNumber(), len(diff.GetData()))
}
}Delivery and recovery
This is an incremental stream. Frame loss, a stream state reset, or an outcome market changing shape closes it with ABORTED. Reconnect and rebuild from the next opening snapshot. For typed order-level diffs without native JSON, use StreamL4OrderUpdates. Shared live-stream and error semantics are on the gRPC overview.
Related references: StreamL4OrderUpdates and the Order Book WebSocket L4 book.
StreamL2BookDiff - Stream Ordered L2 Diffs
Reconstruct up to 20 Hyperliquid L2 books from typed opening snapshots and sequenced level diffs over V3 gRPC.
StreamL4OrderUpdates - Stream Typed Order Diffs
Maintain typed Hyperliquid resting-order state from an opening snapshot and sequenced L4 diffs over V3 gRPC.