StreamTpslUpdates gRPC Method
Please note that this method is metered based on data consumption at 0.0165 MB = 10 API credits.
Parâmetros
coins
repeated string
A carregar...
Devoluções
stream
stream<TpslUpdatesUpdate>
A carregar...
tempo
uint64
A carregar...
altura
uint64
A carregar...
snapshot
bool
A carregar...
diffs
array<TpslOrderDiff>
A carregar...
Pedido
1// StreamTpslUpdates Example - Stream TP/SL trigger-order updates via gRPC2package main34importar (5"contexto"6"flag"7"fmt"8"io"9"registo"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 streamTpslUpdates(coins []string) error {31fmt.Println(strings.Repeat("=", 60))32fmt.Printf("Streaming TP/SL Updates for %s\n", strings.Join(coins, ", "))33fmt.Println("Auto-reconnect: true")34fmt.Println(strings.Repeat("=", 60) + "\n")3536retryCount := 03738for retryCount < maxRetries {39creds := credentials.NewClientTLSFromCert(nil, "")40conn, err := grpc.Dial(grpcEndpoint,41grpc.WithTransportCredentials(creds),42grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)))43if err != nil {44return fmt.Errorf("failed to connect: %w", err)45}4647client := pb.NewOrderBookStreamingClient(conn)48ctx := metadata.AppendToOutgoingContext(context.Background(), "x-token", authToken)4950request := &pb.TpslUpdatesRequest{51Coins: coins,52}5354if retryCount > 0 {55fmt.Printf("\n🔄 Reconnecting (attempt %d/%d)...\n", retryCount+1, maxRetries)56} else {57fmt.Printf("Connecting to %s...\n", grpcEndpoint)58}5960stream, err := client.StreamTpslUpdates(ctx, request)61if err != nil {62conn.Close()63return fmt.Errorf("failed to start stream: %w", err)64}6566msgCount := 067shouldRetry := false6869for {70update, err := stream.Recv()71if err == io.EOF {72break73}74if err != nil {75st, ok := status.FromError(err)76if ok && st.Code() == codes.DataLoss {77fmt.Printf("\n⚠️ Server reinitialized: %s\n", st.Message())78retryCount++79if retryCount < maxRetries {80delay := baseDelay * time.Duration(math.Pow(2, float64(retryCount-1)))81fmt.Printf("⏳ Waiting %v before reconnecting...\n", delay)82time.Sleep(delay)83shouldRetry = true84break85} else {86fmt.Printf("\n❌ Max retries (%d) reached. Giving up.\n", maxRetries)87conn.Close()88return nil89}90}91conn.Close()92return fmt.Errorf("stream error: %w", err)93}9495msgCount++96if msgCount == 1 {97fmt.Println("✓ First TP/SL update received!\n")98retryCount = 0 // Reset on success99}100101// Display update102fmt.Println("\n" + strings.Repeat("─", 60))103snapshotLabel := ""104if update.Snapshot {105snapshotLabel = " | SNAPSHOT"106}107fmt.Printf("Block: %d | Time: %d%s | Diffs: %d\n", update.Height, update.Time, snapshotLabel, len(update.Diffs))108fmt.Println(strings.Repeat("─", 60))109110for _, diff := range update.Diffs {111side := "ASK"112if diff.Side == "B" {113side = "BID"114}115sz := diff.Sz116if diff.IsPositionTpsl {117sz = "position-sized"118}119120switch diff.DiffType {121case pb.TpslDiffType_TPSL_DIFF_TYPE_ADD:122fmt.Printf(" ADD %s oid: %d | %s | %s sz: %s\n", diff.Coin, diff.Oid, diff.OrderType, side, sz)123fmt.Printf(" trigger: %s | limit px: %s | reduce-only: %t\n", diff.TriggerCondition, diff.LimitPx, diff.ReduceOnly)124case pb.TpslDiffType_TPSL_DIFF_TYPE_REMOVE:125fmt.Printf(" REMOVE %s oid: %d | %s | reason: %s\n", diff.Coin, diff.Oid, diff.OrderType, diff.Reason)126}127}128129fmt.Printf("\n Messages received: %d\n", msgCount)130}131132conn.Close()133134if !shouldRetry {135break136}137}138139return nil140}141142func main() {143coinsFlag := flag.String("coins", "ETH", "Comma-separated coin symbols to stream (e.g., ETH,BTC)")144145flag.Parse()146147coins := strings.Split(*coinsFlag, ",")148149fmt.Println("\n" + strings.Repeat("=", 60))150fmt.Println("Hyperliquid StreamTpslUpdates Example")151fmt.Printf("Endpoint: %s\n", grpcEndpoint)152fmt.Println(strings.Repeat("=", 60))153154if err := streamTpslUpdates(coins); err != nil {155log.Fatal(err)156}157}158
1// StreamTpslUpdates Example - Stream TP/SL trigger-order updates via gRPC2package main34importar (5"contexto"6"flag"7"fmt"8"io"9"registo"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 streamTpslUpdates(coins []string) error {31fmt.Println(strings.Repeat("=", 60))32fmt.Printf("Streaming TP/SL Updates for %s\n", strings.Join(coins, ", "))33fmt.Println("Auto-reconnect: true")34fmt.Println(strings.Repeat("=", 60) + "\n")3536retryCount := 03738for retryCount < maxRetries {39creds := credentials.NewClientTLSFromCert(nil, "")40conn, err := grpc.Dial(grpcEndpoint,41grpc.WithTransportCredentials(creds),42grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)))43if err != nil {44return fmt.Errorf("failed to connect: %w", err)45}4647client := pb.NewOrderBookStreamingClient(conn)48ctx := metadata.AppendToOutgoingContext(context.Background(), "x-token", authToken)4950request := &pb.TpslUpdatesRequest{51Coins: coins,52}5354if retryCount > 0 {55fmt.Printf("\n🔄 Reconnecting (attempt %d/%d)...\n", retryCount+1, maxRetries)56} else {57fmt.Printf("Connecting to %s...\n", grpcEndpoint)58}5960stream, err := client.StreamTpslUpdates(ctx, request)61if err != nil {62conn.Close()63return fmt.Errorf("failed to start stream: %w", err)64}6566msgCount := 067shouldRetry := false6869for {70update, err := stream.Recv()71if err == io.EOF {72break73}74if err != nil {75st, ok := status.FromError(err)76if ok && st.Code() == codes.DataLoss {77fmt.Printf("\n⚠️ Server reinitialized: %s\n", st.Message())78retryCount++79if retryCount < maxRetries {80delay := baseDelay * time.Duration(math.Pow(2, float64(retryCount-1)))81fmt.Printf("⏳ Waiting %v before reconnecting...\n", delay)82time.Sleep(delay)83shouldRetry = true84break85} else {86fmt.Printf("\n❌ Max retries (%d) reached. Giving up.\n", maxRetries)87conn.Close()88return nil89}90}91conn.Close()92return fmt.Errorf("stream error: %w", err)93}9495msgCount++96if msgCount == 1 {97fmt.Println("✓ First TP/SL update received!\n")98retryCount = 0 // Reset on success99}100101// Display update102fmt.Println("\n" + strings.Repeat("─", 60))103snapshotLabel := ""104if update.Snapshot {105snapshotLabel = " | SNAPSHOT"106}107fmt.Printf("Block: %d | Time: %d%s | Diffs: %d\n", update.Height, update.Time, snapshotLabel, len(update.Diffs))108fmt.Println(strings.Repeat("─", 60))109110for _, diff := range update.Diffs {111side := "ASK"112if diff.Side == "B" {113side = "BID"114}115sz := diff.Sz116if diff.IsPositionTpsl {117sz = "position-sized"118}119120switch diff.DiffType {121case pb.TpslDiffType_TPSL_DIFF_TYPE_ADD:122fmt.Printf(" ADD %s oid: %d | %s | %s sz: %s\n", diff.Coin, diff.Oid, diff.OrderType, side, sz)123fmt.Printf(" trigger: %s | limit px: %s | reduce-only: %t\n", diff.TriggerCondition, diff.LimitPx, diff.ReduceOnly)124case pb.TpslDiffType_TPSL_DIFF_TYPE_REMOVE:125fmt.Printf(" REMOVE %s oid: %d | %s | reason: %s\n", diff.Coin, diff.Oid, diff.OrderType, diff.Reason)126}127}128129fmt.Printf("\n Messages received: %d\n", msgCount)130}131132conn.Close()133134if !shouldRetry {135break136}137}138139return nil140}141142func main() {143coinsFlag := flag.String("coins", "ETH", "Comma-separated coin symbols to stream (e.g., ETH,BTC)")144145flag.Parse()146147coins := strings.Split(*coinsFlag, ",")148149fmt.Println("\n" + strings.Repeat("=", 60))150fmt.Println("Hyperliquid StreamTpslUpdates Example")151fmt.Printf("Endpoint: %s\n", grpcEndpoint)152fmt.Println(strings.Repeat("=", 60))153154if err := streamTpslUpdates(coins); err != nil {155log.Fatal(err)156}157}158
1// StreamTpslUpdates Example - Stream TP/SL trigger-order updates 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 packageDefinition = protoLoader.loadSync(PROTO_PATH, {11keepCase: true,12longs: String,13enums: String,14defaults: true,15oneofs: true16});17const proto = grpc.loadPackageDefinition(packageDefinition).hyperliquid;1819function createClient() {20return new proto.OrderBookStreaming(21GRPC_ENDPOINT,22grpc.credentials.createSsl(),23{ 'grpc.max_receive_message_length': 100 * 1024 * 1024 }24);25}2627// Stream TP/SL trigger-order updates28async function streamTpslUpdates(coins, autoReconnect = true, retryCount = 0) {29console.log('='.repeat(60));30console.log(`Streaming TP/SL Updates for ${coins.length > 0 ? coins.join(', ') : 'all perp coins'}`);31console.log(`Auto-reconnect: ${autoReconnect}`);32console.log('='.repeat(60) + '\n');3334const maxRetries = 10;35const baseDelay = 2000;3637while (retryCount < maxRetries) {38const client = createClient();39const metadata = new grpc.Metadata();40metadata.add('x-token', AUTH_TOKEN);4142const request = {43coins: coins44};4546try {47if (retryCount > 0) {48console.log(`\n🔄 Reconnecting (attempt ${retryCount + 1}/${maxRetries})...`);49} else {50console.log(`Connecting to ${GRPC_ENDPOINT}...`);51}5253let msgCount = 0;54const call = client.StreamTpslUpdates(request, metadata);5556call.on('data', (update) => {57msgCount++;5859if (msgCount === 1) {60console.log('✓ First TP/SL update received!\n');61retryCount = 0; // Reset on success62}6364console.log('\n' + '─'.repeat(60));65console.log(`Block: ${update.height} | Time: ${update.time}${update.snapshot ? ' | SNAPSHOT' : ''} | Diffs: ${(update.diffs || []).length}`);66console.log('─'.repeat(60));6768(update.diffs || []).forEach(diff => {69const side = diff.side === 'B' ? 'BID' : 'ASK';70const sz = diff.is_position_tpsl ? 'position-sized' : diff.sz;7172if (diff.diff_type === 'TPSL_DIFF_TYPE_ADD') {73console.log(` ADD ${diff.coin} oid: ${diff.oid} | ${diff.order_type} | ${side} sz: ${sz}`);74console.log(` trigger: ${diff.trigger_condition} | limit px: ${diff.limit_px} | reduce-only: ${diff.reduce_only}`);75} else if (diff.diff_type === 'TPSL_DIFF_TYPE_REMOVE') {76console.log(` REMOVE ${diff.coin} oid: ${diff.oid} | ${diff.order_type} | reason: ${diff.reason}`);77}78});7980console.log(`\n Messages received: ${msgCount}`);81});8283call.on('error', (err) => {84if (err.code === grpc.status.DATA_LOSS && autoReconnect) {85console.log(`\n⚠️ Server reinitialized: ${err.message}`);86retryCount++;87if (retryCount < maxRetries) {88const delay = baseDelay * Math.pow(2, retryCount - 1);89console.log(`⏳ Waiting ${delay / 1000}s before reconnecting...`);90setTimeout(() => streamTpslUpdates(coins, autoReconnect, retryCount), delay);91} else {92console.log(`\n❌ Max retries (${maxRetries}) reached. Giving up.`);93}94} else {95console.error('\ngRPC error:', err.code, '-', err.message);96}97});9899call.on('end', () => {100console.log('\nStream ended');101});102103// Wait for stream to complete104await new Promise((resolve) => {105call.on('end', resolve);106call.on('error', resolve);107});108109break; // Exit retry loop on success110111} catch (err) {112console.error('Error:', err.message);113break;114}115}116}117118// Parse command line args119const args = process.argv.slice(2);120const coins = (args.find(a => a.startsWith('--coins='))?.split('=')[1] || 'ETH').split(',');121122console.log('\n' + '='.repeat(60));123console.log('Hyperliquid StreamTpslUpdates Example');124console.log(`Endpoint: ${GRPC_ENDPOINT}`);125console.log('='.repeat(60));126127streamTpslUpdates(coins);128
1// StreamTpslUpdates Example - Stream TP/SL trigger-order updates 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 packageDefinition = protoLoader.loadSync(PROTO_PATH, {11keepCase: true,12longs: String,13enums: String,14defaults: true,15oneofs: true16});17const proto = grpc.loadPackageDefinition(packageDefinition).hyperliquid;1819function createClient() {20return new proto.OrderBookStreaming(21GRPC_ENDPOINT,22grpc.credentials.createSsl(),23{ 'grpc.max_receive_message_length': 100 * 1024 * 1024 }24);25}2627// Stream TP/SL trigger-order updates28async function streamTpslUpdates(coins, autoReconnect = true, retryCount = 0) {29console.log('='.repeat(60));30console.log(`Streaming TP/SL Updates for ${coins.length > 0 ? coins.join(', ') : 'all perp coins'}`);31console.log(`Auto-reconnect: ${autoReconnect}`);32console.log('='.repeat(60) + '\n');3334const maxRetries = 10;35const baseDelay = 2000;3637while (retryCount < maxRetries) {38const client = createClient();39const metadata = new grpc.Metadata();40metadata.add('x-token', AUTH_TOKEN);4142const request = {43coins: coins44};4546try {47if (retryCount > 0) {48console.log(`\n🔄 Reconnecting (attempt ${retryCount + 1}/${maxRetries})...`);49} else {50console.log(`Connecting to ${GRPC_ENDPOINT}...`);51}5253let msgCount = 0;54const call = client.StreamTpslUpdates(request, metadata);5556call.on('data', (update) => {57msgCount++;5859if (msgCount === 1) {60console.log('✓ First TP/SL update received!\n');61retryCount = 0; // Reset on success62}6364console.log('\n' + '─'.repeat(60));65console.log(`Block: ${update.height} | Time: ${update.time}${update.snapshot ? ' | SNAPSHOT' : ''} | Diffs: ${(update.diffs || []).length}`);66console.log('─'.repeat(60));6768(update.diffs || []).forEach(diff => {69const side = diff.side === 'B' ? 'BID' : 'ASK';70const sz = diff.is_position_tpsl ? 'position-sized' : diff.sz;7172if (diff.diff_type === 'TPSL_DIFF_TYPE_ADD') {73console.log(` ADD ${diff.coin} oid: ${diff.oid} | ${diff.order_type} | ${side} sz: ${sz}`);74console.log(` trigger: ${diff.trigger_condition} | limit px: ${diff.limit_px} | reduce-only: ${diff.reduce_only}`);75} else if (diff.diff_type === 'TPSL_DIFF_TYPE_REMOVE') {76console.log(` REMOVE ${diff.coin} oid: ${diff.oid} | ${diff.order_type} | reason: ${diff.reason}`);77}78});7980console.log(`\n Messages received: ${msgCount}`);81});8283call.on('error', (err) => {84if (err.code === grpc.status.DATA_LOSS && autoReconnect) {85console.log(`\n⚠️ Server reinitialized: ${err.message}`);86retryCount++;87if (retryCount < maxRetries) {88const delay = baseDelay * Math.pow(2, retryCount - 1);89console.log(`⏳ Waiting ${delay / 1000}s before reconnecting...`);90setTimeout(() => streamTpslUpdates(coins, autoReconnect, retryCount), delay);91} else {92console.log(`\n❌ Max retries (${maxRetries}) reached. Giving up.`);93}94} else {95console.error('\ngRPC error:', err.code, '-', err.message);96}97});9899call.on('end', () => {100console.log('\nStream ended');101});102103// Wait for stream to complete104await new Promise((resolve) => {105call.on('end', resolve);106call.on('error', resolve);107});108109break; // Exit retry loop on success110111} catch (err) {112console.error('Error:', err.message);113break;114}115}116}117118// Parse command line args119const args = process.argv.slice(2);120const coins = (args.find(a => a.startsWith('--coins='))?.split('=')[1] || 'ETH').split(',');121122console.log('\n' + '='.repeat(60));123console.log('Hyperliquid StreamTpslUpdates Example');124console.log(`Endpoint: ${GRPC_ENDPOINT}`);125console.log('='.repeat(60));126127streamTpslUpdates(coins);128
1#!/usr/bin/env python32"""3StreamTpslUpdates Example - Stream TP/SL trigger-order updates via gRPC45Setup:6pip install grpcio grpcio-tools protobuf zstandard7python -m grpc_tools.protoc -I../../proto --python_out=. --grpc_python_out=. ../../proto/orderbook.proto89Usage:10python stream_tpsl_example.py --coins ETH,BTC11"""1213import grpc14import sys15importar hora16import argparse1718try:19import orderbook_pb2 as pb20import orderbook_pb2_grpc as pb_grpc21except ImportError:22print("Error: Proto files not generated. Run:")23print(" python -m grpc_tools.protoc -I../../proto --python_out=. --grpc_python_out=. ../../proto/orderbook.proto")24sys.exit(1)2526# Configuration27GRPC_ENDPOINT = "your-endpoint.hype-mainnet.quiknode.pro:10000"28AUTH_TOKEN = "your-auth-token"293031def stream_tpsl_updates(coins: list, auto_reconnect: bool = True):32"""33Stream TP/SL trigger-order updates for one or more coins.3435Args:36coins: Symbols to stream (e.g., ["ETH", "BTC"]). Empty list means all perp coins37auto_reconnect: Auto-reconnect on DATA_LOSS errors (default True)38"""39print(f"\n{'='*60}")40print(f"Streaming TP/SL Updates for {', '.join(coins) if coins else 'all perp coins'}")41print(f"Auto-reconnect: {auto_reconnect}")42print(f"{'='*60}\n")4344retry_count = 045max_retries = 1046base_delay = 24748while retry_count < max_retries:49channel = grpc.secure_channel(50GRPC_ENDPOINT,51grpc.ssl_channel_credentials(),52options=[53('grpc.max_receive_message_length', 100 * 1024 * 1024),54('grpc.keepalive_time_ms', 30000),55]56)57stub = pb_grpc.OrderBookStreamingStub(channel)5859# Build request60request = pb.TpslUpdatesRequest(coins=coins)6162msg_count = 06364try:65if retry_count > 0:66print(f"\n🔄 Reconnecting (attempt {retry_count + 1}/{max_retries})...")67else:68print(f"Connecting to {GRPC_ENDPOINT}...")6970for update in stub.StreamTpslUpdates(request, metadata=[('x-token', AUTH_TOKEN)]):71msg_count += 17273if msg_count == 1:74print(f"✓ First TP/SL update received!\n")75retry_count = 0 # Reset retry count on successful connection7677# Display the update78print(f"\n{'─'*60}")79snapshot_label = " | SNAPSHOT" if update.snapshot else ""80print(f"Block: {update.height} | Time: {update.time}{snapshot_label} | Diffs: {len(update.diffs)}")81print(f"{'─'*60}")8283for diff in update.diffs:84side = "BID" if diff.side == "B" else "ASK"85sz = "position-sized" if diff.is_position_tpsl else diff.sz8687if diff.diff_type == pb.TPSL_DIFF_TYPE_ADD:88print(f" ADD {diff.coin} oid: {diff.oid} | {diff.order_type} | {side} sz: {sz}")89print(f" trigger: {diff.trigger_condition} | limit px: {diff.limit_px} | reduce-only: {diff.reduce_only}")90elif diff.diff_type == pb.TPSL_DIFF_TYPE_REMOVE:91print(f" REMOVE {diff.coin} oid: {diff.oid} | {diff.order_type} | reason: {diff.reason}")9293print(f"\n Messages received: {msg_count}")9495except grpc.RpcError as e:96if e.code() == grpc.StatusCode.DATA_LOSS and auto_reconnect:97print(f"\n⚠️ Server reinitialized: {e.details()}")98retry_count += 199if retry_count < max_retries:100delay = base_delay * (2 ** (retry_count - 1)) # Exponential backoff101print(f"⏳ Waiting {delay}s before reconnecting...")102time.sleep(delay)103channel.close()104continue105else:106print(f"\n❌ Max retries ({max_retries}) reached. Giving up.")107break108else:109print(f"\ngRPC error: {e.code()} - {e.details()}")110break111except KeyboardInterrupt:112print("\nStopping TP/SL stream...")113break114finally:115channel.close()116117# If we get here without error, break the retry loop118break119120121def main():122parser = argparse.ArgumentParser(description='Stream Hyperliquid TP/SL trigger-order updates via gRPC')123parser.add_argument('--coins', default='ETH', help='Comma-separated coin symbols to stream (e.g., ETH,BTC)')124125args = parser.parse_args()126coins = [c.strip() for c in args.coins.split(',') if c.strip()]127128print(f"\n{'='*60}")129print("Hyperliquid StreamTpslUpdates Example")130print(f"Endpoint: {GRPC_ENDPOINT}")131print(f"{'='*60}")132133try:134stream_tpsl_updates(coins)135except Exception as e:136print(f"\nError: {e}")137import traceback138traceback.print_exc()139sys.exit(1)140141142if __name__ == "__main__":143main()144
1#!/usr/bin/env python32"""3StreamTpslUpdates Example - Stream TP/SL trigger-order updates via gRPC45Setup:6pip install grpcio grpcio-tools protobuf zstandard7python -m grpc_tools.protoc -I../../proto --python_out=. --grpc_python_out=. ../../proto/orderbook.proto89Usage:10python stream_tpsl_example.py --coins ETH,BTC11"""1213import grpc14import sys15importar hora16import argparse1718try:19import orderbook_pb2 as pb20import orderbook_pb2_grpc as pb_grpc21except ImportError:22print("Error: Proto files not generated. Run:")23print(" python -m grpc_tools.protoc -I../../proto --python_out=. --grpc_python_out=. ../../proto/orderbook.proto")24sys.exit(1)2526# Configuration27GRPC_ENDPOINT = "your-endpoint.hype-mainnet.quiknode.pro:10000"28AUTH_TOKEN = "your-auth-token"293031def stream_tpsl_updates(coins: list, auto_reconnect: bool = True):32"""33Stream TP/SL trigger-order updates for one or more coins.3435Args:36coins: Symbols to stream (e.g., ["ETH", "BTC"]). Empty list means all perp coins37auto_reconnect: Auto-reconnect on DATA_LOSS errors (default True)38"""39print(f"\n{'='*60}")40print(f"Streaming TP/SL Updates for {', '.join(coins) if coins else 'all perp coins'}")41print(f"Auto-reconnect: {auto_reconnect}")42print(f"{'='*60}\n")4344retry_count = 045max_retries = 1046base_delay = 24748while retry_count < max_retries:49channel = grpc.secure_channel(50GRPC_ENDPOINT,51grpc.ssl_channel_credentials(),52options=[53('grpc.max_receive_message_length', 100 * 1024 * 1024),54('grpc.keepalive_time_ms', 30000),55]56)57stub = pb_grpc.OrderBookStreamingStub(channel)5859# Build request60request = pb.TpslUpdatesRequest(coins=coins)6162msg_count = 06364try:65if retry_count > 0:66print(f"\n🔄 Reconnecting (attempt {retry_count + 1}/{max_retries})...")67else:68print(f"Connecting to {GRPC_ENDPOINT}...")6970for update in stub.StreamTpslUpdates(request, metadata=[('x-token', AUTH_TOKEN)]):71msg_count += 17273if msg_count == 1:74print(f"✓ First TP/SL update received!\n")75retry_count = 0 # Reset retry count on successful connection7677# Display the update78print(f"\n{'─'*60}")79snapshot_label = " | SNAPSHOT" if update.snapshot else ""80print(f"Block: {update.height} | Time: {update.time}{snapshot_label} | Diffs: {len(update.diffs)}")81print(f"{'─'*60}")8283for diff in update.diffs:84side = "BID" if diff.side == "B" else "ASK"85sz = "position-sized" if diff.is_position_tpsl else diff.sz8687if diff.diff_type == pb.TPSL_DIFF_TYPE_ADD:88print(f" ADD {diff.coin} oid: {diff.oid} | {diff.order_type} | {side} sz: {sz}")89print(f" trigger: {diff.trigger_condition} | limit px: {diff.limit_px} | reduce-only: {diff.reduce_only}")90elif diff.diff_type == pb.TPSL_DIFF_TYPE_REMOVE:91print(f" REMOVE {diff.coin} oid: {diff.oid} | {diff.order_type} | reason: {diff.reason}")9293print(f"\n Messages received: {msg_count}")9495except grpc.RpcError as e:96if e.code() == grpc.StatusCode.DATA_LOSS and auto_reconnect:97print(f"\n⚠️ Server reinitialized: {e.details()}")98retry_count += 199if retry_count < max_retries:100delay = base_delay * (2 ** (retry_count - 1)) # Exponential backoff101print(f"⏳ Waiting {delay}s before reconnecting...")102time.sleep(delay)103channel.close()104continue105else:106print(f"\n❌ Max retries ({max_retries}) reached. Giving up.")107break108else:109print(f"\ngRPC error: {e.code()} - {e.details()}")110break111except KeyboardInterrupt:112print("\nStopping TP/SL stream...")113break114finally:115channel.close()116117# If we get here without error, break the retry loop118break119120121def main():122parser = argparse.ArgumentParser(description='Stream Hyperliquid TP/SL trigger-order updates via gRPC')123parser.add_argument('--coins', default='ETH', help='Comma-separated coin symbols to stream (e.g., ETH,BTC)')124125args = parser.parse_args()126coins = [c.strip() for c in args.coins.split(',') if c.strip()]127128print(f"\n{'='*60}")129print("Hyperliquid StreamTpslUpdates Example")130print(f"Endpoint: {GRPC_ENDPOINT}")131print(f"{'='*60}")132133try:134stream_tpsl_updates(coins)135except Exception as e:136print(f"\nError: {e}")137import traceback138traceback.print_exc()139sys.exit(1)140141142if __name__ == "__main__":143main()144
Ainda não tem uma conta?
Crie o seu ponto de extremidade Quicknode em segundos e comece a desenvolver
Comece gratuitamente