laplace-api 1.3.3 → 1.4.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/package.json
CHANGED
|
@@ -1,23 +1,65 @@
|
|
|
1
|
+
import { WebSocket } from "ws";
|
|
2
|
+
|
|
3
|
+
interface RawBISTStockLiveData {
|
|
4
|
+
_id: number;
|
|
5
|
+
symbol: string;
|
|
6
|
+
cl: number;
|
|
7
|
+
_i: string;
|
|
8
|
+
c: number;
|
|
9
|
+
d: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface RawUSStockLiveData {
|
|
13
|
+
s: string;
|
|
14
|
+
p: number;
|
|
15
|
+
t: number;
|
|
16
|
+
}
|
|
1
17
|
|
|
2
18
|
export interface BISTStockLiveData {
|
|
19
|
+
id: number;
|
|
3
20
|
symbol: string;
|
|
4
|
-
|
|
5
|
-
|
|
21
|
+
closePrice: number;
|
|
22
|
+
tipId: string;
|
|
23
|
+
percentChange: number;
|
|
24
|
+
timestamp: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface USStockLiveData {
|
|
28
|
+
symbol: string;
|
|
29
|
+
closePrice: number;
|
|
30
|
+
timestamp: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export enum LivePriceFeed {
|
|
34
|
+
LiveBist = "live_price_tr",
|
|
35
|
+
LiveUs = "live_price_us",
|
|
36
|
+
DelayedBist = "delayed_price_tr",
|
|
37
|
+
DelayedUs = "delayed_price_us",
|
|
38
|
+
// DepthBist = "depth_tr",
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
type StockLiveDataType<T extends LivePriceFeed> = T extends
|
|
42
|
+
| LivePriceFeed.LiveBist
|
|
43
|
+
| LivePriceFeed.DelayedBist
|
|
44
|
+
? // | LivePriceFeed.DepthBist
|
|
45
|
+
BISTStockLiveData
|
|
46
|
+
: USStockLiveData;
|
|
47
|
+
|
|
48
|
+
export enum LogLevel {
|
|
49
|
+
Info = "info",
|
|
50
|
+
Warn = "warn",
|
|
51
|
+
Error = "error",
|
|
6
52
|
}
|
|
7
53
|
|
|
8
54
|
interface WebSocketOptions {
|
|
9
55
|
enableLogging?: boolean;
|
|
56
|
+
logLevel?: LogLevel;
|
|
10
57
|
reconnectAttempts?: number;
|
|
11
58
|
reconnectDelay?: number;
|
|
12
59
|
maxReconnectDelay?: number;
|
|
13
60
|
}
|
|
14
61
|
|
|
15
|
-
type WebSocketMessageType = "heartbeat" | "error" | "warning" | "
|
|
16
|
-
|
|
17
|
-
interface WebSocketMessage<T> {
|
|
18
|
-
type: WebSocketMessageType;
|
|
19
|
-
message?: T;
|
|
20
|
-
}
|
|
62
|
+
type WebSocketMessageType = "heartbeat" | "error" | "warning" | "data";
|
|
21
63
|
|
|
22
64
|
export enum WebSocketErrorType {
|
|
23
65
|
MAX_RECONNECT_EXCEEDED = "MAX_RECONNECT_EXCEEDED",
|
|
@@ -54,7 +96,8 @@ export class LivePriceWebSocketClient {
|
|
|
54
96
|
number,
|
|
55
97
|
{
|
|
56
98
|
symbols: string[];
|
|
57
|
-
handler: (data: BISTStockLiveData) => void;
|
|
99
|
+
handler: (data: BISTStockLiveData | USStockLiveData) => void;
|
|
100
|
+
feed: LivePriceFeed;
|
|
58
101
|
}
|
|
59
102
|
>();
|
|
60
103
|
private reconnectAttempts = 0;
|
|
@@ -68,6 +111,7 @@ export class LivePriceWebSocketClient {
|
|
|
68
111
|
constructor(options: WebSocketOptions = {}) {
|
|
69
112
|
this.options = {
|
|
70
113
|
enableLogging: true,
|
|
114
|
+
logLevel: LogLevel.Error,
|
|
71
115
|
reconnectAttempts: 5,
|
|
72
116
|
reconnectDelay: 5000,
|
|
73
117
|
maxReconnectDelay: 30000,
|
|
@@ -79,6 +123,15 @@ export class LivePriceWebSocketClient {
|
|
|
79
123
|
if (!this.options.enableLogging) return;
|
|
80
124
|
|
|
81
125
|
const prefix = `[LivePriceWebSocket][${level.toUpperCase()}]`;
|
|
126
|
+
const logLevel = this.options.logLevel;
|
|
127
|
+
|
|
128
|
+
if (logLevel === LogLevel.Error && level !== "error") {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (logLevel === LogLevel.Warn && level === "info") {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
82
135
|
|
|
83
136
|
switch (level) {
|
|
84
137
|
case "error":
|
|
@@ -101,10 +154,9 @@ export class LivePriceWebSocketClient {
|
|
|
101
154
|
this.ws = new WebSocket(url);
|
|
102
155
|
this.connectPromise = this.setupWebSocket();
|
|
103
156
|
|
|
104
|
-
await this.connectPromise
|
|
157
|
+
await this.connectPromise;
|
|
105
158
|
|
|
106
159
|
this.connectPromise = null;
|
|
107
|
-
|
|
108
160
|
}
|
|
109
161
|
|
|
110
162
|
return this.ws;
|
|
@@ -175,19 +227,48 @@ export class LivePriceWebSocketClient {
|
|
|
175
227
|
this.ws.onmessage = (event) => {
|
|
176
228
|
try {
|
|
177
229
|
const rawData = JSON.parse(event.data.toString());
|
|
230
|
+
|
|
231
|
+
const feed = rawData.feed as LivePriceFeed;
|
|
178
232
|
switch (rawData.type) {
|
|
179
|
-
case "
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
if (!data) {
|
|
233
|
+
case "data":
|
|
234
|
+
const messageData = rawData.message;
|
|
235
|
+
if (!messageData) {
|
|
183
236
|
throw new WebSocketError(
|
|
184
237
|
"Price update message is empty",
|
|
185
238
|
WebSocketErrorType.MESSAGE_PARSE_ERROR
|
|
186
239
|
);
|
|
187
240
|
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
241
|
+
let priceData: BISTStockLiveData | USStockLiveData;
|
|
242
|
+
|
|
243
|
+
if (
|
|
244
|
+
feed === LivePriceFeed.DelayedBist ||
|
|
245
|
+
feed === LivePriceFeed.LiveBist
|
|
246
|
+
// ||
|
|
247
|
+
// feed === LivePriceFeed.DepthBist
|
|
248
|
+
) {
|
|
249
|
+
const message = messageData as RawBISTStockLiveData;
|
|
250
|
+
priceData = {
|
|
251
|
+
symbol: message?.symbol,
|
|
252
|
+
id: message?._id,
|
|
253
|
+
tipId: message?._i,
|
|
254
|
+
closePrice: message?.cl,
|
|
255
|
+
timestamp: message?.d,
|
|
256
|
+
percentChange: message?.c,
|
|
257
|
+
} as BISTStockLiveData;
|
|
258
|
+
} else {
|
|
259
|
+
const message = messageData as RawUSStockLiveData;
|
|
260
|
+
priceData = {
|
|
261
|
+
symbol: message.s,
|
|
262
|
+
closePrice: message.p,
|
|
263
|
+
timestamp: message.t,
|
|
264
|
+
} as USStockLiveData;
|
|
265
|
+
}
|
|
266
|
+
if (priceData.symbol) {
|
|
267
|
+
const handlers = this.getHandlersForSymbol(
|
|
268
|
+
priceData.symbol,
|
|
269
|
+
feed
|
|
270
|
+
);
|
|
271
|
+
handlers.forEach((handler) => handler(priceData));
|
|
191
272
|
}
|
|
192
273
|
break;
|
|
193
274
|
case "heartbeat":
|
|
@@ -210,14 +291,6 @@ export class LivePriceWebSocketClient {
|
|
|
210
291
|
});
|
|
211
292
|
}
|
|
212
293
|
|
|
213
|
-
private getActiveSymbols(): string[] {
|
|
214
|
-
const allSymbols = Array.from(this.subscriptions.values()).flatMap(
|
|
215
|
-
(sub) => sub.symbols
|
|
216
|
-
);
|
|
217
|
-
|
|
218
|
-
return [...new Set(allSymbols)];
|
|
219
|
-
}
|
|
220
|
-
|
|
221
294
|
private async attemptReconnect() {
|
|
222
295
|
const url = this.wsUrl;
|
|
223
296
|
if (!url) {
|
|
@@ -251,11 +324,28 @@ export class LivePriceWebSocketClient {
|
|
|
251
324
|
this.reconnectTimeout = setTimeout(async () => {
|
|
252
325
|
try {
|
|
253
326
|
await this.connect(url);
|
|
254
|
-
|
|
255
|
-
this.isClosed = false
|
|
256
327
|
|
|
257
|
-
|
|
258
|
-
|
|
328
|
+
this.isClosed = false;
|
|
329
|
+
|
|
330
|
+
const symbolsByFeed = new Map<LivePriceFeed, string[]>();
|
|
331
|
+
|
|
332
|
+
this.subscriptions.forEach((subscription) => {
|
|
333
|
+
const { symbols, feed } = subscription;
|
|
334
|
+
if (!symbolsByFeed.has(feed)) {
|
|
335
|
+
symbolsByFeed.set(feed, []);
|
|
336
|
+
}
|
|
337
|
+
symbols.forEach((symbol) => {
|
|
338
|
+
const currentSymbols = symbolsByFeed.get(feed) || [];
|
|
339
|
+
if (!currentSymbols.includes(symbol)) {
|
|
340
|
+
currentSymbols.push(symbol);
|
|
341
|
+
symbolsByFeed.set(feed, currentSymbols);
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
symbolsByFeed.forEach((symbols, feed) => {
|
|
347
|
+
this.addSymbols(symbols, feed);
|
|
348
|
+
});
|
|
259
349
|
|
|
260
350
|
if (this.reconnectTimeout) {
|
|
261
351
|
clearTimeout(this.reconnectTimeout);
|
|
@@ -272,40 +362,50 @@ export class LivePriceWebSocketClient {
|
|
|
272
362
|
}
|
|
273
363
|
}
|
|
274
364
|
|
|
275
|
-
subscribe(
|
|
365
|
+
subscribe<F extends LivePriceFeed>(
|
|
276
366
|
symbols: string[],
|
|
277
|
-
|
|
367
|
+
feed: F,
|
|
368
|
+
handler: (data: StockLiveDataType<F>) => void
|
|
278
369
|
): () => void {
|
|
279
370
|
const subscriptionId = this.subscriptionCounter++;
|
|
280
371
|
let symbolsToAdd: string[] = [];
|
|
281
372
|
|
|
282
|
-
|
|
373
|
+
const typedHandler = (data: BISTStockLiveData | USStockLiveData) => {
|
|
374
|
+
handler(data as StockLiveDataType<F>);
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
this.subscriptions.set(subscriptionId, {
|
|
378
|
+
symbols,
|
|
379
|
+
feed,
|
|
380
|
+
handler: typedHandler,
|
|
381
|
+
});
|
|
283
382
|
|
|
284
383
|
for (const symbol of symbols) {
|
|
285
|
-
if (this.getHandlersForSymbol(symbol).length === 1) {
|
|
384
|
+
if (this.getHandlersForSymbol(symbol, feed).length === 1) {
|
|
286
385
|
symbolsToAdd.push(symbol);
|
|
287
386
|
}
|
|
288
387
|
}
|
|
289
|
-
this.addSymbols(symbolsToAdd);
|
|
388
|
+
this.addSymbols(symbolsToAdd, feed);
|
|
290
389
|
|
|
291
390
|
return () => {
|
|
292
391
|
this.subscriptions.delete(subscriptionId);
|
|
293
392
|
const symbolsForRemove = symbols.filter(
|
|
294
|
-
(s) => this.getHandlersForSymbol(s).length === 0
|
|
393
|
+
(s) => this.getHandlersForSymbol(s, feed).length === 0
|
|
295
394
|
);
|
|
296
|
-
this.removeSymbols(symbolsForRemove);
|
|
395
|
+
this.removeSymbols(symbolsForRemove, feed);
|
|
297
396
|
};
|
|
298
397
|
}
|
|
299
398
|
|
|
300
399
|
private getHandlersForSymbol(
|
|
301
|
-
symbol: string
|
|
302
|
-
|
|
400
|
+
symbol: string,
|
|
401
|
+
feed: LivePriceFeed
|
|
402
|
+
): ((data: BISTStockLiveData | USStockLiveData) => void)[] {
|
|
303
403
|
return Array.from(this.subscriptions.values())
|
|
304
|
-
.filter((s) => s.symbols.includes(symbol))
|
|
404
|
+
.filter((s) => s.symbols.includes(symbol) && s.feed === feed)
|
|
305
405
|
.map((s) => s.handler);
|
|
306
406
|
}
|
|
307
407
|
|
|
308
|
-
private async removeSymbols(symbols: string[]) {
|
|
408
|
+
private async removeSymbols(symbols: string[], feed: LivePriceFeed) {
|
|
309
409
|
if (symbols.length === 0) return;
|
|
310
410
|
|
|
311
411
|
if (!this.ws) {
|
|
@@ -316,7 +416,7 @@ export class LivePriceWebSocketClient {
|
|
|
316
416
|
}
|
|
317
417
|
|
|
318
418
|
if (this.connectPromise) {
|
|
319
|
-
await this.connectPromise
|
|
419
|
+
await this.connectPromise;
|
|
320
420
|
}
|
|
321
421
|
|
|
322
422
|
if (this.ws.readyState !== WebSocket.OPEN) {
|
|
@@ -325,15 +425,17 @@ export class LivePriceWebSocketClient {
|
|
|
325
425
|
WebSocketErrorType.WEBSOCKET_NOT_CONNECTED
|
|
326
426
|
);
|
|
327
427
|
}
|
|
428
|
+
|
|
328
429
|
this.ws.send(
|
|
329
430
|
JSON.stringify({
|
|
330
431
|
type: "unsubscribe",
|
|
331
432
|
symbols: symbols,
|
|
433
|
+
feed: feed,
|
|
332
434
|
})
|
|
333
435
|
);
|
|
334
436
|
}
|
|
335
437
|
|
|
336
|
-
private async addSymbols(symbols: string[]) {
|
|
438
|
+
private async addSymbols(symbols: string[], feed: LivePriceFeed) {
|
|
337
439
|
if (symbols.length === 0) return;
|
|
338
440
|
|
|
339
441
|
if (!this.ws) {
|
|
@@ -344,7 +446,7 @@ export class LivePriceWebSocketClient {
|
|
|
344
446
|
}
|
|
345
447
|
|
|
346
448
|
if (this.connectPromise) {
|
|
347
|
-
await this.connectPromise
|
|
449
|
+
await this.connectPromise;
|
|
348
450
|
}
|
|
349
451
|
|
|
350
452
|
if (this.ws.readyState !== WebSocket.OPEN) {
|
|
@@ -358,6 +460,7 @@ export class LivePriceWebSocketClient {
|
|
|
358
460
|
JSON.stringify({
|
|
359
461
|
type: "subscribe",
|
|
360
462
|
symbols: symbols,
|
|
463
|
+
feed: feed,
|
|
361
464
|
})
|
|
362
465
|
);
|
|
363
466
|
}
|
package/src/client/live-price.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Client } from "./client";
|
|
2
2
|
import { Region } from "./collections";
|
|
3
3
|
import { v4 as uuidv4 } from 'uuid';
|
|
4
|
+
import { LivePriceFeed } from "./live-price-web-socket";
|
|
4
5
|
|
|
5
6
|
interface WebSocketUrlResponse {
|
|
6
7
|
url: string;
|
|
@@ -8,6 +9,7 @@ interface WebSocketUrlResponse {
|
|
|
8
9
|
|
|
9
10
|
interface WebSocketUrlParams {
|
|
10
11
|
externalUserId: string;
|
|
12
|
+
feeds: LivePriceFeed[];
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
export interface BISTStockLiveData {
|
|
@@ -39,14 +41,15 @@ function getSSELivePrice<T>(
|
|
|
39
41
|
export class LivePriceClient extends Client {
|
|
40
42
|
async getWebSocketUrl(
|
|
41
43
|
externalUserId: string,
|
|
42
|
-
region: Region
|
|
44
|
+
region: Region,
|
|
45
|
+
feeds: LivePriceFeed[]
|
|
43
46
|
): Promise<string> {
|
|
44
|
-
const url = new URL(`${this["baseUrl"]}/api/
|
|
47
|
+
const url = new URL(`${this["baseUrl"]}/api/v2/ws/url`);
|
|
45
48
|
url.searchParams.append("region", region);
|
|
46
|
-
url.searchParams.append("accessLevel", "KRMD1");
|
|
47
49
|
|
|
48
50
|
const params: WebSocketUrlParams = {
|
|
49
51
|
externalUserId,
|
|
52
|
+
feeds
|
|
50
53
|
};
|
|
51
54
|
|
|
52
55
|
const response = await this.sendRequest<WebSocketUrlResponse>({
|
|
@@ -5,7 +5,9 @@ import "./client_test_suite";
|
|
|
5
5
|
import { LivePriceClient } from "../client/live-price";
|
|
6
6
|
import {
|
|
7
7
|
BISTStockLiveData,
|
|
8
|
+
LivePriceFeed,
|
|
8
9
|
LivePriceWebSocketClient,
|
|
10
|
+
USStockLiveData,
|
|
9
11
|
} from "../client/live-price-web-socket";
|
|
10
12
|
|
|
11
13
|
describe("LivePrice", () => {
|
|
@@ -28,7 +30,9 @@ describe("LivePrice", () => {
|
|
|
28
30
|
} as unknown as Logger;
|
|
29
31
|
|
|
30
32
|
livePriceUrlClient = new LivePriceClient(config, logger);
|
|
31
|
-
url = await livePriceUrlClient.getWebSocketUrl("2459", Region.Tr
|
|
33
|
+
url = await livePriceUrlClient.getWebSocketUrl("2459", Region.Tr, [
|
|
34
|
+
LivePriceFeed.LiveBist,
|
|
35
|
+
]);
|
|
32
36
|
|
|
33
37
|
ws = new LivePriceWebSocketClient({
|
|
34
38
|
enableLogging: true,
|
|
@@ -47,22 +51,28 @@ describe("LivePrice", () => {
|
|
|
47
51
|
|
|
48
52
|
describe("BIST Live Price Tests", () => {
|
|
49
53
|
const symbols = ["TUPRS", "SASA", "THYAO", "GARAN", "YKBNK"];
|
|
50
|
-
// const newSymbols = ["AKBNK", "KCHOL"];
|
|
51
54
|
|
|
52
55
|
it(
|
|
53
56
|
"should receive data for initial and updated symbols",
|
|
54
57
|
async () => {
|
|
55
58
|
const receivedData: BISTStockLiveData[] = [];
|
|
56
59
|
|
|
57
|
-
let unsubscribe: (() => void) | null =
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
let unsubscribe: (() => void) | null =
|
|
61
|
+
ws.subscribe<LivePriceFeed.LiveBist>(
|
|
62
|
+
symbols,
|
|
63
|
+
LivePriceFeed.LiveBist,
|
|
64
|
+
(data) => {
|
|
65
|
+
console.log("RECEIVED DATA", data);
|
|
66
|
+
receivedData.push(data);
|
|
67
|
+
}
|
|
68
|
+
);
|
|
61
69
|
|
|
62
70
|
await new Promise((resolve) => setTimeout(resolve, 20000));
|
|
63
71
|
|
|
64
72
|
for (const symbol of symbols) {
|
|
65
|
-
const symbolData = receivedData.filter(
|
|
73
|
+
const symbolData = receivedData.filter(
|
|
74
|
+
(data) => data.symbol === symbol
|
|
75
|
+
);
|
|
66
76
|
expect(symbolData.length).toBeGreaterThan(0);
|
|
67
77
|
}
|
|
68
78
|
|
|
@@ -70,72 +80,39 @@ describe("LivePrice", () => {
|
|
|
70
80
|
},
|
|
71
81
|
TEST_CONSTANTS.JEST_TIMEOUT
|
|
72
82
|
);
|
|
73
|
-
|
|
74
|
-
// it(
|
|
75
|
-
// "should handle multiple subscriptions for the same symbol",
|
|
76
|
-
// async () => {
|
|
77
|
-
// const symbol = "GARAN";
|
|
78
|
-
// const receivedData1: BISTStockLiveData[] = [];
|
|
79
|
-
// const receivedData2: BISTStockLiveData[] = [];
|
|
80
|
-
|
|
81
|
-
// await new Promise<void>((resolve, reject) => {
|
|
82
|
-
// const timeoutId = setTimeout(() => {
|
|
83
|
-
// reject(new Error("Test timeout: No data received"));
|
|
84
|
-
// }, TEST_CONSTANTS.MAIN_TIMEOUT).unref();
|
|
85
|
-
|
|
86
|
-
// const unsubscribe1 = ws.subscribe([symbol], (data) => {
|
|
87
|
-
// receivedData1.push(data);
|
|
88
|
-
// });
|
|
89
|
-
|
|
90
|
-
// const unsubscribe2 = ws.subscribe([symbol], (data) => {
|
|
91
|
-
// receivedData2.push(data);
|
|
92
|
-
// if (receivedData2.length >= 2) {
|
|
93
|
-
// clearTimeout(timeoutId);
|
|
94
|
-
// unsubscribe1();
|
|
95
|
-
// unsubscribe2();
|
|
96
|
-
// resolve();
|
|
97
|
-
// }
|
|
98
|
-
// });
|
|
99
|
-
// });
|
|
100
|
-
|
|
101
|
-
// expect(receivedData1.length).toBeGreaterThan(0);
|
|
102
|
-
// expect(receivedData2.length).toBeGreaterThan(0);
|
|
103
|
-
// expect(receivedData1).toEqual(receivedData2);
|
|
104
|
-
// },
|
|
105
|
-
// TEST_CONSTANTS.JEST_TIMEOUT
|
|
106
|
-
// );
|
|
107
83
|
});
|
|
108
84
|
|
|
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
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
85
|
+
//TODO: Use this test after region issue fixed
|
|
86
|
+
// describe("US Live Price Tests", () => {
|
|
87
|
+
// const symbols = ["AAPL"];
|
|
88
|
+
|
|
89
|
+
// it(
|
|
90
|
+
// "should receive data for initial and updated symbols for us",
|
|
91
|
+
// async () => {
|
|
92
|
+
// const receivedData: USStockLiveData[] = [];
|
|
93
|
+
|
|
94
|
+
// let unsubscribe: (() => void) | null =
|
|
95
|
+
// ws.subscribe<LivePriceFeed.LiveUs>(
|
|
96
|
+
// symbols,
|
|
97
|
+
// LivePriceFeed.LiveUs,
|
|
98
|
+
// (data) => {
|
|
99
|
+
// console.log("RECEIVED DATA FOR US", data);
|
|
100
|
+
// receivedData.push(data);
|
|
101
|
+
// }
|
|
102
|
+
// );
|
|
103
|
+
|
|
104
|
+
// await new Promise((resolve) => setTimeout(resolve, 20000));
|
|
105
|
+
|
|
106
|
+
// for (const symbol of symbols) {
|
|
107
|
+
// const symbolData = receivedData.filter(
|
|
108
|
+
// (data) => data.symbol === symbol
|
|
109
|
+
// );
|
|
110
|
+
// expect(symbolData.length).toBeGreaterThan(0);
|
|
111
|
+
// }
|
|
112
|
+
|
|
113
|
+
// unsubscribe();
|
|
114
|
+
// },
|
|
115
|
+
// TEST_CONSTANTS.JEST_TIMEOUT
|
|
116
|
+
// );
|
|
117
|
+
// });
|
|
141
118
|
});
|