GetOrderBookSnapshot
Retrieve a single order book snapshot at a specific point in time from the Hyperliquid L1 Gateway.
When to Use This Method
GetOrderBookSnapshot
is essential for:
- Market Analysis - Get current market depth and liquidity
- Trading Strategies - Analyze bid/ask spreads and order distribution
- Price Discovery - Determine fair market value
- Risk Management - Assess market impact before placing orders
Method Signature
rpc GetOrderBookSnapshot(Timestamp) returns (OrderBookSnapshot) {}
Request Message
message Timestamp {
int64 timestamp = 1;
}
Current Limitation: The timestamp parameter is not yet implemented. This method currently returns the most recent order book snapshot regardless of the timestamp value provided.
Response Message
message OrderBookSnapshot {
// JSON-encoded object conforming to a
// Hyperliquid order book snapshot
bytes data = 1;
}
The data
field contains a complete order book snapshot in JSON format with:
- Bid orders (buy orders) sorted by price descending
- Ask orders (sell orders) sorted by price ascending
- Market depth and liquidity information
- Timestamp of the snapshot
Implementation Examples
- Go
- Python
- Node.js
package main
import (
"context"
"encoding/json"
"log"
pb "your-project/hyperliquid_l1_gateway/v1"
"google.golang.org/grpc"
)
type OrderBookData struct {
Bids [][]string `json:"bids"`
Asks [][]string `json:"asks"`
Timestamp int64 `json:"timestamp"`
}
func getOrderBookSnapshot(client pb.HyperliquidL1GatewayClient) (*OrderBookData, error) {
// Request current snapshot (timestamp ignored for now)
response, err := client.GetOrderBookSnapshot(
context.Background(),
&pb.Timestamp{Timestamp: 0},
)
if err != nil {
return nil, err
}
// Parse JSON response
var orderBook OrderBookData
if err := json.Unmarshal(response.Data, &orderBook); err != nil {
return nil, err
}
return &orderBook, nil
}
func main() {
// Connect to Hyperliquid L1 Gateway
conn, err := grpc.Dial(
"<YOUR_HYPERLIQUID_ENDPOINT>", // Contact support@dwellir.com
grpc.WithInsecure(),
)
if err != nil {
log.Fatalf("Failed to connect: %v", err)
}
defer conn.Close()
client := pb.NewHyperliquidL1GatewayClient(conn)
// Get current order book snapshot
orderBook, err := getOrderBookSnapshot(client)
if err != nil {
log.Fatalf("Failed to get order book: %v", err)
}
log.Printf("Order book - Bids: %d, Asks: %d",
len(orderBook.Bids), len(orderBook.Asks))
// Process order book data
if len(orderBook.Bids) > 0 {
log.Printf("Best bid: %s @ %s", orderBook.Bids[0][1], orderBook.Bids[0][0])
}
if len(orderBook.Asks) > 0 {
log.Printf("Best ask: %s @ %s", orderBook.Asks[0][1], orderBook.Asks[0][0])
}
}
import grpc
import json
from hyperliquid_l1_gateway_pb2 import Timestamp
from hyperliquid_l1_gateway_pb2_grpc import HyperliquidL1GatewayStub
class OrderBookAnalyzer:
def __init__(self, endpoint):
self.channel = grpc.insecure_channel(endpoint)
self.stub = HyperliquidL1GatewayStub(self.channel)
def get_snapshot(self):
"""Get current order book snapshot"""
timestamp = Timestamp(timestamp=0) # Currently ignored
response = self.stub.GetOrderBookSnapshot(timestamp)
# Parse JSON data
data = json.loads(response.data)
return data
def analyze_spread(self, order_book):
"""Calculate bid-ask spread"""
if not order_book.get('bids') or not order_book.get('asks'):
return None
best_bid = float(order_book['bids'][0][0])
best_ask = float(order_book['asks'][0][0])
spread = best_ask - best_bid
spread_bps = (spread / best_bid) * 10000
return {
'best_bid': best_bid,
'best_ask': best_ask,
'spread': spread,
'spread_bps': spread_bps
}
def calculate_depth(self, order_book, levels=10):
"""Calculate market depth"""
bids = order_book.get('bids', [])[:levels]
asks = order_book.get('asks', [])[:levels]
bid_volume = sum(float(order[1]) for order in bids)
ask_volume = sum(float(order[1]) for order in asks)
return {
'bid_depth': bid_volume,
'ask_depth': ask_volume,
'total_depth': bid_volume + ask_volume
}
def main():
analyzer = OrderBookAnalyzer('<YOUR_HYPERLIQUID_ENDPOINT>')
try:
# Get order book snapshot
order_book = analyzer.get_snapshot()
print(f"Order book timestamp: {order_book.get('timestamp', 'N/A')}")
# Analyze spread
spread_info = analyzer.analyze_spread(order_book)
if spread_info:
print(f"Best bid: {spread_info['best_bid']}")
print(f"Best ask: {spread_info['best_ask']}")
print(f"Spread: {spread_info['spread']} ({spread_info['spread_bps']:.2f} bps)")
# Calculate depth
depth_info = analyzer.calculate_depth(order_book)
print(f"Market depth (top 10): {depth_info['total_depth']}")
except grpc.RpcError as e:
print(f"gRPC error: {e}")
except json.JSONDecodeError as e:
print(f"JSON parsing error: {e}")
if __name__ == '__main__':
main()
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
// Load proto file
const packageDefinition = protoLoader.loadSync(
'hyperliquid_l1_gateway.proto',
{
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true
}
);
class OrderBookClient {
constructor(endpoint) {
const proto = grpc.loadPackageDefinition(packageDefinition);
this.client = new proto.hyperliquid_l1_gateway.v1.HyperliquidL1Gateway(
endpoint, // Contact support@dwellir.com
grpc.credentials.createInsecure()
);
}
async getSnapshot() {
return new Promise((resolve, reject) => {
this.client.GetOrderBookSnapshot(
{ timestamp: 0 }, // Currently ignored
(error, response) => {
if (error) {
reject(error);
return;
}
try {
const data = JSON.parse(response.data.toString());
resolve(data);
} catch (parseError) {
reject(parseError);
}
}
);
});
}
calculateMetrics(orderBook) {
const bids = orderBook.bids || [];
const asks = orderBook.asks || [];
if (bids.length === 0 || asks.length === 0) {
return null;
}
const bestBid = parseFloat(bids[0][0]);
const bestAsk = parseFloat(asks[0][0]);
const spread = bestAsk - bestBid;
// Calculate total volume at top levels
const bidVolume = bids.slice(0, 10).reduce(
(sum, order) => sum + parseFloat(order[1]), 0
);
const askVolume = asks.slice(0, 10).reduce(
(sum, order) => sum + parseFloat(order[1]), 0
);
return {
bestBid,
bestAsk,
spread,
spreadBps: (spread / bestBid) * 10000,
bidVolume,
askVolume,
totalVolume: bidVolume + askVolume
};
}
}
async function main() {
const client = new OrderBookClient('<YOUR_HYPERLIQUID_ENDPOINT>');
try {
console.log('Fetching order book snapshot...');
const orderBook = await client.getSnapshot();
console.log(`Timestamp: ${orderBook.timestamp || 'N/A'}`);
console.log(`Bids: ${orderBook.bids?.length || 0} levels`);
console.log(`Asks: ${orderBook.asks?.length || 0} levels`);
const metrics = client.calculateMetrics(orderBook);
if (metrics) {
console.log(`\nMarket Metrics:`);
console.log(`Best bid: ${metrics.bestBid}`);
console.log(`Best ask: ${metrics.bestAsk}`);
console.log(`Spread: ${metrics.spread} (${metrics.spreadBps.toFixed(2)} bps)`);
console.log(`Top 10 levels volume: ${metrics.totalVolume.toFixed(4)}`);
}
} catch (error) {
console.error('Error:', error.message);
}
}
main();
Common Use Cases
1. Market Making Strategy
async function marketMakingSignals(client) {
const orderBook = await client.getSnapshot();
const metrics = client.calculateMetrics(orderBook);
if (!metrics) return null;
// Calculate fair value and optimal spread
const midPrice = (metrics.bestBid + metrics.bestAsk) / 2;
const optimalSpread = Math.max(metrics.spread * 0.8, 0.001); // Minimum spread
return {
fairValue: midPrice,
bidPrice: midPrice - (optimalSpread / 2),
askPrice: midPrice + (optimalSpread / 2),
marketDepth: metrics.totalVolume,
spreadTightness: metrics.spreadBps
};
}
2. Liquidity Assessment
def assess_liquidity(order_book, target_size):
"""Assess market impact for a given trade size"""
bids = order_book.get('bids', [])
asks = order_book.get('asks', [])
def calculate_slippage(orders, size):
filled = 0
weighted_price = 0
for price_str, volume_str in orders:
price = float(price_str)
volume = float(volume_str)
fill_amount = min(size - filled, volume)
weighted_price += price * fill_amount
filled += fill_amount
if filled >= size:
break
return weighted_price / filled if filled > 0 else None
buy_price = calculate_slippage(asks, target_size) # Buy from asks
sell_price = calculate_slippage(bids, target_size) # Sell to bids
if not bids or not asks:
return None
mid_price = (float(bids[0][0]) + float(asks[0][0])) / 2
return {
'mid_price': mid_price,
'buy_price': buy_price,
'sell_price': sell_price,
'buy_slippage': (buy_price - mid_price) / mid_price if buy_price else None,
'sell_slippage': (mid_price - sell_price) / mid_price if sell_price else None
}
3. Real-time Price Display
func displayOrderBook(orderBook *OrderBookData) {
fmt.Println("=== ORDER BOOK ===")
fmt.Printf("Timestamp: %d\n", orderBook.Timestamp)
// Display top 5 asks (reverse order for display)
fmt.Println("\nAsks:")
askCount := len(orderBook.Asks)
for i := min(5, askCount) - 1; i >= 0; i-- {
price := orderBook.Asks[i][0]
volume := orderBook.Asks[i][1]
fmt.Printf(" %s @ %s\n", volume, price)
}
fmt.Println(" -----------")
// Display top 5 bids
fmt.Println("Bids:")
for i := 0; i < min(5, len(orderBook.Bids)); i++ {
price := orderBook.Bids[i][0]
volume := orderBook.Bids[i][1]
fmt.Printf(" %s @ %s\n", volume, price)
}
}
Error Handling
async function robustGetSnapshot(client, retries = 3) {
for (let attempt = 0; attempt < retries; attempt++) {
try {
return await client.getSnapshot();
} catch (error) {
console.warn(`Attempt ${attempt + 1} failed:`, error.message);
if (attempt === retries - 1) {
throw error;
}
// Exponential backoff
await new Promise(resolve =>
setTimeout(resolve, Math.pow(2, attempt) * 1000)
);
}
}
}
Best Practices
- Cache Management: Order book snapshots can be cached briefly (1-5 seconds) for non-critical applications
- Data Validation: Always validate JSON structure and numerical values
- Error Recovery: Implement retry logic with exponential backoff
- Resource Management: Close gRPC connections properly to avoid resource leaks
- Performance: For high-frequency updates, consider using the streaming methods instead
Current Limitations
- Historical Data: Timestamp parameter is not implemented; only current snapshots available
- Data Retention: Historical order book data is limited to a 24-hour rolling window
- Rate Limits: Be mindful of request frequency to avoid overwhelming the service
Need help? Contact our support team or check the Hyperliquid gRPC documentation.