@tentou-tech/poly-websockets 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +212 -0
- package/dist/WSSubscriptionManager.d.ts +160 -0
- package/dist/WSSubscriptionManager.js +1020 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +21 -0
- package/dist/logger.d.ts +2 -0
- package/dist/logger.js +34 -0
- package/dist/modules/OrderBookCache.d.ts +54 -0
- package/dist/modules/OrderBookCache.js +194 -0
- package/dist/types/PolymarketWebSocket.d.ts +460 -0
- package/dist/types/PolymarketWebSocket.js +86 -0
- package/dist/types/WebSocketSubscriptions.d.ts +32 -0
- package/dist/types/WebSocketSubscriptions.js +12 -0
- package/package.json +54 -0
- package/src/WSSubscriptionManager.ts +1126 -0
- package/src/index.ts +3 -0
- package/src/logger.ts +36 -0
- package/src/modules/OrderBookCache.ts +227 -0
- package/src/types/PolymarketWebSocket.ts +538 -0
- package/src/types/WebSocketSubscriptions.ts +35 -0
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a single price level in the order book
|
|
3
|
+
* @example
|
|
4
|
+
* { price: "0.01", size: "510000" }
|
|
5
|
+
*/
|
|
6
|
+
export type PriceLevel = {
|
|
7
|
+
price: string;
|
|
8
|
+
size: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// WebSocket Messages (Client -> Server)
|
|
13
|
+
// ============================================================================
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Initial subscription message sent when connecting to the market WebSocket.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* {
|
|
20
|
+
* assets_ids: ["71321045679252212594626385532706912750332728571942532289631379312455583992563"],
|
|
21
|
+
* type: "market"
|
|
22
|
+
* }
|
|
23
|
+
*/
|
|
24
|
+
export type MarketSubscriptionMessage = {
|
|
25
|
+
assets_ids: string[];
|
|
26
|
+
type: 'market';
|
|
27
|
+
custom_feature_enabled?: boolean; // Custom feature flag for Polymarket
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Subscribe to additional assets on an existing connection.
|
|
32
|
+
*
|
|
33
|
+
* IMPORTANT: The Polymarket WebSocket protocol does NOT send any confirmation or
|
|
34
|
+
* acknowledgment message for subscribe operations. The server silently accepts the
|
|
35
|
+
* request, and the client will start receiving events for the subscribed assets.
|
|
36
|
+
* There is no way to know if a subscription was rejected (events simply won't arrive).
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* {
|
|
40
|
+
* operation: "subscribe",
|
|
41
|
+
* assets_ids: ["71321045679252212594626385532706912750332728571942532289631379312455583992563"]
|
|
42
|
+
* }
|
|
43
|
+
*/
|
|
44
|
+
export type SubscribeMessage = {
|
|
45
|
+
operation: 'subscribe';
|
|
46
|
+
assets_ids: string[];
|
|
47
|
+
custom_feature_enabled?: boolean; // Custom feature flag for Polymarket
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Unsubscribe from assets on an existing connection.
|
|
52
|
+
*
|
|
53
|
+
* IMPORTANT: The Polymarket WebSocket protocol does NOT send any confirmation or
|
|
54
|
+
* acknowledgment message for unsubscribe operations. The server silently accepts the
|
|
55
|
+
* request, and the client will stop receiving events for the unsubscribed assets.
|
|
56
|
+
* There is no way to know if an unsubscription was rejected.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* {
|
|
60
|
+
* operation: "unsubscribe",
|
|
61
|
+
* assets_ids: ["71321045679252212594626385532706912750332728571942532289631379312455583992563"]
|
|
62
|
+
* }
|
|
63
|
+
*/
|
|
64
|
+
export type UnsubscribeMessage = {
|
|
65
|
+
operation: 'unsubscribe';
|
|
66
|
+
assets_ids: string[];
|
|
67
|
+
custom_feature_enabled?: boolean; // Custom feature flag for Polymarket
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Union type for all client-to-server messages.
|
|
72
|
+
*/
|
|
73
|
+
export type PolymarketWSMessage = MarketSubscriptionMessage | SubscribeMessage | UnsubscribeMessage;
|
|
74
|
+
|
|
75
|
+
// ============================================================================
|
|
76
|
+
// WebSocket Events (Server -> Client)
|
|
77
|
+
// ============================================================================
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Represents a single price change item
|
|
81
|
+
*/
|
|
82
|
+
export type PriceChangeItem = {
|
|
83
|
+
asset_id: string;
|
|
84
|
+
price: string;
|
|
85
|
+
size: string;
|
|
86
|
+
side: 'BUY' | 'SELL';
|
|
87
|
+
hash: string;
|
|
88
|
+
best_bid: string;
|
|
89
|
+
best_ask: string;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Represents a price_change event from Polymarket WebSocket
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* {
|
|
97
|
+
* market: "0x5f65177b394277fd294cd75650044e32ba009a95022d88a0c1d565897d72f8f1",
|
|
98
|
+
* price_changes: [
|
|
99
|
+
* {
|
|
100
|
+
* asset_id: "71321045679252212594626385532706912750332728571942532289631379312455583992563",
|
|
101
|
+
* price: "0.5",
|
|
102
|
+
* size: "200",
|
|
103
|
+
* side: "BUY",
|
|
104
|
+
* hash: "56621a121a47ed9333273e21c83b660cff37ae50",
|
|
105
|
+
* best_bid: "0.5",
|
|
106
|
+
* best_ask: "1"
|
|
107
|
+
* }
|
|
108
|
+
* ],
|
|
109
|
+
* timestamp: "1757908892351",
|
|
110
|
+
* event_type: "price_change"
|
|
111
|
+
* }
|
|
112
|
+
*/
|
|
113
|
+
export type PriceChangeEvent = {
|
|
114
|
+
event_type: 'price_change';
|
|
115
|
+
market: string;
|
|
116
|
+
timestamp: string;
|
|
117
|
+
price_changes: PriceChangeItem[];
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Represents a Polymarket book
|
|
122
|
+
* @example
|
|
123
|
+
* {
|
|
124
|
+
* bids: [
|
|
125
|
+
* { price: "0.01", size: "510000" },
|
|
126
|
+
* { price: "0.02", size: "3100" }
|
|
127
|
+
* ],
|
|
128
|
+
* asks: [
|
|
129
|
+
* { price: "0.99", size: "58.07" },
|
|
130
|
+
* { price: "0.97", size: "178.73" }
|
|
131
|
+
* }
|
|
132
|
+
*/
|
|
133
|
+
export type Book = {
|
|
134
|
+
bids: PriceLevel[];
|
|
135
|
+
asks: PriceLevel[];
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Represents a book event from Polymarket WebSocket
|
|
140
|
+
* @example
|
|
141
|
+
* {
|
|
142
|
+
* market: "0xf83fb46dd70a4459fcc441a8511701c463374c5c3c250f585d74fda85ddfb7c9",
|
|
143
|
+
* asset_id: "101007741586870489619361069512452187353898396425142157315847015703471254508752",
|
|
144
|
+
* timestamp: "1740759191594",
|
|
145
|
+
* hash: "c0e51b1cfdbcb1b2aec58feaf7b01004019a89c6",
|
|
146
|
+
* bids: [
|
|
147
|
+
* { price: "0.01", size: "510000" },
|
|
148
|
+
* { price: "0.02", size: "3100" }
|
|
149
|
+
* ],
|
|
150
|
+
* asks: [
|
|
151
|
+
* { price: "0.99", size: "58.07" },
|
|
152
|
+
* { price: "0.97", size: "178.73" }
|
|
153
|
+
* ],
|
|
154
|
+
* event_type: "book"
|
|
155
|
+
* }
|
|
156
|
+
*/
|
|
157
|
+
export type BookEvent = {
|
|
158
|
+
market: string;
|
|
159
|
+
asset_id: string;
|
|
160
|
+
timestamp: string;
|
|
161
|
+
hash: string;
|
|
162
|
+
bids: PriceLevel[];
|
|
163
|
+
asks: PriceLevel[];
|
|
164
|
+
event_type: 'book';
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Represents a last trade price event from Polymarket WebSocket
|
|
169
|
+
* @example
|
|
170
|
+
* {
|
|
171
|
+
* asset_id: "101007741586870489619361069512452187353898396425142157315847015703471254508752",
|
|
172
|
+
* event_type: "last_trade_price",
|
|
173
|
+
* fee_rate_bps: "0",
|
|
174
|
+
* market: "0xf83fb46dd70a4459fcc441a8511701c463374c5c3c250f585d74fda85ddfb7c9",
|
|
175
|
+
* price: "0.12",
|
|
176
|
+
* side: "BUY",
|
|
177
|
+
* size: "8.333332",
|
|
178
|
+
* timestamp: "1740760245471",
|
|
179
|
+
* transaction_hash: "0xd449923990fce41c5fcd1fef8079df5b1dc55fa00c2df62831d0bd3a7cdcc2aa"
|
|
180
|
+
* }
|
|
181
|
+
*/
|
|
182
|
+
export type LastTradePriceEvent = {
|
|
183
|
+
asset_id: string;
|
|
184
|
+
event_type: 'last_trade_price';
|
|
185
|
+
fee_rate_bps: string;
|
|
186
|
+
market: string;
|
|
187
|
+
price: string;
|
|
188
|
+
side: 'BUY' | 'SELL';
|
|
189
|
+
size: string;
|
|
190
|
+
timestamp: string;
|
|
191
|
+
transaction_hash: string;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Represents a tick size change event from Polymarket WebSocket
|
|
196
|
+
* @example
|
|
197
|
+
* {
|
|
198
|
+
* event_type: "tick_size_change",
|
|
199
|
+
* asset_id: "65818619657568813474341868652308942079804919287380422192892211131408793125422",
|
|
200
|
+
* market: "0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af",
|
|
201
|
+
* old_tick_size: "0.01",
|
|
202
|
+
* new_tick_size: "0.001",
|
|
203
|
+
* timestamp: "100000000"
|
|
204
|
+
* }
|
|
205
|
+
*/
|
|
206
|
+
export type TickSizeChangeEvent = {
|
|
207
|
+
asset_id: string;
|
|
208
|
+
event_type: 'tick_size_change';
|
|
209
|
+
market: string;
|
|
210
|
+
old_tick_size: string;
|
|
211
|
+
new_tick_size: string;
|
|
212
|
+
timestamp: string;
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Represents a best bid/ask event from Polymarket WebSocket
|
|
217
|
+
*
|
|
218
|
+
* Emitted when the best bid or ask price changes
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* {
|
|
222
|
+
* event_type: "best_bid_ask",
|
|
223
|
+
* asset_id: "65818619657568813474341868652308942079804919287380422192892211131408793125422",
|
|
224
|
+
* market: "0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af",
|
|
225
|
+
* best_bid: "0.48",
|
|
226
|
+
* best_ask: "0.52",
|
|
227
|
+
* timestamp: "123456789000"
|
|
228
|
+
* }
|
|
229
|
+
*/
|
|
230
|
+
export type BestBidAskEvent = {
|
|
231
|
+
asset_id: string;
|
|
232
|
+
event_type: 'best_bid_ask';
|
|
233
|
+
market: string;
|
|
234
|
+
best_bid: string;
|
|
235
|
+
best_ask: string;
|
|
236
|
+
timestamp: string;
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Represents the event message object nested in new_market and market_resolved events
|
|
241
|
+
*/
|
|
242
|
+
export type EventMessage = {
|
|
243
|
+
id: string;
|
|
244
|
+
ticker: string;
|
|
245
|
+
slug: string;
|
|
246
|
+
title: string;
|
|
247
|
+
description: string;
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Represents a new_market event from Polymarket WebSocket
|
|
252
|
+
*
|
|
253
|
+
* Note: This event requires custom_feature_enabled flag to be set to true
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* {
|
|
257
|
+
* id: "1031769",
|
|
258
|
+
* question: "Will NVIDIA (NVDA) close above $240 end of January?",
|
|
259
|
+
* market: "0x311d0c4b6671ab54af4970c06fcf58662516f5168997bdda209ec3db5aa6b0c1",
|
|
260
|
+
* slug: "nvda-above-240-on-january-30-2026",
|
|
261
|
+
* description: "This market will resolve to...",
|
|
262
|
+
* assets_ids: ["76043073756653678226373981964075571318267289248134717369284518995922789326425"],
|
|
263
|
+
* outcomes: ["Yes", "No"],
|
|
264
|
+
* event_message: {
|
|
265
|
+
* id: "125819",
|
|
266
|
+
* ticker: "nvda-above-in-january-2026",
|
|
267
|
+
* slug: "nvda-above-in-january-2026",
|
|
268
|
+
* title: "Will NVIDIA (NVDA) close above ___ end of January?",
|
|
269
|
+
* description: "..."
|
|
270
|
+
* },
|
|
271
|
+
* timestamp: "1766790415550",
|
|
272
|
+
* event_type: "new_market"
|
|
273
|
+
* }
|
|
274
|
+
*/
|
|
275
|
+
export type NewMarketEvent = {
|
|
276
|
+
event_type: 'new_market';
|
|
277
|
+
id: string;
|
|
278
|
+
question: string;
|
|
279
|
+
market: string;
|
|
280
|
+
slug: string;
|
|
281
|
+
description: string;
|
|
282
|
+
assets_ids: string[];
|
|
283
|
+
outcomes: string[];
|
|
284
|
+
event_message: EventMessage;
|
|
285
|
+
timestamp: string;
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Represents a market_resolved event from Polymarket WebSocket
|
|
290
|
+
*
|
|
291
|
+
* Note: This event requires custom_feature_enabled flag to be set to true
|
|
292
|
+
*
|
|
293
|
+
* @example
|
|
294
|
+
* {
|
|
295
|
+
* id: "1031769",
|
|
296
|
+
* question: "Will NVIDIA (NVDA) close above $240 end of January?",
|
|
297
|
+
* market: "0x311d0c4b6671ab54af4970c06fcf58662516f5168997bdda209ec3db5aa6b0c1",
|
|
298
|
+
* slug: "nvda-above-240-on-january-30-2026",
|
|
299
|
+
* description: "This market will resolve to...",
|
|
300
|
+
* assets_ids: ["76043073756653678226373981964075571318267289248134717369284518995922789326425"],
|
|
301
|
+
* outcomes: ["Yes", "No"],
|
|
302
|
+
* winning_asset_id: "76043073756653678226373981964075571318267289248134717369284518995922789326425",
|
|
303
|
+
* winning_outcome: "Yes",
|
|
304
|
+
* event_message: {
|
|
305
|
+
* id: "125819",
|
|
306
|
+
* ticker: "nvda-above-in-january-2026",
|
|
307
|
+
* slug: "nvda-above-in-january-2026",
|
|
308
|
+
* title: "Will NVIDIA (NVDA) close above ___ end of January?",
|
|
309
|
+
* description: "..."
|
|
310
|
+
* },
|
|
311
|
+
* timestamp: "1766790415550",
|
|
312
|
+
* event_type: "market_resolved"
|
|
313
|
+
* }
|
|
314
|
+
*/
|
|
315
|
+
export type MarketResolvedEvent = {
|
|
316
|
+
event_type: 'market_resolved';
|
|
317
|
+
id: string;
|
|
318
|
+
question: string;
|
|
319
|
+
market: string;
|
|
320
|
+
slug: string;
|
|
321
|
+
description: string;
|
|
322
|
+
assets_ids: string[];
|
|
323
|
+
outcomes: string[];
|
|
324
|
+
winning_asset_id: string;
|
|
325
|
+
winning_outcome: string;
|
|
326
|
+
event_message: EventMessage;
|
|
327
|
+
timestamp: string;
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Union type representing all possible event types from Polymarket WebSocket
|
|
332
|
+
* @example BookEvent
|
|
333
|
+
* {
|
|
334
|
+
* market: "0xf83fb46dd70a4459fcc441a8511701c463374c5c3c250f585d74fda85ddfb7c9",
|
|
335
|
+
* asset_id: "101007741586870489619361069512452187353898396425142157315847015703471254508752",
|
|
336
|
+
* timestamp: "1740759191594",
|
|
337
|
+
* hash: "c0e51b1cfdbcb1b2aec58feaf7b01004019a89c6",
|
|
338
|
+
* bids: [{ price: "0.01", size: "510000" }],
|
|
339
|
+
* asks: [{ price: "0.99", size: "58.07" }],
|
|
340
|
+
* event_type: "book"
|
|
341
|
+
* }
|
|
342
|
+
*
|
|
343
|
+
* @example LastTradePriceEvent
|
|
344
|
+
* {
|
|
345
|
+
* asset_id: "101007741586870489619361069512452187353898396425142157315847015703471254508752",
|
|
346
|
+
* event_type: "last_trade_price",
|
|
347
|
+
* fee_rate_bps: "0",
|
|
348
|
+
* market: "0xf83fb46dd70a4459fcc441a8511701c463374c5c3c250f585d74fda85ddfb7c9",
|
|
349
|
+
* price: "0.12",
|
|
350
|
+
* side: "BUY",
|
|
351
|
+
* size: "8.333332",
|
|
352
|
+
* timestamp: "1740760245471"
|
|
353
|
+
* }
|
|
354
|
+
*
|
|
355
|
+
* @example PriceChangeEvent
|
|
356
|
+
* {
|
|
357
|
+
* market: "0x5f65177b394277fd294cd75650044e32ba009a95022d88a0c1d565897d72f8f1",
|
|
358
|
+
* price_changes: [
|
|
359
|
+
* {
|
|
360
|
+
* asset_id: "71321045679252212594626385532706912750332728571942532289631379312455583992563",
|
|
361
|
+
* price: "0.5",
|
|
362
|
+
* size: "200",
|
|
363
|
+
* side: "BUY",
|
|
364
|
+
* hash: "56621a121a47ed9333273e21c83b660cff37ae50",
|
|
365
|
+
* best_bid: "0.5",
|
|
366
|
+
* best_ask: "1"
|
|
367
|
+
* }
|
|
368
|
+
* ],
|
|
369
|
+
* timestamp: "1757908892351",
|
|
370
|
+
* event_type: "price_change"
|
|
371
|
+
* }
|
|
372
|
+
*
|
|
373
|
+
* @example TickSizeChangeEvent
|
|
374
|
+
* {
|
|
375
|
+
* event_type: "tick_size_change",
|
|
376
|
+
* asset_id: "65818619657568813474341868652308942079804919287380422192892211131408793125422",
|
|
377
|
+
* market: "0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af",
|
|
378
|
+
* old_tick_size: "0.01",
|
|
379
|
+
* new_tick_size: "0.001",
|
|
380
|
+
* timestamp: "100000000"
|
|
381
|
+
* }
|
|
382
|
+
*/
|
|
383
|
+
export type PolymarketWSEvent = BookEvent | LastTradePriceEvent | PriceChangeEvent | TickSizeChangeEvent | BestBidAskEvent | NewMarketEvent | MarketResolvedEvent;
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Represents a price update event
|
|
387
|
+
*
|
|
388
|
+
* This is an event that is emitted to faciliate price update events. It is
|
|
389
|
+
* not emitted by the Polymarket WebSocket directly.
|
|
390
|
+
*
|
|
391
|
+
* See https://docs.polymarket.com/polymarket-learn/trading/how-are-prices-calculated
|
|
392
|
+
*
|
|
393
|
+
* TLDR: The prices displayed on Polymarket are the midpoint of the bid-ask spread in the orderbook,
|
|
394
|
+
* UNLESS that spread is over $0.10, in which case the **last traded price** is used.
|
|
395
|
+
*/
|
|
396
|
+
export interface PolymarketPriceUpdateEvent {
|
|
397
|
+
event_type: 'price_update';
|
|
398
|
+
asset_id: string;
|
|
399
|
+
timestamp: string;
|
|
400
|
+
triggeringEvent: LastTradePriceEvent | PriceChangeEvent;
|
|
401
|
+
book: Book;
|
|
402
|
+
price: string;
|
|
403
|
+
midpoint: string;
|
|
404
|
+
spread: string;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Represents the handlers for the Polymarket WebSocket
|
|
409
|
+
*/
|
|
410
|
+
export type WebSocketHandlers = {
|
|
411
|
+
|
|
412
|
+
/*
|
|
413
|
+
Polymarket WebSocket event handlers
|
|
414
|
+
*/
|
|
415
|
+
|
|
416
|
+
// https://docs.polymarket.com/developers/CLOB/websocket/market-channel#book-message
|
|
417
|
+
onBook?: (events: BookEvent[]) => Promise<void>;
|
|
418
|
+
|
|
419
|
+
// Currently undocumented, but is emitted when a trade occurs
|
|
420
|
+
onLastTradePrice?: (events: LastTradePriceEvent[]) => Promise<void>;
|
|
421
|
+
|
|
422
|
+
// https://docs.polymarket.com/developers/CLOB/websocket/market-channel#tick-size-change-message
|
|
423
|
+
onTickSizeChange?: (events: TickSizeChangeEvent[]) => Promise<void>;
|
|
424
|
+
|
|
425
|
+
// https://docs.polymarket.com/developers/CLOB/websocket/market-channel#price-change-message
|
|
426
|
+
onPriceChange?: (events: PriceChangeEvent[]) => Promise<void>;
|
|
427
|
+
|
|
428
|
+
// https://docs.polymarket.com/developers/CLOB/websocket/market-channel#best_bid_ask-message
|
|
429
|
+
onBestBidAsk?: (events: BestBidAskEvent[]) => Promise<void>;
|
|
430
|
+
|
|
431
|
+
// https://docs.polymarket.com/developers/CLOB/websocket/market-channel#new_market-message
|
|
432
|
+
// Note: Requires enableCustomFeatures option to be set to true
|
|
433
|
+
onNewMarket?: (events: NewMarketEvent[]) => Promise<void>;
|
|
434
|
+
|
|
435
|
+
// https://docs.polymarket.com/developers/CLOB/websocket/market-channel#market_resolved-message
|
|
436
|
+
// Note: Requires enableCustomFeatures option to be set to true
|
|
437
|
+
onMarketResolved?: (events: MarketResolvedEvent[]) => Promise<void>;
|
|
438
|
+
|
|
439
|
+
/*
|
|
440
|
+
Also mentioned as 'Future Price', this is the price that is displayed on the Polymarket UI
|
|
441
|
+
and denotes the probability of an event happening. Read more about it here:
|
|
442
|
+
https://docs.polymarket.com/polymarket-learn/trading/how-are-prices-calculated#future-price
|
|
443
|
+
|
|
444
|
+
This is a derived event that is not emmited by the Polymarket WebSocket directly.
|
|
445
|
+
*/
|
|
446
|
+
onPolymarketPriceUpdate?: (events: PolymarketPriceUpdateEvent[]) => Promise<void>;
|
|
447
|
+
|
|
448
|
+
// Error handling
|
|
449
|
+
onError?: (error: Error) => Promise<void>;
|
|
450
|
+
|
|
451
|
+
// Connection lifecycle events
|
|
452
|
+
onWSClose?: (managerId: string, code: number, reason: string) => Promise<void>;
|
|
453
|
+
onWSOpen?: (managerId: string, pendingAssetIds: string[]) => Promise<void>;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Type guard to check if an event is a BookEvent
|
|
458
|
+
* @example
|
|
459
|
+
* if (isBookEvent(event)) {
|
|
460
|
+
* // event is now typed as BookEvent
|
|
461
|
+
* console.log(event.bids);
|
|
462
|
+
* }
|
|
463
|
+
*/
|
|
464
|
+
export function isBookEvent(event: PolymarketWSEvent | PolymarketPriceUpdateEvent): event is BookEvent {
|
|
465
|
+
return event?.event_type === 'book';
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Type guard to check if an event is a LastTradePriceEvent
|
|
470
|
+
* @example
|
|
471
|
+
* if (isLastTradePriceEvent(event)) {
|
|
472
|
+
* // event is now typed as LastTradePriceEvent
|
|
473
|
+
* console.log(event.side);
|
|
474
|
+
* }
|
|
475
|
+
*/
|
|
476
|
+
export function isLastTradePriceEvent(event: PolymarketWSEvent | PolymarketPriceUpdateEvent): event is LastTradePriceEvent {
|
|
477
|
+
return event?.event_type === 'last_trade_price';
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Type guard to check if an event is a PriceChangeEvent
|
|
482
|
+
* @example
|
|
483
|
+
* if (isPriceChangeEvent(event)) {
|
|
484
|
+
* // event is now typed as PriceChangeEvent
|
|
485
|
+
* console.log(event.changes);
|
|
486
|
+
* }
|
|
487
|
+
*/
|
|
488
|
+
export function isPriceChangeEvent(event: PolymarketWSEvent | PolymarketPriceUpdateEvent): event is PriceChangeEvent {
|
|
489
|
+
return event?.event_type === 'price_change';
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Type guard to check if an event is a TickSizeChangeEvent
|
|
494
|
+
* @example
|
|
495
|
+
* if (isTickSizeChangeEvent(event)) {
|
|
496
|
+
* // event is now typed as TickSizeChangeEvent
|
|
497
|
+
* console.log(event.old_tick_size);
|
|
498
|
+
* }
|
|
499
|
+
*/
|
|
500
|
+
export function isTickSizeChangeEvent(event: PolymarketWSEvent | PolymarketPriceUpdateEvent): event is TickSizeChangeEvent {
|
|
501
|
+
return event?.event_type === 'tick_size_change';
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Type guard to check if an event is a BestBidAskEvent
|
|
506
|
+
* @example
|
|
507
|
+
* if (isBestBidAskEvent(event)) {
|
|
508
|
+
* // event is now typed as BestBidAskEvent
|
|
509
|
+
* console.log(event.best_bid, event.best_ask);
|
|
510
|
+
* }
|
|
511
|
+
*/
|
|
512
|
+
export function isBestBidAskEvent(event: PolymarketWSEvent | PolymarketPriceUpdateEvent): event is BestBidAskEvent {
|
|
513
|
+
return event?.event_type === 'best_bid_ask';
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Type guard to check if an event is a NewMarketEvent
|
|
518
|
+
* @example
|
|
519
|
+
* if (isNewMarketEvent(event)) {
|
|
520
|
+
* // event is now typed as NewMarketEvent
|
|
521
|
+
* console.log(event.question);
|
|
522
|
+
* }
|
|
523
|
+
*/
|
|
524
|
+
export function isNewMarketEvent(event: PolymarketWSEvent | PolymarketPriceUpdateEvent): event is NewMarketEvent {
|
|
525
|
+
return event?.event_type === 'new_market';
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Type guard to check if an event is a MarketResolvedEvent
|
|
530
|
+
* @example
|
|
531
|
+
* if (isMarketResolvedEvent(event)) {
|
|
532
|
+
* // event is now typed as MarketResolvedEvent
|
|
533
|
+
* console.log(event.winning_outcome);
|
|
534
|
+
* }
|
|
535
|
+
*/
|
|
536
|
+
export function isMarketResolvedEvent(event: PolymarketWSEvent | PolymarketPriceUpdateEvent): event is MarketResolvedEvent {
|
|
537
|
+
return event?.event_type === 'market_resolved';
|
|
538
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connection status for the WebSocket.
|
|
3
|
+
*/
|
|
4
|
+
export enum WebSocketConnectionStatus {
|
|
5
|
+
DISCONNECTED = 'disconnected',
|
|
6
|
+
CONNECTING = 'connecting',
|
|
7
|
+
CONNECTED = 'connected',
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Options for configuring the WSSubscriptionManager.
|
|
12
|
+
*/
|
|
13
|
+
export type SubscriptionManagerOptions = {
|
|
14
|
+
/**
|
|
15
|
+
* How often to check for reconnection (in milliseconds).
|
|
16
|
+
* Default: 5000ms (5 seconds)
|
|
17
|
+
*
|
|
18
|
+
* Note: We intentionally use a static interval rather than exponential backoff.
|
|
19
|
+
* Perhaps change this to exponential backoff in the future.
|
|
20
|
+
*/
|
|
21
|
+
reconnectAndCleanupIntervalMs?: number;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* How often to flush pending subscriptions to the WebSocket (in milliseconds).
|
|
25
|
+
* Default: 100ms
|
|
26
|
+
*/
|
|
27
|
+
pendingFlushIntervalMs?: number;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Enable custom features such as new_market and market_resolved events.
|
|
31
|
+
* When enabled, sets the custom_feature_enabled flag in WebSocket messages.
|
|
32
|
+
* Default: false
|
|
33
|
+
*/
|
|
34
|
+
enableCustomFeatures?: boolean;
|
|
35
|
+
}
|