-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathstream_l2_book.ts
More file actions
134 lines (110 loc) · 3.49 KB
/
stream_l2_book.ts
File metadata and controls
134 lines (110 loc) · 3.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#!/usr/bin/env npx ts-node
// @ts-nocheck
/**
* L2 Order Book Streaming - Aggregated Price Levels
*
* L2 order book shows total size at each price level (aggregated).
* Available via both WebSocket and gRPC.
*
* Use L2 for:
* - Price monitoring
* - Basic trading strategies
* - Lower bandwidth requirements
*
* Use L4 (gRPC only) when you need:
* - Individual order IDs
* - Queue position tracking
* - Order flow analysis
*
* Usage:
* export ENDPOINT="https://your-endpoint.example.com/TOKEN"
* npx ts-node stream_l2_book.ts
*/
import { HyperliquidSDK } from '@quicknode/hyperliquid-sdk';
const ENDPOINT = process.env.ENDPOINT;
if (!ENDPOINT) {
console.log("L2 Order Book Streaming Example");
console.log("=".repeat(60));
console.log();
console.log("Usage:");
console.log(" export ENDPOINT='https://your-endpoint.example.com/TOKEN'");
console.log(" npx ts-node stream_l2_book.ts");
process.exit(1);
}
function timestamp(): string {
return new Date().toISOString().slice(11, 23);
}
class L2BookTracker {
coin: string;
bids: any[] = [];
asks: any[] = [];
updateCount = 0;
constructor(coin: string) {
this.coin = coin;
}
update(data: any): void {
this.updateCount++;
this.bids = data.bids || [];
this.asks = data.asks || [];
}
bestBid(): [number, number] {
if (this.bids.length === 0) return [0, 0];
const bid = this.bids[0];
return Array.isArray(bid) ? [parseFloat(bid[0]), parseFloat(bid[1])] : [0, 0];
}
bestAsk(): [number, number] {
if (this.asks.length === 0) return [0, 0];
const ask = this.asks[0];
return Array.isArray(ask) ? [parseFloat(ask[0]), parseFloat(ask[1])] : [0, 0];
}
spread(): number {
const [bidPx] = this.bestBid();
const [askPx] = this.bestAsk();
return bidPx && askPx ? askPx - bidPx : 0;
}
spreadBps(): number {
const [bidPx] = this.bestBid();
const [askPx] = this.bestAsk();
if (!bidPx || !askPx) return 0;
const mid = (bidPx + askPx) / 2;
return ((askPx - bidPx) / mid) * 10000;
}
display(): void {
const [bidPx, bidSz] = this.bestBid();
const [askPx, askSz] = this.bestAsk();
console.log(`[${timestamp()}] ${this.coin}`);
console.log(` Bid: ${bidSz.toFixed(4)} @ $${bidPx.toLocaleString()}`);
console.log(` Ask: ${askSz.toFixed(4)} @ $${askPx.toLocaleString()}`);
console.log(` Spread: $${this.spread().toFixed(2)} (${this.spreadBps().toFixed(2)} bps)`);
console.log(` Levels: ${this.bids.length} bids, ${this.asks.length} asks`);
}
}
async function main() {
console.log("=".repeat(60));
console.log("L2 Order Book Streaming");
console.log("=".repeat(60));
const tracker = new L2BookTracker("ETH");
// Create SDK client
const sdk = new HyperliquidSDK(ENDPOINT!);
// Configure gRPC stream
sdk.grpc.onConnect = () => console.log("[CONNECTED]");
sdk.grpc.onError = (err) => console.log(`[ERROR] ${err.message}`);
sdk.grpc.l2Book("ETH", (data: any) => {
tracker.update(data);
tracker.display();
if (tracker.updateCount >= 5) {
console.log(`\nReceived ${tracker.updateCount} L2 updates.`);
}
}, { nLevels: 20 });
console.log("\nSubscribing to ETH L2 order book...");
console.log("-".repeat(60));
await sdk.grpc.start();
const start = Date.now();
while (tracker.updateCount < 5 && Date.now() - start < 20000) {
await new Promise(resolve => setTimeout(resolve, 100));
}
sdk.grpc.stop();
console.log("\n" + "=".repeat(60));
console.log("Done!");
}
main().catch(console.error);