StreamL4Book gRPC Method
이 방식은 데이터 사용량을 기준으로 0.0165 MB당 10 API 크레딧으로 과금된다는 점에 유의하시기 바랍니다.
매개변수
동전
문자열
로딩 중...
반품
스트림
stream<L4BookUpdate>
로딩 중...
스냅샷
L4BookSnapshot
로딩 중...
diff
L4BookDiff
로딩 중...
요청
1// StreamL4Book Example - Stream individual order data via gRPC2패키지 main34import (5"문맥"6"encoding/json"7"깃발"8"fmt"9"io"10"로그"11"수학"12"문자열"13"시간"1415"google.golang.org/grpc"16"google.golang.org/grpc/codes"17"google.golang.org/grpc/credentials"18"google.golang.org/grpc/metadata"19"google.golang.org/grpc/status"2021pb "hyperliquid-orderbook-example/proto"22)2324const (25grpcEndpoint = "your-endpoint.hype-mainnet.quiknode.pro:10000"26authToken = "your-auth-token"27maxRetries = 1028baseDelay = 2 * time.초29)3031func streamL4Orderbook(coin string, maxMessages int) error {32fmt.PrintlnPrintln문자열.반복("=", 60))33fmt.Printf("Streaming L4 Orderbook for %s\n", coin)34fmt.PrintlnPrintln ("자동 재연결: true")35fmt.PrintlnPrintln문자열.반복("=", 60) + "\n")3637retryCount := 038totalMsgCount := 03940for retryCount < maxRetries {41creds := 인증 정보.NewClientTLSFromCert(nil, "")42conn, err := grpc.Dial(grpcEndpoint,43grpc.WithTransportCredentials(creds),44grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)))45만약 err != nil {46return fmt.Errorf("연결 실패: %w", err)47}4849클라이언트 := pb.NewOrderBookStreamingClient)(conn)50ctx := 메타데이터.AppendToOutgoingContext(컨텍스트.배경(), "x-token", authToken)5152request := &pb.L4BookRequest{53Coin: coin,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.StreamL4Book(ctx, request)63만약 err != nil {64conn.닫기()65return fmt.Errorf("스트림 시작에 실패했습니다: %w", err)66}6768snapshotReceived := false69shouldRetry := 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}9697totalMsgCount++9899if snapshot := update.GetSnapshot(); snapshot != nil {100snapshotReceived = true101retryCount = 0 // 성공 시 재설정102103fmt.Println("\n✓ L4 Snapshot Received!")104fmt.Println(strings.Repeat("─", 60))105fmt.Printf("Coin: %s\n", snapshot.Coin)106fmt.Printf("Height: %d\n", snapshot.Height)107fmt.Printf("Time: %d\n", snapshot.Time)108fmt.Printf("Bids: %d orders\n", len(snapshot.Bids))109fmt.Printf("Asks: %d orders\n", len(snapshot.Asks))110fmt.Println(strings.Repeat("─", 60))111112// Sample bids113if len(snapshot.Bids) > 0 {114fmt.Println("\nSample Bids (first 5):")115bidCount := len(snapshot.Bids)116if bidCount > 5 {117bidCount = 5118}119for i := 0; i < bidCount; i++ {120order := snapshot.Bids[i]121userShort := order.User122if len(userShort) > 10 {123userShort = userShort[:10] + "..."124}125fmt.Printf(" OID: %d | Price: %s | Size: %s | User: %s\n",126order.Oid, order.LimitPx, order.Sz, userShort)127}128}129130// Sample asks131if len(snapshot.Asks) > 0 {132fmt.Println("\nSample Asks (first 5):")133askCount := len(snapshot.Asks)134if askCount > 5 {135askCount = 5136}137for i := 0; i < askCount; i++ {138order := snapshot.Asks[i]139userShort := order.User140if len(userShort) > 10 {141userShort = userShort[:10] + "..."142}143fmt.Printf(" OID: %d | Price: %s | Size: %s | User: %s\n",144order.Oid, order.LimitPx, order.Sz, userShort)145}146}147148} else if diff := update.GetDiff(); diff != nil {149if !snapshotReceived {150fmt.Println("\n⚠ Received diff before snapshot")151}152153var diffData map[string]interface{}154if err := json.Unmarshal([]byte(diff.Data), &diffData); err == nil {155orderStatuses := []interface{}{}156bookDiffs := []interface{}{}157158if os, ok := diffData["order_statuses"].([]interface{}); ok {159orderStatuses = os160}161if bd, ok := diffData["book_diffs"].([]interface{}); ok {162bookDiffs = bd163}164165fmt.Printf("\n[Block %d] L4 Diff:\n", diff.Height)166fmt.Printf(" Time: %d\n", diff.Time)167fmt.Printf(" Order Statuses: %d\n", len(orderStatuses))168fmt.Printf(" Book Diffs: %d\n", len(bookDiffs))169170if len(bookDiffs) > 0 && len(bookDiffs) <= 5 {171pretty, _ := json.MarshalIndent(bookDiffs, " ", " ")172fmt.Printf(" Diffs: %s\n", pretty)173}174}175}176177if maxMessages > 0 && totalMsgCount >= maxMessages {178fmt.Printf("\nReached max messages (%d), stopping...\n", maxMessages)179conn.닫기()180return nil181}182}183184conn.닫기()185186만약 !shouldRetry {187중단188}189}190191return nil192}193194func main() {195coin := flag.String("coin", "BTC", "Coin symbol to stream")196maxMessages := flag.Int("max-messages", 0, "Maximum messages (0 = unlimited)")197198깃발.구문 분석()199200fmt.PrintlnPrintln ("\n" + strings.반복("=", 60))201fmt.Println("Hyperliquid StreamL4Book Example")202fmt.Printf("엔드포인트: %s\n", grpcEndpoint)203fmt.PrintlnPrintln문자열.반복("=", 60))204205if err := streamL4Orderbook(*coin, *maxMessages); err != nil {206로그.치명적(err)207}208}209
1// StreamL4Book Example - Stream individual order data via gRPC2패키지 main34import (5"문맥"6"encoding/json"7"깃발"8"fmt"9"io"10"로그"11"수학"12"문자열"13"시간"1415"google.golang.org/grpc"16"google.golang.org/grpc/codes"17"google.golang.org/grpc/credentials"18"google.golang.org/grpc/metadata"19"google.golang.org/grpc/status"2021pb "hyperliquid-orderbook-example/proto"22)2324const (25grpcEndpoint = "your-endpoint.hype-mainnet.quiknode.pro:10000"26authToken = "your-auth-token"27maxRetries = 1028baseDelay = 2 * time.초29)3031func streamL4Orderbook(coin string, maxMessages int) error {32fmt.PrintlnPrintln문자열.반복("=", 60))33fmt.Printf("Streaming L4 Orderbook for %s\n", coin)34fmt.PrintlnPrintln ("자동 재연결: true")35fmt.PrintlnPrintln문자열.반복("=", 60) + "\n")3637retryCount := 038totalMsgCount := 03940for retryCount < maxRetries {41creds := 인증 정보.NewClientTLSFromCert(nil, "")42conn, err := grpc.Dial(grpcEndpoint,43grpc.WithTransportCredentials(creds),44grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)))45만약 err != nil {46return fmt.Errorf("연결 실패: %w", err)47}4849클라이언트 := pb.NewOrderBookStreamingClient)(conn)50ctx := 메타데이터.AppendToOutgoingContext(컨텍스트.배경(), "x-token", authToken)5152request := &pb.L4BookRequest{53Coin: coin,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.StreamL4Book(ctx, request)63만약 err != nil {64conn.닫기()65return fmt.Errorf("스트림 시작에 실패했습니다: %w", err)66}6768snapshotReceived := false69shouldRetry := 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}9697totalMsgCount++9899if snapshot := update.GetSnapshot(); snapshot != nil {100snapshotReceived = true101retryCount = 0 // 성공 시 재설정102103fmt.Println("\n✓ L4 Snapshot Received!")104fmt.Println(strings.Repeat("─", 60))105fmt.Printf("Coin: %s\n", snapshot.Coin)106fmt.Printf("Height: %d\n", snapshot.Height)107fmt.Printf("Time: %d\n", snapshot.Time)108fmt.Printf("Bids: %d orders\n", len(snapshot.Bids))109fmt.Printf("Asks: %d orders\n", len(snapshot.Asks))110fmt.Println(strings.Repeat("─", 60))111112// Sample bids113if len(snapshot.Bids) > 0 {114fmt.Println("\nSample Bids (first 5):")115bidCount := len(snapshot.Bids)116if bidCount > 5 {117bidCount = 5118}119for i := 0; i < bidCount; i++ {120order := snapshot.Bids[i]121userShort := order.User122if len(userShort) > 10 {123userShort = userShort[:10] + "..."124}125fmt.Printf(" OID: %d | Price: %s | Size: %s | User: %s\n",126order.Oid, order.LimitPx, order.Sz, userShort)127}128}129130// Sample asks131if len(snapshot.Asks) > 0 {132fmt.Println("\nSample Asks (first 5):")133askCount := len(snapshot.Asks)134if askCount > 5 {135askCount = 5136}137for i := 0; i < askCount; i++ {138order := snapshot.Asks[i]139userShort := order.User140if len(userShort) > 10 {141userShort = userShort[:10] + "..."142}143fmt.Printf(" OID: %d | Price: %s | Size: %s | User: %s\n",144order.Oid, order.LimitPx, order.Sz, userShort)145}146}147148} else if diff := update.GetDiff(); diff != nil {149if !snapshotReceived {150fmt.Println("\n⚠ Received diff before snapshot")151}152153var diffData map[string]interface{}154if err := json.Unmarshal([]byte(diff.Data), &diffData); err == nil {155orderStatuses := []interface{}{}156bookDiffs := []interface{}{}157158if os, ok := diffData["order_statuses"].([]interface{}); ok {159orderStatuses = os160}161if bd, ok := diffData["book_diffs"].([]interface{}); ok {162bookDiffs = bd163}164165fmt.Printf("\n[Block %d] L4 Diff:\n", diff.Height)166fmt.Printf(" Time: %d\n", diff.Time)167fmt.Printf(" Order Statuses: %d\n", len(orderStatuses))168fmt.Printf(" Book Diffs: %d\n", len(bookDiffs))169170if len(bookDiffs) > 0 && len(bookDiffs) <= 5 {171pretty, _ := json.MarshalIndent(bookDiffs, " ", " ")172fmt.Printf(" Diffs: %s\n", pretty)173}174}175}176177if maxMessages > 0 && totalMsgCount >= maxMessages {178fmt.Printf("\nReached max messages (%d), stopping...\n", maxMessages)179conn.닫기()180return nil181}182}183184conn.닫기()185186만약 !shouldRetry {187중단188}189}190191return nil192}193194func main() {195coin := flag.String("coin", "BTC", "Coin symbol to stream")196maxMessages := flag.Int("max-messages", 0, "Maximum messages (0 = unlimited)")197198깃발.구문 분석()199200fmt.PrintlnPrintln ("\n" + strings.반복("=", 60))201fmt.Println("Hyperliquid StreamL4Book Example")202fmt.Printf("엔드포인트: %s\n", grpcEndpoint)203fmt.PrintlnPrintln문자열.반복("=", 60))204205if err := streamL4Orderbook(*coin, *maxMessages); err != nil {206로그.치명적(err)207}208}209
1// StreamL4Book Example - Stream individual order 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 L4 (individual orders) orderbook28async function streamL4Orderbook(coin, maxMessages = null, autoReconnect = true, retryCount = 0) {29콘솔.log('='.반복(60));30console.log(`Streaming L4 Orderbook for ${coin}`);31console.log(`Auto-reconnect: ${autoReconnect}`);32콘솔.log('='.반복(60) + '\n');3334const maxRetries = 10;35const baseDelay = 2000;36let totalMsgCount = 0;3738while (retryCount < maxRetries) {39const client = createClient();40const 메타데이터 = new grpc.메타데이터();41메타데이터.추가('x-token', AUTH_TOKEN);4243const request = { coin: coin };4445시도해 보세요 {46만약 (retryCount > 0) {47console.log(`\n🔄 Reconnecting (attempt ${retryCount + 1}/${maxRetries})...`);48} else {49console.log(`Connecting to ${GRPC_ENDPOINT}...`);50}5152let snapshotReceived = false;53const call = client.StreamL4Book(request, metadata);5455호출.on('data', (업데이트) => {56totalMsgCount++;5758if (update.snapshot) {59const snapshot = update.snapshot;60snapshotReceived = true;61retryCount = 0; // 성공 시 재설정6263console.log('\n✓ L4 Snapshot Received!');64console.log('─'.repeat(60));65console.log(`Coin: ${snapshot.coin}`);66console.log(`Height: ${snapshot.height}`);67console.log(`Time: ${snapshot.time}`);68console.log(`Bids: ${snapshot.bids.length} orders`);69console.log(`Asks: ${snapshot.asks.length} orders`);70console.log('─'.repeat(60));7172// Sample bids73if (snapshot.bids.length > 0) {74console.log('\nSample Bids (first 5):');75snapshot.bids.slice(0, 5).forEach(order => {76console.log(` OID: ${order.oid} | Price: ${order.limit_px} | Size: ${order.sz} | User: ${order.user.substring(0, 10)}...`);77});78}7980// Sample asks81if (snapshot.asks.length > 0) {82console.log('\nSample Asks (first 5):');83snapshot.asks.slice(0, 5).forEach(order => {84console.log(` OID: ${order.oid} | Price: ${order.limit_px} | Size: ${order.sz} | User: ${order.user.substring(0, 10)}...`);85});86}8788} else if (update.diff) {89const diff = update.diff;9091if (!snapshotReceived) {92console.log('\n⚠ Received diff before snapshot');93}9495try {96const diffData = JSON.parse(diff.data);97const orderStatuses = diffData.order_statuses || [];98const bookDiffs = diffData.book_diffs || [];99100console.log(`\n[Block ${diff.height}] L4 Diff:`);101console.log(` Time: ${diff.time}`);102console.log(` Order Statuses: ${orderStatuses.length}`);103console.log(` Book Diffs: ${bookDiffs.length}`);104105if (bookDiffs.length > 0 && bookDiffs.length <= 5) {106console.log(` Diffs: ${JSON.stringify(bookDiffs, null, 2)}`);107}108} catch (e) {109console.log(` Error parsing diff: ${e.message}`);110}111}112113if (maxMessages && totalMsgCount >= maxMessages) {114console.log(`\nReached max messages (${maxMessages}), stopping...`);115call.cancel();116}117});118119호출.on('error', (err) => {120만약 (err.코드 === grpc.상태.DATA_LOSS && autoReconnect) {121console.log(`\n⚠️ Server reinitialized: ${err.message}`);122retryCount++;123if (retryCount < maxRetries) {124const delay = baseDelay * Math.pow(2, retryCount - 1);125console.log(`⏳ Waiting ${delay / 1000}s before reconnecting...`);126setTimeout(() => streamL4Orderbook(coin, maxMessages, autoReconnect, retryCount), delay);127} else {128console.log(`\n❌ Max retries (${maxRetries}) reached. Giving up.`);129}130} else if (err.code !== grpc.status.CANCELLED) {131콘솔.오류('\ngRPC 오류:', err.code, '-', err.메시지);132}133});134135호출.on('end', () => {136콘솔.log('\n스트림 종료됨');137});138139// Wait for stream to complete140기다리다 새로운 약속((결심) => {141호출.on('end', 해결);142호출.on('error', 해결);143});144145break; // 성공 시 재시도 루프 종료146147} catch (err) {148콘솔.오류('오류:', err.message);149break;150}151}152}153154// Parse command line args155const args = process.argv.slice(2);156const coin = args.find(a => a.startsWith('--coin='))?.split('=')[1] || 'BTC';157const maxMessages = parseInt(args.find(a => a.startsWith('--max-messages='))?.split('=')[1]) || null;158159콘솔.log('\n' + '='.반복(60));160console.log('Hyperliquid StreamL4Book Example');161console.log(`Endpoint: ${GRPC_ENDPOINT}`);162콘솔.log('='.반복(60));163164streamL4Orderbook(coin, maxMessages);165
1// StreamL4Book Example - Stream individual order 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 L4 (individual orders) orderbook28async function streamL4Orderbook(coin, maxMessages = null, autoReconnect = true, retryCount = 0) {29콘솔.log('='.반복(60));30console.log(`Streaming L4 Orderbook for ${coin}`);31console.log(`Auto-reconnect: ${autoReconnect}`);32콘솔.log('='.반복(60) + '\n');3334const maxRetries = 10;35const baseDelay = 2000;36let totalMsgCount = 0;3738while (retryCount < maxRetries) {39const client = createClient();40const 메타데이터 = new grpc.메타데이터();41메타데이터.추가('x-token', AUTH_TOKEN);4243const request = { coin: coin };4445시도해 보세요 {46만약 (retryCount > 0) {47console.log(`\n🔄 Reconnecting (attempt ${retryCount + 1}/${maxRetries})...`);48} else {49console.log(`Connecting to ${GRPC_ENDPOINT}...`);50}5152let snapshotReceived = false;53const call = client.StreamL4Book(request, metadata);5455호출.on('data', (업데이트) => {56totalMsgCount++;5758if (update.snapshot) {59const snapshot = update.snapshot;60snapshotReceived = true;61retryCount = 0; // 성공 시 재설정6263console.log('\n✓ L4 Snapshot Received!');64console.log('─'.repeat(60));65console.log(`Coin: ${snapshot.coin}`);66console.log(`Height: ${snapshot.height}`);67console.log(`Time: ${snapshot.time}`);68console.log(`Bids: ${snapshot.bids.length} orders`);69console.log(`Asks: ${snapshot.asks.length} orders`);70console.log('─'.repeat(60));7172// Sample bids73if (snapshot.bids.length > 0) {74console.log('\nSample Bids (first 5):');75snapshot.bids.slice(0, 5).forEach(order => {76console.log(` OID: ${order.oid} | Price: ${order.limit_px} | Size: ${order.sz} | User: ${order.user.substring(0, 10)}...`);77});78}7980// Sample asks81if (snapshot.asks.length > 0) {82console.log('\nSample Asks (first 5):');83snapshot.asks.slice(0, 5).forEach(order => {84console.log(` OID: ${order.oid} | Price: ${order.limit_px} | Size: ${order.sz} | User: ${order.user.substring(0, 10)}...`);85});86}8788} else if (update.diff) {89const diff = update.diff;9091if (!snapshotReceived) {92console.log('\n⚠ Received diff before snapshot');93}9495try {96const diffData = JSON.parse(diff.data);97const orderStatuses = diffData.order_statuses || [];98const bookDiffs = diffData.book_diffs || [];99100console.log(`\n[Block ${diff.height}] L4 Diff:`);101console.log(` Time: ${diff.time}`);102console.log(` Order Statuses: ${orderStatuses.length}`);103console.log(` Book Diffs: ${bookDiffs.length}`);104105if (bookDiffs.length > 0 && bookDiffs.length <= 5) {106console.log(` Diffs: ${JSON.stringify(bookDiffs, null, 2)}`);107}108} catch (e) {109console.log(` Error parsing diff: ${e.message}`);110}111}112113if (maxMessages && totalMsgCount >= maxMessages) {114console.log(`\nReached max messages (${maxMessages}), stopping...`);115call.cancel();116}117});118119호출.on('error', (err) => {120만약 (err.코드 === grpc.상태.DATA_LOSS && autoReconnect) {121console.log(`\n⚠️ Server reinitialized: ${err.message}`);122retryCount++;123if (retryCount < maxRetries) {124const delay = baseDelay * Math.pow(2, retryCount - 1);125console.log(`⏳ Waiting ${delay / 1000}s before reconnecting...`);126setTimeout(() => streamL4Orderbook(coin, maxMessages, autoReconnect, retryCount), delay);127} else {128console.log(`\n❌ Max retries (${maxRetries}) reached. Giving up.`);129}130} else if (err.code !== grpc.status.CANCELLED) {131콘솔.오류('\ngRPC 오류:', err.code, '-', err.메시지);132}133});134135호출.on('end', () => {136콘솔.log('\n스트림 종료됨');137});138139// Wait for stream to complete140기다리다 새로운 약속((결심) => {141호출.on('end', 해결);142호출.on('error', 해결);143});144145break; // 성공 시 재시도 루프 종료146147} catch (err) {148콘솔.오류('오류:', err.message);149break;150}151}152}153154// Parse command line args155const args = process.argv.slice(2);156const coin = args.find(a => a.startsWith('--coin='))?.split('=')[1] || 'BTC';157const maxMessages = parseInt(args.find(a => a.startsWith('--max-messages='))?.split('=')[1]) || null;158159콘솔.log('\n' + '='.반복(60));160console.log('Hyperliquid StreamL4Book Example');161console.log(`Endpoint: ${GRPC_ENDPOINT}`);162콘솔.log('='.반복(60));163164streamL4Orderbook(coin, maxMessages);165
1#!/usr/bin/env python32"""3StreamL4Book Example - Stream individual order 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_l4_example.py --coin BTC --max-messages 10011"""1213import grpc14import json15import sys16import 시간17import argparse18from typing import Optional1920시도해 보세요:21import orderbook_pb2 다음과 같이 pb22import orderbook_pb2_grpc 다음과 같이 pb_grpc23except ImportError:24인쇄("오류: Proto 파일이 생성되지 않았습니다. 다음을 실행하십시오:")25인쇄(" python -m grpc_tools.protoc -I../../proto --python_out=. --grpc_python_out=. ../../proto/orderbook.proto")26sys.exit(1)2728# 구성29GRPC_ENDPOINT = "your-endpoint.hype-mainnet.quiknode.pro:10000"30AUTH_TOKEN = "your-auth-token"313233def stream_l4_orderbook(coin: str, max_messages: Optional[int] = None, auto_reconnect: bool = True):34"""35Stream L4 (individual orders) orderbook updates for a coin.3637인수:38coin: Symbol to stream (e.g., "BTC", "ETH")39max_messages: Maximum number of messages to receive (None for unlimited)40auto_reconnect: DATA_LOSS 오류 발생 시 자동 재연결 (기본값: True)41"""42인쇄(f"\n{'='*60}")43print(f"Streaming L4 Orderbook for {coin}")44print(f"Auto-reconnect: {auto_reconnect}")45인쇄(f"{'='*60}\n")4647retry_count = 048max_retries = 1049base_delay = 250total_msg_count = 05152while retry_count < max_retries:53채널 = grpc.secure_channel(54GRPC_ENDPOINT,55grpc.ssl_channel_credentials(),56옵션=[57('grpc.max_receive_message_length', 100 * 1024 * 1024),58('grpc.keepalive_time_ms', 30000),59]60)61스텁 = pb_grpc.OrderBookStreamingStub(채널)6263request = pb.L4BookRequest(coin=coin)6465msg_count = 066snapshot_received = False6768시도해 보세요:69if retry_count > 0:70인쇄(f"\n🔄 다시 연결 중 (시도 중 {재시도 횟수 + 1}/{최대 재시도 횟수})...")71else:72인쇄(f"연결 중 {GRPC_ENDPOINT}...")7374for update in stub.StreamL4Book(request, metadata=[('x-token', AUTH_TOKEN)]):75msg_count += 176total_msg_count += 17778if update.HasField('snapshot'):79snapshot = update.snapshot80snapshot_received = True81retry_count = 0 # 연결에 성공하면 재시도 횟수를 초기화합니다8283print(f"\n✓ L4 Snapshot Received!")84print(f"{'─'*60}")85print(f"Coin: {snapshot.coin}")86print(f"Height: {snapshot.height}")87print(f"Time: {snapshot.time}")88print(f"Bids: {len(snapshot.bids)} orders")89print(f"Asks: {len(snapshot.asks)} orders")90print(f"{'─'*60}")9192# Show sample of orders93if snapshot.bids:94print(f"\nSample Bids (first 5):")95for order in snapshot.bids[:5]:96print(f" OID: {order.oid} | Price: {order.limit_px} | Size: {order.sz} | User: {order.user[:10]}...")9798if snapshot.asks:99print(f"\nSample Asks (first 5):")100for order in snapshot.asks[:5]:101print(f" OID: {order.oid} | Price: {order.limit_px} | Size: {order.sz} | User: {order.user[:10]}...")102103elif update.HasField('diff'):104diff = update.diff105106if not snapshot_received:107print(f"\n⚠ Received diff before snapshot")108109# Parse the JSON diff data110try:111diff_data = json.loads(diff.data)112order_statuses = diff_data.get('order_statuses', [])113book_diffs = diff_data.get('book_diffs', [])114115print(f"\n[Block {diff.height}] L4 Diff:")116print(f" Time: {diff.time}")117print(f" Order Statuses: {len(order_statuses)}")118print(f" Book Diffs: {len(book_diffs)}")119120# Show sample diffs121if book_diffs and len(book_diffs) <= 5:122print(f" Diffs: {json.dumps(book_diffs, indent=4)}")123124except json.JSONDecodeError as e:125print(f" Error parsing diff data: {e}")126print(f" Raw data: {diff.data[:200]}...")127128if max_messages and total_msg_count >= max_messages:129print(f"\nReached max messages ({max_messages}), stopping...")130채널.닫기()131반환132133단, grpc.RpcError 를 e:134만약 e.코드() == grpc.StatusCode.DATA_LOSS 및 auto_reconnect:135print(f"\n⚠️ Server reinitialized: {e.details()}")136retry_count += 1137if retry_count < max_retries:138지연 = 기본_지연 * (2 ** (retry_count - 1)) # 지수적 백오프139인쇄(f"⏳ 대기 중 {지연}초 후 재연결됩니다...")140시간.sleep(지연)141채널.닫기()142계속143else:144인쇄(f"\n❌ 최대 재시도 횟수 ({max_retries})에 도달했습니다. 중단합니다.")145중단146else:147print(f"\ngRPC error: {e.code()} - {e.details()}")148중단149단, KeyboardInterrupt:150print("\nStopping L4 stream...")151중단152드디어:153채널.닫기()154155# 오류 없이 여기까지 도달했다면, 재시도 루프를 종료한다156중단157158159def main():160parser = argparse.ArgumentParser(description='Stream Hyperliquid L4 orderbook data via gRPC')161parser.add_argument('--coin', default='BTC', help='Coin symbol to stream')162parser.add_argument('--max-messages', type=int, default=None, help='Maximum number of messages to receive')163164args = parser.parse_args()165166인쇄(f"\n{'='*60}")167print("Hyperliquid StreamL4Book Example")168print(f"Endpoint: {GRPC_ENDPOINT}")169인쇄(f"{'='*60}")170171시도해 보세요:172stream_l4_orderbook(args.coin, max_messages=args.max_messages)173단, 예외 ~처럼 e:174print(f"\nError: {e}")175import 트레이스백176트레이스백.print_exc()177sys.exit(1)178179180if __name__ == "__main__":181main()182
1#!/usr/bin/env python32"""3StreamL4Book Example - Stream individual order 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_l4_example.py --coin BTC --max-messages 10011"""1213import grpc14import json15import sys16import 시간17import argparse18from typing import Optional1920시도해 보세요:21import orderbook_pb2 다음과 같이 pb22import orderbook_pb2_grpc 다음과 같이 pb_grpc23except ImportError:24인쇄("오류: Proto 파일이 생성되지 않았습니다. 다음을 실행하십시오:")25인쇄(" python -m grpc_tools.protoc -I../../proto --python_out=. --grpc_python_out=. ../../proto/orderbook.proto")26sys.exit(1)2728# 구성29GRPC_ENDPOINT = "your-endpoint.hype-mainnet.quiknode.pro:10000"30AUTH_TOKEN = "your-auth-token"313233def stream_l4_orderbook(coin: str, max_messages: Optional[int] = None, auto_reconnect: bool = True):34"""35Stream L4 (individual orders) orderbook updates for a coin.3637인수:38coin: Symbol to stream (e.g., "BTC", "ETH")39max_messages: Maximum number of messages to receive (None for unlimited)40auto_reconnect: DATA_LOSS 오류 발생 시 자동 재연결 (기본값: True)41"""42인쇄(f"\n{'='*60}")43print(f"Streaming L4 Orderbook for {coin}")44print(f"Auto-reconnect: {auto_reconnect}")45인쇄(f"{'='*60}\n")4647retry_count = 048max_retries = 1049base_delay = 250total_msg_count = 05152while retry_count < max_retries:53채널 = grpc.secure_channel(54GRPC_ENDPOINT,55grpc.ssl_channel_credentials(),56옵션=[57('grpc.max_receive_message_length', 100 * 1024 * 1024),58('grpc.keepalive_time_ms', 30000),59]60)61스텁 = pb_grpc.OrderBookStreamingStub(채널)6263request = pb.L4BookRequest(coin=coin)6465msg_count = 066snapshot_received = False6768시도해 보세요:69if retry_count > 0:70인쇄(f"\n🔄 다시 연결 중 (시도 중 {재시도 횟수 + 1}/{최대 재시도 횟수})...")71else:72인쇄(f"연결 중 {GRPC_ENDPOINT}...")7374for update in stub.StreamL4Book(request, metadata=[('x-token', AUTH_TOKEN)]):75msg_count += 176total_msg_count += 17778if update.HasField('snapshot'):79snapshot = update.snapshot80snapshot_received = True81retry_count = 0 # 연결에 성공하면 재시도 횟수를 초기화합니다8283print(f"\n✓ L4 Snapshot Received!")84print(f"{'─'*60}")85print(f"Coin: {snapshot.coin}")86print(f"Height: {snapshot.height}")87print(f"Time: {snapshot.time}")88print(f"Bids: {len(snapshot.bids)} orders")89print(f"Asks: {len(snapshot.asks)} orders")90print(f"{'─'*60}")9192# Show sample of orders93if snapshot.bids:94print(f"\nSample Bids (first 5):")95for order in snapshot.bids[:5]:96print(f" OID: {order.oid} | Price: {order.limit_px} | Size: {order.sz} | User: {order.user[:10]}...")9798if snapshot.asks:99print(f"\nSample Asks (first 5):")100for order in snapshot.asks[:5]:101print(f" OID: {order.oid} | Price: {order.limit_px} | Size: {order.sz} | User: {order.user[:10]}...")102103elif update.HasField('diff'):104diff = update.diff105106if not snapshot_received:107print(f"\n⚠ Received diff before snapshot")108109# Parse the JSON diff data110try:111diff_data = json.loads(diff.data)112order_statuses = diff_data.get('order_statuses', [])113book_diffs = diff_data.get('book_diffs', [])114115print(f"\n[Block {diff.height}] L4 Diff:")116print(f" Time: {diff.time}")117print(f" Order Statuses: {len(order_statuses)}")118print(f" Book Diffs: {len(book_diffs)}")119120# Show sample diffs121if book_diffs and len(book_diffs) <= 5:122print(f" Diffs: {json.dumps(book_diffs, indent=4)}")123124except json.JSONDecodeError as e:125print(f" Error parsing diff data: {e}")126print(f" Raw data: {diff.data[:200]}...")127128if max_messages and total_msg_count >= max_messages:129print(f"\nReached max messages ({max_messages}), stopping...")130채널.닫기()131반환132133단, grpc.RpcError 를 e:134만약 e.코드() == grpc.StatusCode.DATA_LOSS 및 auto_reconnect:135print(f"\n⚠️ Server reinitialized: {e.details()}")136retry_count += 1137if retry_count < max_retries:138지연 = 기본_지연 * (2 ** (retry_count - 1)) # 지수적 백오프139인쇄(f"⏳ 대기 중 {지연}초 후 재연결됩니다...")140시간.sleep(지연)141채널.닫기()142계속143else:144인쇄(f"\n❌ 최대 재시도 횟수 ({max_retries})에 도달했습니다. 중단합니다.")145중단146else:147print(f"\ngRPC error: {e.code()} - {e.details()}")148중단149단, KeyboardInterrupt:150print("\nStopping L4 stream...")151중단152드디어:153채널.닫기()154155# 오류 없이 여기까지 도달했다면, 재시도 루프를 종료한다156중단157158159def main():160parser = argparse.ArgumentParser(description='Stream Hyperliquid L4 orderbook data via gRPC')161parser.add_argument('--coin', default='BTC', help='Coin symbol to stream')162parser.add_argument('--max-messages', type=int, default=None, help='Maximum number of messages to receive')163164args = parser.parse_args()165166인쇄(f"\n{'='*60}")167print("Hyperliquid StreamL4Book Example")168print(f"Endpoint: {GRPC_ENDPOINT}")169인쇄(f"{'='*60}")170171시도해 보세요:172stream_l4_orderbook(args.coin, max_messages=args.max_messages)173단, 예외 ~처럼 e:174print(f"\nError: {e}")175import 트레이스백176트레이스백.print_exc()177sys.exit(1)178179180if __name__ == "__main__":181main()182