Skip to main content

StreamTpslUpdates gRPC Method

Loading...

Updated on
Jun 10, 2026

StreamTpslUpdates gRPC Method

Please note that this method is metered based on data consumption at 0.0165 MB = 10 API credits.

Parameters

coins
repeated string
Loading...

Returns

stream
stream<TpslUpdatesUpdate>
Loading...
time
uint64
Loading...
height
uint64
Loading...
snapshot
bool
Loading...
diffs
array<TpslOrderDiff>
Loading...
Request
1
// StreamTpslUpdates Example - Stream TP/SL trigger-order updates via gRPC
2
package main
3
4
import (
5
"context"
6
"flag"
7
"fmt"
8
"io"
9
"log"
10
"math"
11
"strings"
12
"time"
13
14
"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"
19
20
pb "hyperliquid-orderbook-example/proto"
21
)
22
23
const (
24
grpcEndpoint = "your-endpoint.hype-mainnet.quiknode.pro:10000"
25
authToken = "your-auth-token"
26
maxRetries = 10
27
baseDelay = 2 * time.Second
28
)
29
30
func streamTpslUpdates(coins []string) error {
31
fmt.Println(strings.Repeat("=", 60))
32
fmt.Printf("Streaming TP/SL Updates for %s\n", strings.Join(coins, ", "))
33
fmt.Println("Auto-reconnect: true")
34
fmt.Println(strings.Repeat("=", 60) + "\n")
35
36
retryCount := 0
37
38
for retryCount < maxRetries {
39
creds := credentials.NewClientTLSFromCert(nil, "")
40
conn, err := grpc.Dial(grpcEndpoint,
41
grpc.WithTransportCredentials(creds),
42
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)))
43
if err != nil {
44
return fmt.Errorf("failed to connect: %w", err)
45
}
46
47
client := pb.NewOrderBookStreamingClient(conn)
48
ctx := metadata.AppendToOutgoingContext(context.Background(), "x-token", authToken)
49
50
request := &pb.TpslUpdatesRequest{
51
Coins: coins,
52
}
53
54
if retryCount > 0 {
55
fmt.Printf("\nšŸ”„ Reconnecting (attempt %d/%d)...\n", retryCount+1, maxRetries)
56
} else {
57
fmt.Printf("Connecting to %s...\n", grpcEndpoint)
58
}
59
60
stream, err := client.StreamTpslUpdates(ctx, request)
61
if err != nil {
62
conn.Close()
63
return fmt.Errorf("failed to start stream: %w", err)
64
}
65
66
msgCount := 0
67
shouldRetry := false
68
69
for {
70
update, err := stream.Recv()
71
if err == io.EOF {
72
break
73
}
74
if err != nil {
75
st, ok := status.FromError(err)
76
if ok && st.Code() == codes.DataLoss {
77
fmt.Printf("\nāš ļø Server reinitialized: %s\n", st.Message())
78
retryCount++
79
if retryCount < maxRetries {
80
delay := baseDelay * time.Duration(math.Pow(2, float64(retryCount-1)))
81
fmt.Printf("ā³ Waiting %v before reconnecting...\n", delay)
82
time.Sleep(delay)
83
shouldRetry = true
84
break
85
} else {
86
fmt.Printf("\nāŒ Max retries (%d) reached. Giving up.\n", maxRetries)
87
conn.Close()
88
return nil
89
}
90
}
91
conn.Close()
92
return fmt.Errorf("stream error: %w", err)
93
}
94
95
msgCount++
96
if msgCount == 1 {
97
fmt.Println("āœ“ First TP/SL update received!\n")
98
retryCount = 0 // Reset on success
99
}
100
101
// Display update
102
fmt.Println("\n" + strings.Repeat("─", 60))
103
snapshotLabel := ""
104
if update.Snapshot {
105
snapshotLabel = " | SNAPSHOT"
106
}
107
fmt.Printf("Block: %d | Time: %d%s | Diffs: %d\n", update.Height, update.Time, snapshotLabel, len(update.Diffs))
108
fmt.Println(strings.Repeat("─", 60))
109
110
for _, diff := range update.Diffs {
111
side := "ASK"
112
if diff.Side == "B" {
113
side = "BID"
114
}
115
sz := diff.Sz
116
if diff.IsPositionTpsl {
117
sz = "position-sized"
118
}
119
120
switch diff.DiffType {
121
case pb.TpslDiffType_TPSL_DIFF_TYPE_ADD:
122
fmt.Printf(" ADD %s oid: %d | %s | %s sz: %s\n", diff.Coin, diff.Oid, diff.OrderType, side, sz)
123
fmt.Printf(" trigger: %s | limit px: %s | reduce-only: %t\n", diff.TriggerCondition, diff.LimitPx, diff.ReduceOnly)
124
case pb.TpslDiffType_TPSL_DIFF_TYPE_REMOVE:
125
fmt.Printf(" REMOVE %s oid: %d | %s | reason: %s\n", diff.Coin, diff.Oid, diff.OrderType, diff.Reason)
126
}
127
}
128
129
fmt.Printf("\n Messages received: %d\n", msgCount)
130
}
131
132
conn.Close()
133
134
if !shouldRetry {
135
break
136
}
137
}
138
139
return nil
140
}
141
142
func main() {
143
coinsFlag := flag.String("coins", "ETH", "Comma-separated coin symbols to stream (e.g., ETH,BTC)")
144
145
flag.Parse()
146
147
coins := strings.Split(*coinsFlag, ",")
148
149
fmt.Println("\n" + strings.Repeat("=", 60))
150
fmt.Println("Hyperliquid StreamTpslUpdates Example")
151
fmt.Printf("Endpoint: %s\n", grpcEndpoint)
152
fmt.Println(strings.Repeat("=", 60))
153
154
if err := streamTpslUpdates(coins); err != nil {
155
log.Fatal(err)
156
}
157
}
158
1
// StreamTpslUpdates Example - Stream TP/SL trigger-order updates via gRPC
2
package main
3
4
import (
5
"context"
6
"flag"
7
"fmt"
8
"io"
9
"log"
10
"math"
11
"strings"
12
"time"
13
14
"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"
19
20
pb "hyperliquid-orderbook-example/proto"
21
)
22
23
const (
24
grpcEndpoint = "your-endpoint.hype-mainnet.quiknode.pro:10000"
25
authToken = "your-auth-token"
26
maxRetries = 10
27
baseDelay = 2 * time.Second
28
)
29
30
func streamTpslUpdates(coins []string) error {
31
fmt.Println(strings.Repeat("=", 60))
32
fmt.Printf("Streaming TP/SL Updates for %s\n", strings.Join(coins, ", "))
33
fmt.Println("Auto-reconnect: true")
34
fmt.Println(strings.Repeat("=", 60) + "\n")
35
36
retryCount := 0
37
38
for retryCount < maxRetries {
39
creds := credentials.NewClientTLSFromCert(nil, "")
40
conn, err := grpc.Dial(grpcEndpoint,
41
grpc.WithTransportCredentials(creds),
42
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(100*1024*1024)))
43
if err != nil {
44
return fmt.Errorf("failed to connect: %w", err)
45
}
46
47
client := pb.NewOrderBookStreamingClient(conn)
48
ctx := metadata.AppendToOutgoingContext(context.Background(), "x-token", authToken)
49
50
request := &pb.TpslUpdatesRequest{
51
Coins: coins,
52
}
53
54
if retryCount > 0 {
55
fmt.Printf("\nšŸ”„ Reconnecting (attempt %d/%d)...\n", retryCount+1, maxRetries)
56
} else {
57
fmt.Printf("Connecting to %s...\n", grpcEndpoint)
58
}
59
60
stream, err := client.StreamTpslUpdates(ctx, request)
61
if err != nil {
62
conn.Close()
63
return fmt.Errorf("failed to start stream: %w", err)
64
}
65
66
msgCount := 0
67
shouldRetry := false
68
69
for {
70
update, err := stream.Recv()
71
if err == io.EOF {
72
break
73
}
74
if err != nil {
75
st, ok := status.FromError(err)
76
if ok && st.Code() == codes.DataLoss {
77
fmt.Printf("\nāš ļø Server reinitialized: %s\n", st.Message())
78
retryCount++
79
if retryCount < maxRetries {
80
delay := baseDelay * time.Duration(math.Pow(2, float64(retryCount-1)))
81
fmt.Printf("ā³ Waiting %v before reconnecting...\n", delay)
82
time.Sleep(delay)
83
shouldRetry = true
84
break
85
} else {
86
fmt.Printf("\nāŒ Max retries (%d) reached. Giving up.\n", maxRetries)
87
conn.Close()
88
return nil
89
}
90
}
91
conn.Close()
92
return fmt.Errorf("stream error: %w", err)
93
}
94
95
msgCount++
96
if msgCount == 1 {
97
fmt.Println("āœ“ First TP/SL update received!\n")
98
retryCount = 0 // Reset on success
99
}
100
101
// Display update
102
fmt.Println("\n" + strings.Repeat("─", 60))
103
snapshotLabel := ""
104
if update.Snapshot {
105
snapshotLabel = " | SNAPSHOT"
106
}
107
fmt.Printf("Block: %d | Time: %d%s | Diffs: %d\n", update.Height, update.Time, snapshotLabel, len(update.Diffs))
108
fmt.Println(strings.Repeat("─", 60))
109
110
for _, diff := range update.Diffs {
111
side := "ASK"
112
if diff.Side == "B" {
113
side = "BID"
114
}
115
sz := diff.Sz
116
if diff.IsPositionTpsl {
117
sz = "position-sized"
118
}
119
120
switch diff.DiffType {
121
case pb.TpslDiffType_TPSL_DIFF_TYPE_ADD:
122
fmt.Printf(" ADD %s oid: %d | %s | %s sz: %s\n", diff.Coin, diff.Oid, diff.OrderType, side, sz)
123
fmt.Printf(" trigger: %s | limit px: %s | reduce-only: %t\n", diff.TriggerCondition, diff.LimitPx, diff.ReduceOnly)
124
case pb.TpslDiffType_TPSL_DIFF_TYPE_REMOVE:
125
fmt.Printf(" REMOVE %s oid: %d | %s | reason: %s\n", diff.Coin, diff.Oid, diff.OrderType, diff.Reason)
126
}
127
}
128
129
fmt.Printf("\n Messages received: %d\n", msgCount)
130
}
131
132
conn.Close()
133
134
if !shouldRetry {
135
break
136
}
137
}
138
139
return nil
140
}
141
142
func main() {
143
coinsFlag := flag.String("coins", "ETH", "Comma-separated coin symbols to stream (e.g., ETH,BTC)")
144
145
flag.Parse()
146
147
coins := strings.Split(*coinsFlag, ",")
148
149
fmt.Println("\n" + strings.Repeat("=", 60))
150
fmt.Println("Hyperliquid StreamTpslUpdates Example")
151
fmt.Printf("Endpoint: %s\n", grpcEndpoint)
152
fmt.Println(strings.Repeat("=", 60))
153
154
if err := streamTpslUpdates(coins); err != nil {
155
log.Fatal(err)
156
}
157
}
158
Don't have an account yet?
Create your Quicknode endpoint in seconds and start building
Get started for free