StreamL2Book gRPC Method
이 방식은 데이터 사용량을 기준으로 0.0165 MB당 10 API 크레딧으로 과금된다는 점에 유의하시기 바랍니다.
매개변수
동전
문자열
로딩 중...
n_levels
uint32
로딩 중...
n_sig_figs
uint32
로딩 중...
mantissa
uint64
로딩 중...
반품
스트림
stream<L2BookUpdate>
로딩 중...
동전
문자열
로딩 중...
시간
uint64
로딩 중...
block_number
uint64
로딩 중...
bids
array<L2Level>
로딩 중...
asks
array<L2Level>
로딩 중...
요청
1// StreamL2Book Example - Stream aggregated orderbook data via gRPC2패키지 main34import (5"문맥"6"깃발"7"fmt"8"io"9"로그"10"수학"11"문자열"12"시간"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.초28)2930func streamL2Orderbook(coin string, nLevels uint32) error {31fmt.PrintlnPrintln문자열.반복("=", 60))32fmt.Printf("Streaming L2 Orderbook for %s\n", coin)33fmt.Printf("Levels: %d\n", nLevels)34fmt.PrintlnPrintln ("자동 재연결: true")35fmt.PrintlnPrintln문자열.반복("=", 60) + "\n")3637retryCount := 03839for retryCount < maxRetries {40creds := 인증 정보.NewClientTLSFromCert(nil, "")41conn, err := grpc.Dial(grpcEndpoint,42grpc.WithTransportCredentials(creds),43grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)))44만약 err != nil {45return fmt.Errorf("연결 실패: %w", err)46}4748클라이언트 := pb.NewOrderBookStreamingClient)(conn)49ctx := 메타데이터.AppendToOutgoingContext(컨텍스트.배경(), "x-token", authToken)5051request := &pb.L2BookRequest{52Coin: coin,53NLevels: nLevels,54}5556if retryCount > 0 {57fmt.Printf("\n🔄 재연결 중 (시도 %d/%d)...\n", retryCount+1, maxRetries)58} else {59fmt.Printf("%s에 연결 중...\n", printf("%s에 연결 중...\n",)60}6162stream, err := client.StreamL2Book(ctx, request)63만약 err != nil {64conn.닫기()65return fmt.Errorf("스트림 시작에 실패했습니다: %w", err)66}6768msgCount := 069shouldRetry := false7071~을 위해 {72업데이트, 오류 := 스트림.Recv()73만약 err == io.EOF {74중단75}76만약 err != nil {77st, 알겠습니다 := 상태.FromError(err)78만약 ok && st.코드() == 코드.DataLoss {79fmt.Printf("\n⚠️ 서버 재초기화됨: %s\n", st.메시지())80retryCount++81if retryCount < maxRetries {82지연 := 기본지연 * time.Duration(수학.Pow(2, float64(retryCount-1)))83fmt.Printf("⏳ 재연결하기 전 %v 동안 대기 중...\n", delay)84시간.수면(지연)85shouldRetry = true86중단87} else {88fmt.Printf("\n❌ 최대 재시도 횟수(%d)에 도달했습니다. 중단합니다.\n", maxRetries)89conn.닫기()90return nil91}92}93conn.닫기()94return fmt.Errorf("스트림 오류: %w", err)95}9697msgCount++98if msgCount == 1 {99fmt.Println("✓ First L2 update received!\n")100retryCount = 0 // 성공 시 재설정101}102103// Display orderbook104fmt.PrintlnPrintln ("\n" + strings.반복("─", 60))105fmt.Printf("Block: %d | Time: %d | Coin: %s\n", update.BlockNumber, update.Time, update.Coin)106fmt.PrintlnPrintln문자열.반복("─", 60))107108// Display asks (reversed)109if len(update.Asks) > 0 {110fmt.Println("\n ASKS:")111askCount := len(update.Asks)112if askCount > 10 {113askCount = 10114}115for i := askCount - 1; i >= 0; i-- {116level := update.Asks[i]117fmt.Printf(" %12s | %12s | (%d orders)\n", level.Px, level.Sz, level.N)118}119}120121// Display spread122if len(update.Bids) > 0 && len(update.Asks) > 0 {123fmt.Println("\n " + strings.Repeat("─", 44))124fmt.Printf(" SPREAD: (best bid: %s, best ask: %s)\n", update.Bids[0].Px, update.Asks[0].Px)125fmt.Println(" " + strings.Repeat("─", 44))126}127128// Display bids129if len(update.Bids) > 0 {130fmt.Println("\n BIDS:")131bidCount := len(update.Bids)132if bidCount > 10 {133bidCount = 10134}135for i := 0; i < bidCount; i++ {136level := update.Bids[i]137fmt.Printf(" %12s | %12s | (%d orders)\n", level.Px, level.Sz, level.N)138}139}140141fmt.Printf("\n 수신된 메시지: %d\n", msgCount)142}143144conn.닫기()145146만약 !shouldRetry {147중단148}149}150151return nil152}153154func main() {155coin := flag.String("coin", "BTC", "Coin symbol to stream")156levels := flag.Uint("levels", 20, "Number of price levels")157158깃발.구문 분석()159160fmt.PrintlnPrintln ("\n" + strings.반복("=", 60))161fmt.Println("Hyperliquid StreamL2Book Example")162fmt.Printf("엔드포인트: %s\n", grpcEndpoint)163fmt.PrintlnPrintln문자열.반복("=", 60))164165if err := streamL2Orderbook(*coin, uint32(*levels)); err != nil {166로그.치명적(err)167}168}169
1// StreamL2Book Example - Stream aggregated orderbook data via gRPC2패키지 main34import (5"문맥"6"깃발"7"fmt"8"io"9"로그"10"수학"11"문자열"12"시간"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.초28)2930func streamL2Orderbook(coin string, nLevels uint32) error {31fmt.PrintlnPrintln문자열.반복("=", 60))32fmt.Printf("Streaming L2 Orderbook for %s\n", coin)33fmt.Printf("Levels: %d\n", nLevels)34fmt.PrintlnPrintln ("자동 재연결: true")35fmt.PrintlnPrintln문자열.반복("=", 60) + "\n")3637retryCount := 03839for retryCount < maxRetries {40creds := 인증 정보.NewClientTLSFromCert(nil, "")41conn, err := grpc.Dial(grpcEndpoint,42grpc.WithTransportCredentials(creds),43grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)))44만약 err != nil {45return fmt.Errorf("연결 실패: %w", err)46}4748클라이언트 := pb.NewOrderBookStreamingClient)(conn)49ctx := 메타데이터.AppendToOutgoingContext(컨텍스트.배경(), "x-token", authToken)5051request := &pb.L2BookRequest{52Coin: coin,53NLevels: nLevels,54}5556if retryCount > 0 {57fmt.Printf("\n🔄 재연결 중 (시도 %d/%d)...\n", retryCount+1, maxRetries)58} else {59fmt.Printf("%s에 연결 중...\n", printf("%s에 연결 중...\n",)60}6162stream, err := client.StreamL2Book(ctx, request)63만약 err != nil {64conn.닫기()65return fmt.Errorf("스트림 시작에 실패했습니다: %w", err)66}6768msgCount := 069shouldRetry := false7071~을 위해 {72업데이트, 오류 := 스트림.Recv()73만약 err == io.EOF {74중단75}76만약 err != nil {77st, 알겠습니다 := 상태.FromError(err)78만약 ok && st.코드() == 코드.DataLoss {79fmt.Printf("\n⚠️ 서버 재초기화됨: %s\n", st.메시지())80retryCount++81if retryCount < maxRetries {82지연 := 기본지연 * time.Duration(수학.Pow(2, float64(retryCount-1)))83fmt.Printf("⏳ 재연결하기 전 %v 동안 대기 중...\n", delay)84시간.수면(지연)85shouldRetry = true86중단87} else {88fmt.Printf("\n❌ 최대 재시도 횟수(%d)에 도달했습니다. 중단합니다.\n", maxRetries)89conn.닫기()90return nil91}92}93conn.닫기()94return fmt.Errorf("스트림 오류: %w", err)95}9697msgCount++98if msgCount == 1 {99fmt.Println("✓ First L2 update received!\n")100retryCount = 0 // 성공 시 재설정101}102103// Display orderbook104fmt.PrintlnPrintln ("\n" + strings.반복("─", 60))105fmt.Printf("Block: %d | Time: %d | Coin: %s\n", update.BlockNumber, update.Time, update.Coin)106fmt.PrintlnPrintln문자열.반복("─", 60))107108// Display asks (reversed)109if len(update.Asks) > 0 {110fmt.Println("\n ASKS:")111askCount := len(update.Asks)112if askCount > 10 {113askCount = 10114}115for i := askCount - 1; i >= 0; i-- {116level := update.Asks[i]117fmt.Printf(" %12s | %12s | (%d orders)\n", level.Px, level.Sz, level.N)118}119}120121// Display spread122if len(update.Bids) > 0 && len(update.Asks) > 0 {123fmt.Println("\n " + strings.Repeat("─", 44))124fmt.Printf(" SPREAD: (best bid: %s, best ask: %s)\n", update.Bids[0].Px, update.Asks[0].Px)125fmt.Println(" " + strings.Repeat("─", 44))126}127128// Display bids129if len(update.Bids) > 0 {130fmt.Println("\n BIDS:")131bidCount := len(update.Bids)132if bidCount > 10 {133bidCount = 10134}135for i := 0; i < bidCount; i++ {136level := update.Bids[i]137fmt.Printf(" %12s | %12s | (%d orders)\n", level.Px, level.Sz, level.N)138}139}140141fmt.Printf("\n 수신된 메시지: %d\n", msgCount)142}143144conn.닫기()145146만약 !shouldRetry {147중단148}149}150151return nil152}153154func main() {155coin := flag.String("coin", "BTC", "Coin symbol to stream")156levels := flag.Uint("levels", 20, "Number of price levels")157158깃발.구문 분석()159160fmt.PrintlnPrintln ("\n" + strings.반복("=", 60))161fmt.Println("Hyperliquid StreamL2Book Example")162fmt.Printf("엔드포인트: %s\n", grpcEndpoint)163fmt.PrintlnPrintln문자열.반복("=", 60))164165if err := streamL2Orderbook(*coin, uint32(*levels)); err != nil {166로그.치명적(err)167}168}169
1// StreamL2Book Example - Stream aggregated orderbook data via gRPC2const grpc = require('@grpc/grpc-js');3const protoLoader = require('@grpc/proto-loader');4const path = require('path');56const GRPC_ENDPOINT = 'your-endpoint.hype-mainnet.quiknode.pro:10000';7const AUTH_TOKEN = 'your-auth-token';8const PROTO_PATH = path.join(__dirname, 'proto', 'orderbook.proto');910const 패키지 정의 = protoLoader.loadSync(PROTO_PATH, {11keepCase: true,12longs: String,13열거형: String,14기본값: true,15oneofs: true16});17const proto = grpc.loadPackageDefinition(packageDefinition).hyperliquid;1819함수 createClient() {20돌아가기 new proto.OrderBookStreaming((21GRPC_ENDPOINT,22grpc.인증 정보.createSsl(),23{ 'grpc.max_receive_message_length': 100 * 1024 * 1024 }24);25}2627// Stream L2 (aggregated) orderbook28async function streamL2Orderbook(coin, nLevels = 20, autoReconnect = true, retryCount = 0) {29콘솔.log('='.반복(60));30console.log(`Streaming L2 Orderbook for ${coin}`);31console.log(`Levels: ${nLevels}`);32console.log(`Auto-reconnect: ${autoReconnect}`);33콘솔.log('='.반복(60) + '\n');3435const maxRetries = 10;36const baseDelay = 2000;3738while (retryCount < maxRetries) {39const client = createClient();40const 메타데이터 = new grpc.메타데이터();41메타데이터.추가('x-token', AUTH_TOKEN);4243const request = {44coin: coin,45n_levels: nLevels46};4748시도해 보세요 {49만약 (retryCount > 0) {50console.log(`\n🔄 Reconnecting (attempt ${retryCount + 1}/${maxRetries})...`);51} else {52console.log(`Connecting to ${GRPC_ENDPOINT}...`);53}5455let msgCount = 0;56const call = client.StreamL2Book(request, metadata);5758호출.on('data', (업데이트) => {59msgCount++;6061만약 (msgCount === 1) {62console.log('✓ First L2 update received!\n');63retryCount = 0; // 성공 시 재설정64}6566콘솔.log('\n' + '─'.반복(60));67console.log(`Block: ${update.block_number} | Time: ${update.time} | Coin: ${update.coin}`);68콘솔.log('─'.반복(60));6970// Display asks (reversed for display)71if (update.asks && update.asks.length > 0) {72console.log('\n ASKS:');73update.asks.slice(0, 10).reverse().forEach(level => {74console.log(` ${level.px.padStart(12)} | ${level.sz.padStart(12)} | (${level.n} orders)`);75});76}7778// Display spread79if (update.bids && update.bids.length > 0 && update.asks && update.asks.length > 0) {80const bestBid = parseFloat(update.bids[0].px);81const bestAsk = parseFloat(update.asks[0].px);82const spread = bestAsk - bestBid;83const spreadBps = (spread / bestBid) * 10000;84console.log('\n ' + '─'.repeat(44));85console.log(` SPREAD: ${spread.toFixed(2)} (${spreadBps.toFixed(2)} bps)`);86console.log(' ' + '─'.repeat(44));87}8889// Display bids90if (update.bids && update.bids.length > 0) {91console.log('\n BIDS:');92update.bids.slice(0, 10).forEach(level => {93console.log(` ${level.px.padStart(12)} | ${level.sz.padStart(12)} | (${level.n} orders)`);94});95}9697console.log(`\n Messages received: ${msgCount}`);98});99100호출.on('error', (err) => {101만약 (err.코드 === grpc.상태.DATA_LOSS && autoReconnect) {102console.log(`\n⚠️ Server reinitialized: ${err.message}`);103retryCount++;104if (retryCount < maxRetries) {105const delay = baseDelay * Math.pow(2, retryCount - 1);106console.log(`⏳ Waiting ${delay / 1000}s before reconnecting...`);107setTimeout(() => streamL2Orderbook(coin, nLevels, autoReconnect, retryCount), delay);108} else {109console.log(`\n❌ Max retries (${maxRetries}) reached. Giving up.`);110}111} else {112콘솔.오류('\ngRPC 오류:', err.code, '-', err.메시지);113}114});115116호출.on('end', () => {117콘솔.log('\n스트림 종료됨');118});119120// Wait for stream to complete121기다리다 새로운 약속((결심) => {122호출.on('end', 해결);123호출.on('error', 해결);124});125126break; // 성공 시 재시도 루프 종료127128} catch (err) {129콘솔.오류('오류:', err.message);130break;131}132}133}134135// Parse command line args136const args = process.argv.slice(2);137const coin = args.find(a => a.startsWith('--coin='))?.split('=')[1] || 'BTC';138const levels = parseInt(args.find(a => a.startsWith('--levels='))?.split('=')[1]) || 20;139140콘솔.log('\n' + '='.반복(60));141console.log('Hyperliquid StreamL2Book Example');142console.log(`Endpoint: ${GRPC_ENDPOINT}`);143콘솔.log('='.반복(60));144145streamL2Orderbook(coin, levels);146
1// StreamL2Book Example - Stream aggregated orderbook data via gRPC2const grpc = require('@grpc/grpc-js');3const protoLoader = require('@grpc/proto-loader');4const path = require('path');56const GRPC_ENDPOINT = 'your-endpoint.hype-mainnet.quiknode.pro:10000';7const AUTH_TOKEN = 'your-auth-token';8const PROTO_PATH = path.join(__dirname, 'proto', 'orderbook.proto');910const 패키지 정의 = protoLoader.loadSync(PROTO_PATH, {11keepCase: true,12longs: String,13열거형: String,14기본값: true,15oneofs: true16});17const proto = grpc.loadPackageDefinition(packageDefinition).hyperliquid;1819함수 createClient() {20돌아가기 new proto.OrderBookStreaming((21GRPC_ENDPOINT,22grpc.인증 정보.createSsl(),23{ 'grpc.max_receive_message_length': 100 * 1024 * 1024 }24);25}2627// Stream L2 (aggregated) orderbook28async function streamL2Orderbook(coin, nLevels = 20, autoReconnect = true, retryCount = 0) {29콘솔.log('='.반복(60));30console.log(`Streaming L2 Orderbook for ${coin}`);31console.log(`Levels: ${nLevels}`);32console.log(`Auto-reconnect: ${autoReconnect}`);33콘솔.log('='.반복(60) + '\n');3435const maxRetries = 10;36const baseDelay = 2000;3738while (retryCount < maxRetries) {39const client = createClient();40const 메타데이터 = new grpc.메타데이터();41메타데이터.추가('x-token', AUTH_TOKEN);4243const request = {44coin: coin,45n_levels: nLevels46};4748시도해 보세요 {49만약 (retryCount > 0) {50console.log(`\n🔄 Reconnecting (attempt ${retryCount + 1}/${maxRetries})...`);51} else {52console.log(`Connecting to ${GRPC_ENDPOINT}...`);53}5455let msgCount = 0;56const call = client.StreamL2Book(request, metadata);5758호출.on('data', (업데이트) => {59msgCount++;6061만약 (msgCount === 1) {62console.log('✓ First L2 update received!\n');63retryCount = 0; // 성공 시 재설정64}6566콘솔.log('\n' + '─'.반복(60));67console.log(`Block: ${update.block_number} | Time: ${update.time} | Coin: ${update.coin}`);68콘솔.log('─'.반복(60));6970// Display asks (reversed for display)71if (update.asks && update.asks.length > 0) {72console.log('\n ASKS:');73update.asks.slice(0, 10).reverse().forEach(level => {74console.log(` ${level.px.padStart(12)} | ${level.sz.padStart(12)} | (${level.n} orders)`);75});76}7778// Display spread79if (update.bids && update.bids.length > 0 && update.asks && update.asks.length > 0) {80const bestBid = parseFloat(update.bids[0].px);81const bestAsk = parseFloat(update.asks[0].px);82const spread = bestAsk - bestBid;83const spreadBps = (spread / bestBid) * 10000;84console.log('\n ' + '─'.repeat(44));85console.log(` SPREAD: ${spread.toFixed(2)} (${spreadBps.toFixed(2)} bps)`);86console.log(' ' + '─'.repeat(44));87}8889// Display bids90if (update.bids && update.bids.length > 0) {91console.log('\n BIDS:');92update.bids.slice(0, 10).forEach(level => {93console.log(` ${level.px.padStart(12)} | ${level.sz.padStart(12)} | (${level.n} orders)`);94});95}9697console.log(`\n Messages received: ${msgCount}`);98});99100호출.on('error', (err) => {101만약 (err.코드 === grpc.상태.DATA_LOSS && autoReconnect) {102console.log(`\n⚠️ Server reinitialized: ${err.message}`);103retryCount++;104if (retryCount < maxRetries) {105const delay = baseDelay * Math.pow(2, retryCount - 1);106console.log(`⏳ Waiting ${delay / 1000}s before reconnecting...`);107setTimeout(() => streamL2Orderbook(coin, nLevels, autoReconnect, retryCount), delay);108} else {109console.log(`\n❌ Max retries (${maxRetries}) reached. Giving up.`);110}111} else {112콘솔.오류('\ngRPC 오류:', err.code, '-', err.메시지);113}114});115116호출.on('end', () => {117콘솔.log('\n스트림 종료됨');118});119120// Wait for stream to complete121기다리다 새로운 약속((결심) => {122호출.on('end', 해결);123호출.on('error', 해결);124});125126break; // 성공 시 재시도 루프 종료127128} catch (err) {129콘솔.오류('오류:', err.message);130break;131}132}133}134135// Parse command line args136const args = process.argv.slice(2);137const coin = args.find(a => a.startsWith('--coin='))?.split('=')[1] || 'BTC';138const levels = parseInt(args.find(a => a.startsWith('--levels='))?.split('=')[1]) || 20;139140콘솔.log('\n' + '='.반복(60));141console.log('Hyperliquid StreamL2Book Example');142console.log(`Endpoint: ${GRPC_ENDPOINT}`);143콘솔.log('='.반복(60));144145streamL2Orderbook(coin, levels);146
1#!/usr/bin/env python32"""3StreamL2Book Example - Stream aggregated orderbook data via gRPC45설정:6pip install grpcio grpcio-tools protobuf zstandard7python -m grpc_tools.protoc -I../../proto --python_out=. --grpc_python_out=. ../../proto/orderbook.proto89사용법:10python stream_l2_example.py --coin BTC --levels 2011"""1213import grpc14import sys15import 시간16import argparse17from typing import Optional1819시도해 보세요:20import orderbook_pb2 다음과 같이 pb21import orderbook_pb2_grpc 다음과 같이 pb_grpc22except ImportError:23인쇄("오류: Proto 파일이 생성되지 않았습니다. 다음을 실행하십시오:")24인쇄(" python -m grpc_tools.protoc -I../../proto --python_out=. --grpc_python_out=. ../../proto/orderbook.proto")25sys.exit(1)2627# 구성28GRPC_ENDPOINT = "your-endpoint.hype-mainnet.quiknode.pro:10000"29AUTH_TOKEN = "your-auth-token"303132def stream_l2_orderbook(coin: str, n_levels: int = 20, n_sig_figs: Optional[int] = None, mantissa: Optional[int] = None, auto_reconnect: bool = True):33"""34Stream L2 (aggregated) orderbook updates for a coin.3536인수:37coin: Symbol to stream (e.g., "BTC", "ETH")38n_levels: Number of price levels to display (default 20, max 100)39n_sig_figs: Significance figures for price bucketing (2-5)40mantissa: Mantissa for bucketing (1, 2, or 5)41auto_reconnect: DATA_LOSS 오류 발생 시 자동 재연결 (기본값: True)42"""43인쇄(f"\n{'='*60}")44print(f"Streaming L2 Orderbook for {coin}")45print(f"Levels: {n_levels}")46print(f"Auto-reconnect: {auto_reconnect}")47인쇄(f"{'='*60}\n")4849retry_count = 050max_retries = 1051base_delay = 25253while retry_count < max_retries:54채널 = grpc.secure_channel(55GRPC_ENDPOINT,56grpc.ssl_channel_credentials(),57옵션=[58('grpc.max_receive_message_length', 100 * 1024 * 1024),59('grpc.keepalive_time_ms', 30000),60]61)62스텁 = pb_grpc.OrderBookStreamingStub(채널)6364# 빌드 요청65request = pb.L2BookRequest(66coin=coin,67n_levels=n_levels68)69if n_sig_figs is not None:70request.n_sig_figs = n_sig_figs71if mantissa is not None:72request.mantissa = mantissa7374msg_count = 07576시도해 보세요:77if retry_count > 0:78인쇄(f"\n🔄 다시 연결 중 (시도 중 {재시도 횟수 + 1}/{최대 재시도 횟수})...")79else:80인쇄(f"연결 중 {GRPC_ENDPOINT}...")8182for update in stub.StreamL2Book(request, metadata=[('x-token', AUTH_TOKEN)]):83msg_count += 18485if msg_count == 1:86print(f"✓ First L2 update received!\n")87retry_count = 0 # 연결에 성공하면 재시도 횟수를 초기화합니다8889# Display the L2 orderbook90인쇄(f"\n{'─'*60}")91print(f"Block: {update.block_number} | Time: {update.time} | Coin: {update.coin}")92인쇄(f"{'─'*60}")9394# Show asks (sorted highest to lowest for display)95if update.asks:96print("\n ASKS:")97for level in reversed(list(update.asks[:10])): # Top 10 asks98print(f" {level.px:>12} | {level.sz:>12} | ({level.n} orders)")99100# Show spread101if update.bids and update.asks:102best_bid = float(update.bids[0].px) if update.bids else 0103best_ask = float(update.asks[0].px) if update.asks else 0104if best_bid and best_ask:105spread = best_ask - best_bid106spread_bps = (spread / best_bid) * 10000 if best_bid > 0 else 0107print(f"\n {'─'*44}")108print(f" SPREAD: {spread:.2f} ({spread_bps:.2f} bps)")109print(f" {'─'*44}")110111# Show bids112if update.bids:113print("\n BIDS:")114for level in update.bids[:10]: # Top 10 bids115print(f" {level.px:>12} | {level.sz:>12} | ({level.n} orders)")116117print(f"\n Messages received: {msg_count}")118119단, grpc.RpcError 를 e:120만약 e.코드() == grpc.StatusCode.DATA_LOSS 및 auto_reconnect:121print(f"\n⚠️ Server reinitialized: {e.details()}")122retry_count += 1123if retry_count < max_retries:124지연 = 기본_지연 * (2 ** (retry_count - 1)) # 지수적 백오프125인쇄(f"⏳ 대기 중 {지연}초 후 재연결됩니다...")126시간.sleep(지연)127채널.닫기()128계속129else:130인쇄(f"\n❌ 최대 재시도 횟수 ({max_retries})에 도달했습니다. 중단합니다.")131중단132else:133print(f"\ngRPC error: {e.code()} - {e.details()}")134중단135단, KeyboardInterrupt:136print("\nStopping L2 stream...")137중단138드디어:139채널.닫기()140141# 오류 없이 여기까지 도달했다면, 재시도 루프를 종료한다142중단143144145def main():146parser = argparse.ArgumentParser(description='Stream Hyperliquid L2 orderbook data via gRPC')147parser.add_argument('--coin', default='BTC', help='Coin symbol to stream')148parser.add_argument('--levels', type=int, default=20, help='Number of price levels (default: 20, max: 100)')149parser.add_argument('--sig-figs', type=int, default=None, help='Significance figures for bucketing (2-5)')150parser.add_argument('--mantissa', type=int, default=None, help='Mantissa for bucketing (1, 2, or 5)')151152args = parser.parse_args()153154인쇄(f"\n{'='*60}")155print("Hyperliquid StreamL2Book Example")156print(f"Endpoint: {GRPC_ENDPOINT}")157인쇄(f"{'='*60}")158159시도해 보세요:160stream_l2_orderbook(args.coin, n_levels=args.levels, n_sig_figs=args.sig_figs, mantissa=args.mantissa)161단, 예외 ~처럼 e:162print(f"\nError: {e}")163import 트레이스백164트레이스백.print_exc()165sys.exit(1)166167168if __name__ == "__main__":169main()170
1#!/usr/bin/env python32"""3StreamL2Book Example - Stream aggregated orderbook data via gRPC45설정:6pip install grpcio grpcio-tools protobuf zstandard7python -m grpc_tools.protoc -I../../proto --python_out=. --grpc_python_out=. ../../proto/orderbook.proto89사용법:10python stream_l2_example.py --coin BTC --levels 2011"""1213import grpc14import sys15import 시간16import argparse17from typing import Optional1819시도해 보세요:20import orderbook_pb2 다음과 같이 pb21import orderbook_pb2_grpc 다음과 같이 pb_grpc22except ImportError:23인쇄("오류: Proto 파일이 생성되지 않았습니다. 다음을 실행하십시오:")24인쇄(" python -m grpc_tools.protoc -I../../proto --python_out=. --grpc_python_out=. ../../proto/orderbook.proto")25sys.exit(1)2627# 구성28GRPC_ENDPOINT = "your-endpoint.hype-mainnet.quiknode.pro:10000"29AUTH_TOKEN = "your-auth-token"303132def stream_l2_orderbook(coin: str, n_levels: int = 20, n_sig_figs: Optional[int] = None, mantissa: Optional[int] = None, auto_reconnect: bool = True):33"""34Stream L2 (aggregated) orderbook updates for a coin.3536인수:37coin: Symbol to stream (e.g., "BTC", "ETH")38n_levels: Number of price levels to display (default 20, max 100)39n_sig_figs: Significance figures for price bucketing (2-5)40mantissa: Mantissa for bucketing (1, 2, or 5)41auto_reconnect: DATA_LOSS 오류 발생 시 자동 재연결 (기본값: True)42"""43인쇄(f"\n{'='*60}")44print(f"Streaming L2 Orderbook for {coin}")45print(f"Levels: {n_levels}")46print(f"Auto-reconnect: {auto_reconnect}")47인쇄(f"{'='*60}\n")4849retry_count = 050max_retries = 1051base_delay = 25253while retry_count < max_retries:54채널 = grpc.secure_channel(55GRPC_ENDPOINT,56grpc.ssl_channel_credentials(),57옵션=[58('grpc.max_receive_message_length', 100 * 1024 * 1024),59('grpc.keepalive_time_ms', 30000),60]61)62스텁 = pb_grpc.OrderBookStreamingStub(채널)6364# 빌드 요청65request = pb.L2BookRequest(66coin=coin,67n_levels=n_levels68)69if n_sig_figs is not None:70request.n_sig_figs = n_sig_figs71if mantissa is not None:72request.mantissa = mantissa7374msg_count = 07576시도해 보세요:77if retry_count > 0:78인쇄(f"\n🔄 다시 연결 중 (시도 중 {재시도 횟수 + 1}/{최대 재시도 횟수})...")79else:80인쇄(f"연결 중 {GRPC_ENDPOINT}...")8182for update in stub.StreamL2Book(request, metadata=[('x-token', AUTH_TOKEN)]):83msg_count += 18485if msg_count == 1:86print(f"✓ First L2 update received!\n")87retry_count = 0 # 연결에 성공하면 재시도 횟수를 초기화합니다8889# Display the L2 orderbook90인쇄(f"\n{'─'*60}")91print(f"Block: {update.block_number} | Time: {update.time} | Coin: {update.coin}")92인쇄(f"{'─'*60}")9394# Show asks (sorted highest to lowest for display)95if update.asks:96print("\n ASKS:")97for level in reversed(list(update.asks[:10])): # Top 10 asks98print(f" {level.px:>12} | {level.sz:>12} | ({level.n} orders)")99100# Show spread101if update.bids and update.asks:102best_bid = float(update.bids[0].px) if update.bids else 0103best_ask = float(update.asks[0].px) if update.asks else 0104if best_bid and best_ask:105spread = best_ask - best_bid106spread_bps = (spread / best_bid) * 10000 if best_bid > 0 else 0107print(f"\n {'─'*44}")108print(f" SPREAD: {spread:.2f} ({spread_bps:.2f} bps)")109print(f" {'─'*44}")110111# Show bids112if update.bids:113print("\n BIDS:")114for level in update.bids[:10]: # Top 10 bids115print(f" {level.px:>12} | {level.sz:>12} | ({level.n} orders)")116117print(f"\n Messages received: {msg_count}")118119단, grpc.RpcError 를 e:120만약 e.코드() == grpc.StatusCode.DATA_LOSS 및 auto_reconnect:121print(f"\n⚠️ Server reinitialized: {e.details()}")122retry_count += 1123if retry_count < max_retries:124지연 = 기본_지연 * (2 ** (retry_count - 1)) # 지수적 백오프125인쇄(f"⏳ 대기 중 {지연}초 후 재연결됩니다...")126시간.sleep(지연)127채널.닫기()128계속129else:130인쇄(f"\n❌ 최대 재시도 횟수 ({max_retries})에 도달했습니다. 중단합니다.")131중단132else:133print(f"\ngRPC error: {e.code()} - {e.details()}")134중단135단, KeyboardInterrupt:136print("\nStopping L2 stream...")137중단138드디어:139채널.닫기()140141# 오류 없이 여기까지 도달했다면, 재시도 루프를 종료한다142중단143144145def main():146parser = argparse.ArgumentParser(description='Stream Hyperliquid L2 orderbook data via gRPC')147parser.add_argument('--coin', default='BTC', help='Coin symbol to stream')148parser.add_argument('--levels', type=int, default=20, help='Number of price levels (default: 20, max: 100)')149parser.add_argument('--sig-figs', type=int, default=None, help='Significance figures for bucketing (2-5)')150parser.add_argument('--mantissa', type=int, default=None, help='Mantissa for bucketing (1, 2, or 5)')151152args = parser.parse_args()153154인쇄(f"\n{'='*60}")155print("Hyperliquid StreamL2Book Example")156print(f"Endpoint: {GRPC_ENDPOINT}")157인쇄(f"{'='*60}")158159시도해 보세요:160stream_l2_orderbook(args.coin, n_levels=args.levels, n_sig_figs=args.sig_figs, mantissa=args.mantissa)161단, 예외 ~처럼 e:162print(f"\nError: {e}")163import 트레이스백164트레이스백.print_exc()165sys.exit(1)166167168if __name__ == "__main__":169main()170