@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,460 @@
|
|
|
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
|
+
* Initial subscription message sent when connecting to the market WebSocket.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* {
|
|
15
|
+
* assets_ids: ["71321045679252212594626385532706912750332728571942532289631379312455583992563"],
|
|
16
|
+
* type: "market"
|
|
17
|
+
* }
|
|
18
|
+
*/
|
|
19
|
+
export type MarketSubscriptionMessage = {
|
|
20
|
+
assets_ids: string[];
|
|
21
|
+
type: 'market';
|
|
22
|
+
custom_feature_enabled?: boolean;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Subscribe to additional assets on an existing connection.
|
|
26
|
+
*
|
|
27
|
+
* IMPORTANT: The Polymarket WebSocket protocol does NOT send any confirmation or
|
|
28
|
+
* acknowledgment message for subscribe operations. The server silently accepts the
|
|
29
|
+
* request, and the client will start receiving events for the subscribed assets.
|
|
30
|
+
* There is no way to know if a subscription was rejected (events simply won't arrive).
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* {
|
|
34
|
+
* operation: "subscribe",
|
|
35
|
+
* assets_ids: ["71321045679252212594626385532706912750332728571942532289631379312455583992563"]
|
|
36
|
+
* }
|
|
37
|
+
*/
|
|
38
|
+
export type SubscribeMessage = {
|
|
39
|
+
operation: 'subscribe';
|
|
40
|
+
assets_ids: string[];
|
|
41
|
+
custom_feature_enabled?: boolean;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Unsubscribe from assets on an existing connection.
|
|
45
|
+
*
|
|
46
|
+
* IMPORTANT: The Polymarket WebSocket protocol does NOT send any confirmation or
|
|
47
|
+
* acknowledgment message for unsubscribe operations. The server silently accepts the
|
|
48
|
+
* request, and the client will stop receiving events for the unsubscribed assets.
|
|
49
|
+
* There is no way to know if an unsubscription was rejected.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* {
|
|
53
|
+
* operation: "unsubscribe",
|
|
54
|
+
* assets_ids: ["71321045679252212594626385532706912750332728571942532289631379312455583992563"]
|
|
55
|
+
* }
|
|
56
|
+
*/
|
|
57
|
+
export type UnsubscribeMessage = {
|
|
58
|
+
operation: 'unsubscribe';
|
|
59
|
+
assets_ids: string[];
|
|
60
|
+
custom_feature_enabled?: boolean;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Union type for all client-to-server messages.
|
|
64
|
+
*/
|
|
65
|
+
export type PolymarketWSMessage = MarketSubscriptionMessage | SubscribeMessage | UnsubscribeMessage;
|
|
66
|
+
/**
|
|
67
|
+
* Represents a single price change item
|
|
68
|
+
*/
|
|
69
|
+
export type PriceChangeItem = {
|
|
70
|
+
asset_id: string;
|
|
71
|
+
price: string;
|
|
72
|
+
size: string;
|
|
73
|
+
side: 'BUY' | 'SELL';
|
|
74
|
+
hash: string;
|
|
75
|
+
best_bid: string;
|
|
76
|
+
best_ask: string;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Represents a price_change event from Polymarket WebSocket
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* {
|
|
83
|
+
* market: "0x5f65177b394277fd294cd75650044e32ba009a95022d88a0c1d565897d72f8f1",
|
|
84
|
+
* price_changes: [
|
|
85
|
+
* {
|
|
86
|
+
* asset_id: "71321045679252212594626385532706912750332728571942532289631379312455583992563",
|
|
87
|
+
* price: "0.5",
|
|
88
|
+
* size: "200",
|
|
89
|
+
* side: "BUY",
|
|
90
|
+
* hash: "56621a121a47ed9333273e21c83b660cff37ae50",
|
|
91
|
+
* best_bid: "0.5",
|
|
92
|
+
* best_ask: "1"
|
|
93
|
+
* }
|
|
94
|
+
* ],
|
|
95
|
+
* timestamp: "1757908892351",
|
|
96
|
+
* event_type: "price_change"
|
|
97
|
+
* }
|
|
98
|
+
*/
|
|
99
|
+
export type PriceChangeEvent = {
|
|
100
|
+
event_type: 'price_change';
|
|
101
|
+
market: string;
|
|
102
|
+
timestamp: string;
|
|
103
|
+
price_changes: PriceChangeItem[];
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Represents a Polymarket book
|
|
107
|
+
* @example
|
|
108
|
+
* {
|
|
109
|
+
* bids: [
|
|
110
|
+
* { price: "0.01", size: "510000" },
|
|
111
|
+
* { price: "0.02", size: "3100" }
|
|
112
|
+
* ],
|
|
113
|
+
* asks: [
|
|
114
|
+
* { price: "0.99", size: "58.07" },
|
|
115
|
+
* { price: "0.97", size: "178.73" }
|
|
116
|
+
* }
|
|
117
|
+
*/
|
|
118
|
+
export type Book = {
|
|
119
|
+
bids: PriceLevel[];
|
|
120
|
+
asks: PriceLevel[];
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* Represents a book event from Polymarket WebSocket
|
|
124
|
+
* @example
|
|
125
|
+
* {
|
|
126
|
+
* market: "0xf83fb46dd70a4459fcc441a8511701c463374c5c3c250f585d74fda85ddfb7c9",
|
|
127
|
+
* asset_id: "101007741586870489619361069512452187353898396425142157315847015703471254508752",
|
|
128
|
+
* timestamp: "1740759191594",
|
|
129
|
+
* hash: "c0e51b1cfdbcb1b2aec58feaf7b01004019a89c6",
|
|
130
|
+
* bids: [
|
|
131
|
+
* { price: "0.01", size: "510000" },
|
|
132
|
+
* { price: "0.02", size: "3100" }
|
|
133
|
+
* ],
|
|
134
|
+
* asks: [
|
|
135
|
+
* { price: "0.99", size: "58.07" },
|
|
136
|
+
* { price: "0.97", size: "178.73" }
|
|
137
|
+
* ],
|
|
138
|
+
* event_type: "book"
|
|
139
|
+
* }
|
|
140
|
+
*/
|
|
141
|
+
export type BookEvent = {
|
|
142
|
+
market: string;
|
|
143
|
+
asset_id: string;
|
|
144
|
+
timestamp: string;
|
|
145
|
+
hash: string;
|
|
146
|
+
bids: PriceLevel[];
|
|
147
|
+
asks: PriceLevel[];
|
|
148
|
+
event_type: 'book';
|
|
149
|
+
};
|
|
150
|
+
/**
|
|
151
|
+
* Represents a last trade price event from Polymarket WebSocket
|
|
152
|
+
* @example
|
|
153
|
+
* {
|
|
154
|
+
* asset_id: "101007741586870489619361069512452187353898396425142157315847015703471254508752",
|
|
155
|
+
* event_type: "last_trade_price",
|
|
156
|
+
* fee_rate_bps: "0",
|
|
157
|
+
* market: "0xf83fb46dd70a4459fcc441a8511701c463374c5c3c250f585d74fda85ddfb7c9",
|
|
158
|
+
* price: "0.12",
|
|
159
|
+
* side: "BUY",
|
|
160
|
+
* size: "8.333332",
|
|
161
|
+
* timestamp: "1740760245471",
|
|
162
|
+
* transaction_hash: "0xd449923990fce41c5fcd1fef8079df5b1dc55fa00c2df62831d0bd3a7cdcc2aa"
|
|
163
|
+
* }
|
|
164
|
+
*/
|
|
165
|
+
export type LastTradePriceEvent = {
|
|
166
|
+
asset_id: string;
|
|
167
|
+
event_type: 'last_trade_price';
|
|
168
|
+
fee_rate_bps: string;
|
|
169
|
+
market: string;
|
|
170
|
+
price: string;
|
|
171
|
+
side: 'BUY' | 'SELL';
|
|
172
|
+
size: string;
|
|
173
|
+
timestamp: string;
|
|
174
|
+
transaction_hash: string;
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* Represents a tick size change event from Polymarket WebSocket
|
|
178
|
+
* @example
|
|
179
|
+
* {
|
|
180
|
+
* event_type: "tick_size_change",
|
|
181
|
+
* asset_id: "65818619657568813474341868652308942079804919287380422192892211131408793125422",
|
|
182
|
+
* market: "0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af",
|
|
183
|
+
* old_tick_size: "0.01",
|
|
184
|
+
* new_tick_size: "0.001",
|
|
185
|
+
* timestamp: "100000000"
|
|
186
|
+
* }
|
|
187
|
+
*/
|
|
188
|
+
export type TickSizeChangeEvent = {
|
|
189
|
+
asset_id: string;
|
|
190
|
+
event_type: 'tick_size_change';
|
|
191
|
+
market: string;
|
|
192
|
+
old_tick_size: string;
|
|
193
|
+
new_tick_size: string;
|
|
194
|
+
timestamp: string;
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* Represents a best bid/ask event from Polymarket WebSocket
|
|
198
|
+
*
|
|
199
|
+
* Emitted when the best bid or ask price changes
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* {
|
|
203
|
+
* event_type: "best_bid_ask",
|
|
204
|
+
* asset_id: "65818619657568813474341868652308942079804919287380422192892211131408793125422",
|
|
205
|
+
* market: "0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af",
|
|
206
|
+
* best_bid: "0.48",
|
|
207
|
+
* best_ask: "0.52",
|
|
208
|
+
* timestamp: "123456789000"
|
|
209
|
+
* }
|
|
210
|
+
*/
|
|
211
|
+
export type BestBidAskEvent = {
|
|
212
|
+
asset_id: string;
|
|
213
|
+
event_type: 'best_bid_ask';
|
|
214
|
+
market: string;
|
|
215
|
+
best_bid: string;
|
|
216
|
+
best_ask: string;
|
|
217
|
+
timestamp: string;
|
|
218
|
+
};
|
|
219
|
+
/**
|
|
220
|
+
* Represents the event message object nested in new_market and market_resolved events
|
|
221
|
+
*/
|
|
222
|
+
export type EventMessage = {
|
|
223
|
+
id: string;
|
|
224
|
+
ticker: string;
|
|
225
|
+
slug: string;
|
|
226
|
+
title: string;
|
|
227
|
+
description: string;
|
|
228
|
+
};
|
|
229
|
+
/**
|
|
230
|
+
* Represents a new_market event from Polymarket WebSocket
|
|
231
|
+
*
|
|
232
|
+
* Note: This event requires custom_feature_enabled flag to be set to true
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* {
|
|
236
|
+
* id: "1031769",
|
|
237
|
+
* question: "Will NVIDIA (NVDA) close above $240 end of January?",
|
|
238
|
+
* market: "0x311d0c4b6671ab54af4970c06fcf58662516f5168997bdda209ec3db5aa6b0c1",
|
|
239
|
+
* slug: "nvda-above-240-on-january-30-2026",
|
|
240
|
+
* description: "This market will resolve to...",
|
|
241
|
+
* assets_ids: ["76043073756653678226373981964075571318267289248134717369284518995922789326425"],
|
|
242
|
+
* outcomes: ["Yes", "No"],
|
|
243
|
+
* event_message: {
|
|
244
|
+
* id: "125819",
|
|
245
|
+
* ticker: "nvda-above-in-january-2026",
|
|
246
|
+
* slug: "nvda-above-in-january-2026",
|
|
247
|
+
* title: "Will NVIDIA (NVDA) close above ___ end of January?",
|
|
248
|
+
* description: "..."
|
|
249
|
+
* },
|
|
250
|
+
* timestamp: "1766790415550",
|
|
251
|
+
* event_type: "new_market"
|
|
252
|
+
* }
|
|
253
|
+
*/
|
|
254
|
+
export type NewMarketEvent = {
|
|
255
|
+
event_type: 'new_market';
|
|
256
|
+
id: string;
|
|
257
|
+
question: string;
|
|
258
|
+
market: string;
|
|
259
|
+
slug: string;
|
|
260
|
+
description: string;
|
|
261
|
+
assets_ids: string[];
|
|
262
|
+
outcomes: string[];
|
|
263
|
+
event_message: EventMessage;
|
|
264
|
+
timestamp: string;
|
|
265
|
+
};
|
|
266
|
+
/**
|
|
267
|
+
* Represents a market_resolved event from Polymarket WebSocket
|
|
268
|
+
*
|
|
269
|
+
* Note: This event requires custom_feature_enabled flag to be set to true
|
|
270
|
+
*
|
|
271
|
+
* @example
|
|
272
|
+
* {
|
|
273
|
+
* id: "1031769",
|
|
274
|
+
* question: "Will NVIDIA (NVDA) close above $240 end of January?",
|
|
275
|
+
* market: "0x311d0c4b6671ab54af4970c06fcf58662516f5168997bdda209ec3db5aa6b0c1",
|
|
276
|
+
* slug: "nvda-above-240-on-january-30-2026",
|
|
277
|
+
* description: "This market will resolve to...",
|
|
278
|
+
* assets_ids: ["76043073756653678226373981964075571318267289248134717369284518995922789326425"],
|
|
279
|
+
* outcomes: ["Yes", "No"],
|
|
280
|
+
* winning_asset_id: "76043073756653678226373981964075571318267289248134717369284518995922789326425",
|
|
281
|
+
* winning_outcome: "Yes",
|
|
282
|
+
* event_message: {
|
|
283
|
+
* id: "125819",
|
|
284
|
+
* ticker: "nvda-above-in-january-2026",
|
|
285
|
+
* slug: "nvda-above-in-january-2026",
|
|
286
|
+
* title: "Will NVIDIA (NVDA) close above ___ end of January?",
|
|
287
|
+
* description: "..."
|
|
288
|
+
* },
|
|
289
|
+
* timestamp: "1766790415550",
|
|
290
|
+
* event_type: "market_resolved"
|
|
291
|
+
* }
|
|
292
|
+
*/
|
|
293
|
+
export type MarketResolvedEvent = {
|
|
294
|
+
event_type: 'market_resolved';
|
|
295
|
+
id: string;
|
|
296
|
+
question: string;
|
|
297
|
+
market: string;
|
|
298
|
+
slug: string;
|
|
299
|
+
description: string;
|
|
300
|
+
assets_ids: string[];
|
|
301
|
+
outcomes: string[];
|
|
302
|
+
winning_asset_id: string;
|
|
303
|
+
winning_outcome: string;
|
|
304
|
+
event_message: EventMessage;
|
|
305
|
+
timestamp: string;
|
|
306
|
+
};
|
|
307
|
+
/**
|
|
308
|
+
* Union type representing all possible event types from Polymarket WebSocket
|
|
309
|
+
* @example BookEvent
|
|
310
|
+
* {
|
|
311
|
+
* market: "0xf83fb46dd70a4459fcc441a8511701c463374c5c3c250f585d74fda85ddfb7c9",
|
|
312
|
+
* asset_id: "101007741586870489619361069512452187353898396425142157315847015703471254508752",
|
|
313
|
+
* timestamp: "1740759191594",
|
|
314
|
+
* hash: "c0e51b1cfdbcb1b2aec58feaf7b01004019a89c6",
|
|
315
|
+
* bids: [{ price: "0.01", size: "510000" }],
|
|
316
|
+
* asks: [{ price: "0.99", size: "58.07" }],
|
|
317
|
+
* event_type: "book"
|
|
318
|
+
* }
|
|
319
|
+
*
|
|
320
|
+
* @example LastTradePriceEvent
|
|
321
|
+
* {
|
|
322
|
+
* asset_id: "101007741586870489619361069512452187353898396425142157315847015703471254508752",
|
|
323
|
+
* event_type: "last_trade_price",
|
|
324
|
+
* fee_rate_bps: "0",
|
|
325
|
+
* market: "0xf83fb46dd70a4459fcc441a8511701c463374c5c3c250f585d74fda85ddfb7c9",
|
|
326
|
+
* price: "0.12",
|
|
327
|
+
* side: "BUY",
|
|
328
|
+
* size: "8.333332",
|
|
329
|
+
* timestamp: "1740760245471"
|
|
330
|
+
* }
|
|
331
|
+
*
|
|
332
|
+
* @example PriceChangeEvent
|
|
333
|
+
* {
|
|
334
|
+
* market: "0x5f65177b394277fd294cd75650044e32ba009a95022d88a0c1d565897d72f8f1",
|
|
335
|
+
* price_changes: [
|
|
336
|
+
* {
|
|
337
|
+
* asset_id: "71321045679252212594626385532706912750332728571942532289631379312455583992563",
|
|
338
|
+
* price: "0.5",
|
|
339
|
+
* size: "200",
|
|
340
|
+
* side: "BUY",
|
|
341
|
+
* hash: "56621a121a47ed9333273e21c83b660cff37ae50",
|
|
342
|
+
* best_bid: "0.5",
|
|
343
|
+
* best_ask: "1"
|
|
344
|
+
* }
|
|
345
|
+
* ],
|
|
346
|
+
* timestamp: "1757908892351",
|
|
347
|
+
* event_type: "price_change"
|
|
348
|
+
* }
|
|
349
|
+
*
|
|
350
|
+
* @example TickSizeChangeEvent
|
|
351
|
+
* {
|
|
352
|
+
* event_type: "tick_size_change",
|
|
353
|
+
* asset_id: "65818619657568813474341868652308942079804919287380422192892211131408793125422",
|
|
354
|
+
* market: "0xbd31dc8a20211944f6b70f31557f1001557b59905b7738480ca09bd4532f84af",
|
|
355
|
+
* old_tick_size: "0.01",
|
|
356
|
+
* new_tick_size: "0.001",
|
|
357
|
+
* timestamp: "100000000"
|
|
358
|
+
* }
|
|
359
|
+
*/
|
|
360
|
+
export type PolymarketWSEvent = BookEvent | LastTradePriceEvent | PriceChangeEvent | TickSizeChangeEvent | BestBidAskEvent | NewMarketEvent | MarketResolvedEvent;
|
|
361
|
+
/**
|
|
362
|
+
* Represents a price update event
|
|
363
|
+
*
|
|
364
|
+
* This is an event that is emitted to faciliate price update events. It is
|
|
365
|
+
* not emitted by the Polymarket WebSocket directly.
|
|
366
|
+
*
|
|
367
|
+
* See https://docs.polymarket.com/polymarket-learn/trading/how-are-prices-calculated
|
|
368
|
+
*
|
|
369
|
+
* TLDR: The prices displayed on Polymarket are the midpoint of the bid-ask spread in the orderbook,
|
|
370
|
+
* UNLESS that spread is over $0.10, in which case the **last traded price** is used.
|
|
371
|
+
*/
|
|
372
|
+
export interface PolymarketPriceUpdateEvent {
|
|
373
|
+
event_type: 'price_update';
|
|
374
|
+
asset_id: string;
|
|
375
|
+
timestamp: string;
|
|
376
|
+
triggeringEvent: LastTradePriceEvent | PriceChangeEvent;
|
|
377
|
+
book: Book;
|
|
378
|
+
price: string;
|
|
379
|
+
midpoint: string;
|
|
380
|
+
spread: string;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Represents the handlers for the Polymarket WebSocket
|
|
384
|
+
*/
|
|
385
|
+
export type WebSocketHandlers = {
|
|
386
|
+
onBook?: (events: BookEvent[]) => Promise<void>;
|
|
387
|
+
onLastTradePrice?: (events: LastTradePriceEvent[]) => Promise<void>;
|
|
388
|
+
onTickSizeChange?: (events: TickSizeChangeEvent[]) => Promise<void>;
|
|
389
|
+
onPriceChange?: (events: PriceChangeEvent[]) => Promise<void>;
|
|
390
|
+
onBestBidAsk?: (events: BestBidAskEvent[]) => Promise<void>;
|
|
391
|
+
onNewMarket?: (events: NewMarketEvent[]) => Promise<void>;
|
|
392
|
+
onMarketResolved?: (events: MarketResolvedEvent[]) => Promise<void>;
|
|
393
|
+
onPolymarketPriceUpdate?: (events: PolymarketPriceUpdateEvent[]) => Promise<void>;
|
|
394
|
+
onError?: (error: Error) => Promise<void>;
|
|
395
|
+
onWSClose?: (managerId: string, code: number, reason: string) => Promise<void>;
|
|
396
|
+
onWSOpen?: (managerId: string, pendingAssetIds: string[]) => Promise<void>;
|
|
397
|
+
};
|
|
398
|
+
/**
|
|
399
|
+
* Type guard to check if an event is a BookEvent
|
|
400
|
+
* @example
|
|
401
|
+
* if (isBookEvent(event)) {
|
|
402
|
+
* // event is now typed as BookEvent
|
|
403
|
+
* console.log(event.bids);
|
|
404
|
+
* }
|
|
405
|
+
*/
|
|
406
|
+
export declare function isBookEvent(event: PolymarketWSEvent | PolymarketPriceUpdateEvent): event is BookEvent;
|
|
407
|
+
/**
|
|
408
|
+
* Type guard to check if an event is a LastTradePriceEvent
|
|
409
|
+
* @example
|
|
410
|
+
* if (isLastTradePriceEvent(event)) {
|
|
411
|
+
* // event is now typed as LastTradePriceEvent
|
|
412
|
+
* console.log(event.side);
|
|
413
|
+
* }
|
|
414
|
+
*/
|
|
415
|
+
export declare function isLastTradePriceEvent(event: PolymarketWSEvent | PolymarketPriceUpdateEvent): event is LastTradePriceEvent;
|
|
416
|
+
/**
|
|
417
|
+
* Type guard to check if an event is a PriceChangeEvent
|
|
418
|
+
* @example
|
|
419
|
+
* if (isPriceChangeEvent(event)) {
|
|
420
|
+
* // event is now typed as PriceChangeEvent
|
|
421
|
+
* console.log(event.changes);
|
|
422
|
+
* }
|
|
423
|
+
*/
|
|
424
|
+
export declare function isPriceChangeEvent(event: PolymarketWSEvent | PolymarketPriceUpdateEvent): event is PriceChangeEvent;
|
|
425
|
+
/**
|
|
426
|
+
* Type guard to check if an event is a TickSizeChangeEvent
|
|
427
|
+
* @example
|
|
428
|
+
* if (isTickSizeChangeEvent(event)) {
|
|
429
|
+
* // event is now typed as TickSizeChangeEvent
|
|
430
|
+
* console.log(event.old_tick_size);
|
|
431
|
+
* }
|
|
432
|
+
*/
|
|
433
|
+
export declare function isTickSizeChangeEvent(event: PolymarketWSEvent | PolymarketPriceUpdateEvent): event is TickSizeChangeEvent;
|
|
434
|
+
/**
|
|
435
|
+
* Type guard to check if an event is a BestBidAskEvent
|
|
436
|
+
* @example
|
|
437
|
+
* if (isBestBidAskEvent(event)) {
|
|
438
|
+
* // event is now typed as BestBidAskEvent
|
|
439
|
+
* console.log(event.best_bid, event.best_ask);
|
|
440
|
+
* }
|
|
441
|
+
*/
|
|
442
|
+
export declare function isBestBidAskEvent(event: PolymarketWSEvent | PolymarketPriceUpdateEvent): event is BestBidAskEvent;
|
|
443
|
+
/**
|
|
444
|
+
* Type guard to check if an event is a NewMarketEvent
|
|
445
|
+
* @example
|
|
446
|
+
* if (isNewMarketEvent(event)) {
|
|
447
|
+
* // event is now typed as NewMarketEvent
|
|
448
|
+
* console.log(event.question);
|
|
449
|
+
* }
|
|
450
|
+
*/
|
|
451
|
+
export declare function isNewMarketEvent(event: PolymarketWSEvent | PolymarketPriceUpdateEvent): event is NewMarketEvent;
|
|
452
|
+
/**
|
|
453
|
+
* Type guard to check if an event is a MarketResolvedEvent
|
|
454
|
+
* @example
|
|
455
|
+
* if (isMarketResolvedEvent(event)) {
|
|
456
|
+
* // event is now typed as MarketResolvedEvent
|
|
457
|
+
* console.log(event.winning_outcome);
|
|
458
|
+
* }
|
|
459
|
+
*/
|
|
460
|
+
export declare function isMarketResolvedEvent(event: PolymarketWSEvent | PolymarketPriceUpdateEvent): event is MarketResolvedEvent;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isBookEvent = isBookEvent;
|
|
4
|
+
exports.isLastTradePriceEvent = isLastTradePriceEvent;
|
|
5
|
+
exports.isPriceChangeEvent = isPriceChangeEvent;
|
|
6
|
+
exports.isTickSizeChangeEvent = isTickSizeChangeEvent;
|
|
7
|
+
exports.isBestBidAskEvent = isBestBidAskEvent;
|
|
8
|
+
exports.isNewMarketEvent = isNewMarketEvent;
|
|
9
|
+
exports.isMarketResolvedEvent = isMarketResolvedEvent;
|
|
10
|
+
/**
|
|
11
|
+
* Type guard to check if an event is a BookEvent
|
|
12
|
+
* @example
|
|
13
|
+
* if (isBookEvent(event)) {
|
|
14
|
+
* // event is now typed as BookEvent
|
|
15
|
+
* console.log(event.bids);
|
|
16
|
+
* }
|
|
17
|
+
*/
|
|
18
|
+
function isBookEvent(event) {
|
|
19
|
+
return (event === null || event === void 0 ? void 0 : event.event_type) === 'book';
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Type guard to check if an event is a LastTradePriceEvent
|
|
23
|
+
* @example
|
|
24
|
+
* if (isLastTradePriceEvent(event)) {
|
|
25
|
+
* // event is now typed as LastTradePriceEvent
|
|
26
|
+
* console.log(event.side);
|
|
27
|
+
* }
|
|
28
|
+
*/
|
|
29
|
+
function isLastTradePriceEvent(event) {
|
|
30
|
+
return (event === null || event === void 0 ? void 0 : event.event_type) === 'last_trade_price';
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Type guard to check if an event is a PriceChangeEvent
|
|
34
|
+
* @example
|
|
35
|
+
* if (isPriceChangeEvent(event)) {
|
|
36
|
+
* // event is now typed as PriceChangeEvent
|
|
37
|
+
* console.log(event.changes);
|
|
38
|
+
* }
|
|
39
|
+
*/
|
|
40
|
+
function isPriceChangeEvent(event) {
|
|
41
|
+
return (event === null || event === void 0 ? void 0 : event.event_type) === 'price_change';
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Type guard to check if an event is a TickSizeChangeEvent
|
|
45
|
+
* @example
|
|
46
|
+
* if (isTickSizeChangeEvent(event)) {
|
|
47
|
+
* // event is now typed as TickSizeChangeEvent
|
|
48
|
+
* console.log(event.old_tick_size);
|
|
49
|
+
* }
|
|
50
|
+
*/
|
|
51
|
+
function isTickSizeChangeEvent(event) {
|
|
52
|
+
return (event === null || event === void 0 ? void 0 : event.event_type) === 'tick_size_change';
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Type guard to check if an event is a BestBidAskEvent
|
|
56
|
+
* @example
|
|
57
|
+
* if (isBestBidAskEvent(event)) {
|
|
58
|
+
* // event is now typed as BestBidAskEvent
|
|
59
|
+
* console.log(event.best_bid, event.best_ask);
|
|
60
|
+
* }
|
|
61
|
+
*/
|
|
62
|
+
function isBestBidAskEvent(event) {
|
|
63
|
+
return (event === null || event === void 0 ? void 0 : event.event_type) === 'best_bid_ask';
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Type guard to check if an event is a NewMarketEvent
|
|
67
|
+
* @example
|
|
68
|
+
* if (isNewMarketEvent(event)) {
|
|
69
|
+
* // event is now typed as NewMarketEvent
|
|
70
|
+
* console.log(event.question);
|
|
71
|
+
* }
|
|
72
|
+
*/
|
|
73
|
+
function isNewMarketEvent(event) {
|
|
74
|
+
return (event === null || event === void 0 ? void 0 : event.event_type) === 'new_market';
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Type guard to check if an event is a MarketResolvedEvent
|
|
78
|
+
* @example
|
|
79
|
+
* if (isMarketResolvedEvent(event)) {
|
|
80
|
+
* // event is now typed as MarketResolvedEvent
|
|
81
|
+
* console.log(event.winning_outcome);
|
|
82
|
+
* }
|
|
83
|
+
*/
|
|
84
|
+
function isMarketResolvedEvent(event) {
|
|
85
|
+
return (event === null || event === void 0 ? void 0 : event.event_type) === 'market_resolved';
|
|
86
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connection status for the WebSocket.
|
|
3
|
+
*/
|
|
4
|
+
export declare enum WebSocketConnectionStatus {
|
|
5
|
+
DISCONNECTED = "disconnected",
|
|
6
|
+
CONNECTING = "connecting",
|
|
7
|
+
CONNECTED = "connected"
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Options for configuring the WSSubscriptionManager.
|
|
11
|
+
*/
|
|
12
|
+
export type SubscriptionManagerOptions = {
|
|
13
|
+
/**
|
|
14
|
+
* How often to check for reconnection (in milliseconds).
|
|
15
|
+
* Default: 5000ms (5 seconds)
|
|
16
|
+
*
|
|
17
|
+
* Note: We intentionally use a static interval rather than exponential backoff.
|
|
18
|
+
* Perhaps change this to exponential backoff in the future.
|
|
19
|
+
*/
|
|
20
|
+
reconnectAndCleanupIntervalMs?: number;
|
|
21
|
+
/**
|
|
22
|
+
* How often to flush pending subscriptions to the WebSocket (in milliseconds).
|
|
23
|
+
* Default: 100ms
|
|
24
|
+
*/
|
|
25
|
+
pendingFlushIntervalMs?: number;
|
|
26
|
+
/**
|
|
27
|
+
* Enable custom features such as new_market and market_resolved events.
|
|
28
|
+
* When enabled, sets the custom_feature_enabled flag in WebSocket messages.
|
|
29
|
+
* Default: false
|
|
30
|
+
*/
|
|
31
|
+
enableCustomFeatures?: boolean;
|
|
32
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WebSocketConnectionStatus = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Connection status for the WebSocket.
|
|
6
|
+
*/
|
|
7
|
+
var WebSocketConnectionStatus;
|
|
8
|
+
(function (WebSocketConnectionStatus) {
|
|
9
|
+
WebSocketConnectionStatus["DISCONNECTED"] = "disconnected";
|
|
10
|
+
WebSocketConnectionStatus["CONNECTING"] = "connecting";
|
|
11
|
+
WebSocketConnectionStatus["CONNECTED"] = "connected";
|
|
12
|
+
})(WebSocketConnectionStatus || (exports.WebSocketConnectionStatus = WebSocketConnectionStatus = {}));
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tentou-tech/poly-websockets",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Plug-and-play Polymarket WebSocket price alerts",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"src"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"prepare": "npm run build && npm run test",
|
|
14
|
+
"test": "vitest run --exclude 'tests/live/**'",
|
|
15
|
+
"test:live": "vitest run tests/live",
|
|
16
|
+
"prepublishOnly": "npm run test:live"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/tentou-tech/poly-websockets.git"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"polymarket",
|
|
24
|
+
"polymarket-api",
|
|
25
|
+
"websocket",
|
|
26
|
+
"price",
|
|
27
|
+
"market",
|
|
28
|
+
"alerts",
|
|
29
|
+
"real-time",
|
|
30
|
+
"trading",
|
|
31
|
+
"prediction-markets"
|
|
32
|
+
],
|
|
33
|
+
"author": "Konstantinos Lekkas",
|
|
34
|
+
"license": "AGPL-3.0",
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": "https://github.com/tentou-tech/poly-websockets/issues"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://github.com/tentou-tech/poly-websockets#readme",
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"lodash": "^4.17.21",
|
|
41
|
+
"ms": "^2.1.3",
|
|
42
|
+
"uuid": "^11.1.0",
|
|
43
|
+
"winston": "^3.17.0",
|
|
44
|
+
"ws": "^8.18.2"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/lodash": "^4.17.17",
|
|
48
|
+
"@types/ms": "^2.1.0",
|
|
49
|
+
"@types/ws": "^8.18.1",
|
|
50
|
+
"typescript": "^5.4.2",
|
|
51
|
+
"vitest": "^3.0.7",
|
|
52
|
+
"@types/node": "^22.13.11"
|
|
53
|
+
}
|
|
54
|
+
}
|