laplace-api 1.1.3 → 1.1.6

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,6 +1,6 @@
1
1
  {
2
2
  "name": "laplace-api",
3
- "version": "1.1.3",
3
+ "version": "1.1.6",
4
4
  "description": "Client library for Laplace API for the US stock market and BIST (Istanbul stock market) fundamental financial data.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -42,7 +42,8 @@
42
42
  "event-source-polyfill": "^1.0.31",
43
43
  "mongodb": "^6.8.0",
44
44
  "uuid": "^10.0.0",
45
- "winston": "^3.14.2"
45
+ "winston": "^3.14.2",
46
+ "ws": "^8.18.0"
46
47
  },
47
48
  "devDependencies": {
48
49
  "@types/axios": "^0.14.0",
@@ -51,6 +52,7 @@
51
52
  "@types/mongodb": "^4.0.7",
52
53
  "@types/node": "^22.5.4",
53
54
  "@types/winston": "^2.4.4",
55
+ "@types/ws": "^8.5.13",
54
56
  "jest": "^29.7.0",
55
57
  "ts-jest": "^29.2.5",
56
58
  "typescript": "^5.5.4"
@@ -0,0 +1,398 @@
1
+ export interface BISTStockLiveData {
2
+ symbol: string;
3
+ cl: number; // Close
4
+ c: number; // PercentChange
5
+ }
6
+
7
+ interface WebSocketOptions {
8
+ enableLogging?: boolean;
9
+ reconnectAttempts?: number;
10
+ reconnectDelay?: number;
11
+ maxReconnectDelay?: number;
12
+ }
13
+
14
+ type WebSocketMessageType = "heartbeat" | "error" | "warning" | "price_update";
15
+
16
+ interface WebSocketMessage<T> {
17
+ type: WebSocketMessageType;
18
+ message?: T;
19
+ }
20
+
21
+ export enum WebSocketErrorType {
22
+ MAX_RECONNECT_EXCEEDED = "MAX_RECONNECT_EXCEEDED",
23
+ CONNECTION_ERROR = "CONNECTION_ERROR",
24
+ CLOSE_ERROR = "CLOSE_ERROR",
25
+ WEBSOCKET_NOT_INITIALIZED = "WEBSOCKET_NOT_INITIALIZED",
26
+ MESSAGE_PARSE_ERROR = "MESSAGE_PARSE_ERROR",
27
+ WEBSOCKET_NOT_CONNECTED = "WEBSOCKET_NOT_CONNECTED",
28
+ WEBSOCKET_ERROR = "WEBSOCKET_ERROR",
29
+ UNKNOWN_ERROR = "UNKNOWN_ERROR",
30
+ }
31
+
32
+ export enum WebSocketCloseReason {
33
+ NORMAL_CLOSURE = "NORMAL_CLOSURE",
34
+ CONNECTION_ERROR = "CONNECTION_ERROR",
35
+ MAX_RECONNECT_EXCEEDED = "MAX_RECONNECT_EXCEEDED",
36
+ UNKNOWN = "UNKNOWN",
37
+ }
38
+
39
+ export class WebSocketError extends Error {
40
+ constructor(
41
+ message: string,
42
+ public readonly code: WebSocketErrorType = WebSocketErrorType.UNKNOWN_ERROR
43
+ ) {
44
+ super(message);
45
+ this.name = "WebSocketError";
46
+ }
47
+ }
48
+
49
+ export class LivePriceWebSocketClient {
50
+ private ws: WebSocket | null = null;
51
+ private subscriptionCounter = 0;
52
+ private subscriptions = new Map<
53
+ number,
54
+ {
55
+ symbols: string[];
56
+ handler: (data: BISTStockLiveData) => void;
57
+ }
58
+ >();
59
+ private reconnectAttempts = 0;
60
+ private reconnectTimeout: NodeJS.Timeout | null = null;
61
+ private isClosed: boolean = false;
62
+ private closedReason: WebSocketCloseReason | null = null;
63
+ private wsUrl: string | null = null;
64
+ private readonly options: Required<WebSocketOptions>;
65
+
66
+ constructor(options: WebSocketOptions = {}) {
67
+ this.options = {
68
+ enableLogging: true,
69
+ reconnectAttempts: 5,
70
+ reconnectDelay: 1000,
71
+ maxReconnectDelay: 30000,
72
+ ...options,
73
+ };
74
+ }
75
+
76
+ private log(message: string, level: "info" | "error" | "warn" = "info") {
77
+ if (!this.options.enableLogging) return;
78
+
79
+ const prefix = `[LivePriceWebSocket][${level.toUpperCase()}]`;
80
+
81
+ switch (level) {
82
+ case "error":
83
+ console.error(`${prefix} ${message}`);
84
+ break;
85
+ case "warn":
86
+ console.warn(`${prefix} ${message}`);
87
+ break;
88
+ default:
89
+ console.info(`${prefix} ${message}`);
90
+ break;
91
+ }
92
+ }
93
+
94
+ async connect(url: string): Promise<WebSocket> {
95
+ this.log("Connecting to WebSocket...");
96
+ this.wsUrl = url;
97
+
98
+ if (!this.ws || this.ws.readyState === WebSocket.CLOSED) {
99
+ this.ws = new WebSocket(url);
100
+ await this.setupWebSocket();
101
+ }
102
+
103
+ return this.ws;
104
+ }
105
+
106
+ private async setupWebSocket(): Promise<void> {
107
+ if (!this.ws) {
108
+ throw new WebSocketError(
109
+ "WebSocket not initialized",
110
+ WebSocketErrorType.WEBSOCKET_NOT_INITIALIZED
111
+ );
112
+ }
113
+
114
+ return new Promise((resolve, reject) => {
115
+ if (!this.ws) {
116
+ return reject(
117
+ new WebSocketError(
118
+ "WebSocket not initialized",
119
+ WebSocketErrorType.WEBSOCKET_NOT_INITIALIZED
120
+ )
121
+ );
122
+ }
123
+
124
+ this.ws.onopen = () => {
125
+ this.reconnectAttempts = 0;
126
+ this.log("WebSocket connected");
127
+ resolve();
128
+ };
129
+
130
+ this.ws.onerror = (error) => {
131
+ reject(
132
+ new WebSocketError(
133
+ `WebSocket connection error: ${error}`,
134
+ WebSocketErrorType.CONNECTION_ERROR
135
+ )
136
+ );
137
+ };
138
+
139
+ this.ws.onclose = () => {
140
+ this.isClosed = true;
141
+ this.log("WebSocket closed");
142
+ if (this.closedReason !== WebSocketCloseReason.NORMAL_CLOSURE) {
143
+ try {
144
+ this.attemptReconnect();
145
+ } catch (error) {
146
+ if (error instanceof WebSocketError) {
147
+ switch (error.code) {
148
+ case WebSocketErrorType.MAX_RECONNECT_EXCEEDED:
149
+ this.closedReason =
150
+ WebSocketCloseReason.MAX_RECONNECT_EXCEEDED;
151
+ break;
152
+ case WebSocketErrorType.CONNECTION_ERROR:
153
+ case WebSocketErrorType.WEBSOCKET_NOT_INITIALIZED:
154
+ this.closedReason = WebSocketCloseReason.CONNECTION_ERROR;
155
+ break;
156
+ default:
157
+ this.closedReason = WebSocketCloseReason.UNKNOWN;
158
+ break;
159
+ }
160
+ } else {
161
+ this.closedReason = WebSocketCloseReason.UNKNOWN;
162
+ }
163
+ this.log(`Failed to reconnect: ${error}`, "error");
164
+ }
165
+ }
166
+ };
167
+
168
+ this.ws.onmessage = (event) => {
169
+ try {
170
+ const rawData = JSON.parse(event.data.toString());
171
+ switch (rawData.type) {
172
+ case "price_update":
173
+ const priceData = rawData as WebSocketMessage<BISTStockLiveData>;
174
+ const data = priceData.message;
175
+ if (!data) {
176
+ throw new WebSocketError(
177
+ "Price update message is empty",
178
+ WebSocketErrorType.MESSAGE_PARSE_ERROR
179
+ );
180
+ }
181
+ if (data.symbol) {
182
+ const handlers = this.getHandlersForSymbol(data.symbol);
183
+ handlers.forEach((handler) => handler(data));
184
+ }
185
+ break;
186
+ case "heartbeat":
187
+ this.log("Received heartbeat");
188
+ return;
189
+ case "error":
190
+ this.log(`Received error: ${rawData.message}`, "error");
191
+ return;
192
+ case "warning":
193
+ this.log(`Received warning: ${rawData.message}`, "warn");
194
+ return;
195
+ default:
196
+ this.log(`Unknown message type: ${rawData.type}`, "error");
197
+ return;
198
+ }
199
+ } catch (error) {
200
+ this.log(`Failed to parse WebSocket message: ${error}`, "error");
201
+ }
202
+ };
203
+ });
204
+ }
205
+
206
+ private getActiveSymbols(): string[] {
207
+ const allSymbols = Array.from(this.subscriptions.values()).flatMap(
208
+ (sub) => sub.symbols
209
+ );
210
+
211
+ return [...new Set(allSymbols)];
212
+ }
213
+
214
+ private async attemptReconnect() {
215
+ const url = this.wsUrl;
216
+ if (!url) {
217
+ throw new WebSocketError(
218
+ "WebSocket URL is not set",
219
+ WebSocketErrorType.WEBSOCKET_NOT_INITIALIZED
220
+ );
221
+ }
222
+ if (this.reconnectAttempts >= this.options.reconnectAttempts) {
223
+ throw new WebSocketError(
224
+ `Maximum reconnection attempts (${this.options.reconnectAttempts}) reached`,
225
+ WebSocketErrorType.MAX_RECONNECT_EXCEEDED
226
+ );
227
+ }
228
+
229
+ this.reconnectAttempts++;
230
+ const delay = Math.min(
231
+ this.options.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1),
232
+ this.options.maxReconnectDelay
233
+ );
234
+
235
+ this.log(
236
+ `Attempting to reconnect (${this.reconnectAttempts}/${this.options.reconnectAttempts}) in ${delay}ms...`
237
+ );
238
+
239
+ if (this.reconnectTimeout) {
240
+ clearTimeout(this.reconnectTimeout);
241
+ this.reconnectTimeout = null;
242
+ }
243
+
244
+ this.reconnectTimeout = setTimeout(async () => {
245
+ try {
246
+ await this.connect(url);
247
+ const activeSymbols = this.getActiveSymbols();
248
+ if (activeSymbols.length > 0) {
249
+ this.addSymbols(activeSymbols);
250
+ }
251
+ if (this.reconnectTimeout) {
252
+ clearTimeout(this.reconnectTimeout);
253
+ this.reconnectTimeout = null;
254
+ }
255
+ this.reconnectAttempts = 0;
256
+ } catch (error) {
257
+ this.attemptReconnect();
258
+ }
259
+ }, delay).unref();
260
+ }
261
+
262
+ subscribe(
263
+ symbols: string[],
264
+ handler: (data: BISTStockLiveData) => void
265
+ ): () => void {
266
+ const subscriptionId = this.subscriptionCounter++;
267
+ let symbolsToAdd: string[] = [];
268
+
269
+ this.subscriptions.set(subscriptionId, { symbols, handler });
270
+
271
+ for (const symbol of symbols) {
272
+ if (this.getHandlersForSymbol(symbol).length === 1) {
273
+ symbolsToAdd.push(symbol);
274
+ }
275
+ }
276
+ if (symbolsToAdd.length > 0) {
277
+ this.addSymbols(symbolsToAdd);
278
+ }
279
+
280
+ return () => {
281
+ this.subscriptions.delete(subscriptionId);
282
+ const symbolsForRemove = symbols.filter(
283
+ (s) => this.getHandlersForSymbol(s).length === 0
284
+ );
285
+ this.removeSymbols(symbolsForRemove);
286
+ };
287
+ }
288
+
289
+ private getHandlersForSymbol(
290
+ symbol: string
291
+ ): ((data: BISTStockLiveData) => void)[] {
292
+ return Array.from(this.subscriptions.values())
293
+ .filter((s) => s.symbols.includes(symbol))
294
+ .map((s) => s.handler);
295
+ }
296
+
297
+ private async removeSymbols(symbols: string[]) {
298
+ if (!this.ws) {
299
+ throw new WebSocketError(
300
+ "WebSocket is not initialized",
301
+ WebSocketErrorType.WEBSOCKET_NOT_INITIALIZED
302
+ );
303
+ }
304
+
305
+ if (this.ws.readyState !== WebSocket.OPEN) {
306
+ throw new WebSocketError(
307
+ "WebSocket is not connected",
308
+ WebSocketErrorType.WEBSOCKET_NOT_CONNECTED
309
+ );
310
+ }
311
+ this.ws.send(
312
+ JSON.stringify({
313
+ type: "unsubscribe",
314
+ symbols: symbols,
315
+ })
316
+ );
317
+ }
318
+
319
+ private async addSymbols(symbols: string[]) {
320
+ if (!this.ws) {
321
+ throw new WebSocketError(
322
+ "WebSocket is not initialized",
323
+ WebSocketErrorType.WEBSOCKET_NOT_INITIALIZED
324
+ );
325
+ }
326
+
327
+ if (this.ws.readyState !== WebSocket.OPEN) {
328
+ throw new WebSocketError(
329
+ "WebSocket is not connected",
330
+ WebSocketErrorType.WEBSOCKET_NOT_CONNECTED
331
+ );
332
+ }
333
+
334
+ this.ws.send(
335
+ JSON.stringify({
336
+ type: "subscribe",
337
+ symbols: symbols,
338
+ })
339
+ );
340
+ }
341
+
342
+ async close(): Promise<void> {
343
+ try {
344
+ this.subscriptions.clear();
345
+ this.closedReason = WebSocketCloseReason.NORMAL_CLOSURE;
346
+ if (this.ws?.readyState === WebSocket.OPEN) {
347
+ await new Promise<void>((resolve, reject) => {
348
+ if (!this.ws) {
349
+ resolve();
350
+ return;
351
+ }
352
+
353
+ this.ws.onclose = () => {
354
+ this.isClosed = true;
355
+ resolve();
356
+ };
357
+
358
+ try {
359
+ this.ws.close();
360
+ } catch (closeError) {
361
+ this.closedReason = null;
362
+ reject(
363
+ new WebSocketError(
364
+ `Failed to initiate close: ${closeError}`,
365
+ WebSocketErrorType.CLOSE_ERROR
366
+ )
367
+ );
368
+ }
369
+ });
370
+ }
371
+ } catch (error) {
372
+ const errorMessage =
373
+ error instanceof WebSocketError
374
+ ? error.message
375
+ : `Unexpected error during close: ${error}`;
376
+
377
+ this.log(errorMessage, "error");
378
+ throw error instanceof WebSocketError
379
+ ? error
380
+ : new WebSocketError(errorMessage, WebSocketErrorType.CLOSE_ERROR);
381
+ } finally {
382
+ if (this.reconnectTimeout) {
383
+ clearTimeout(this.reconnectTimeout);
384
+ this.reconnectTimeout = null;
385
+ }
386
+ this.ws = null;
387
+ this.subscriptions.clear();
388
+ }
389
+ }
390
+
391
+ isConnectionClosed(): boolean {
392
+ return this.isClosed;
393
+ }
394
+
395
+ getCloseReason(): WebSocketCloseReason | null {
396
+ return this.closedReason;
397
+ }
398
+ }
@@ -1,19 +1,13 @@
1
- import { Client } from './client';
2
- import { Region } from './collections';
1
+ import { Client } from "./client";
2
+ import { Region } from "./collections";
3
3
  import { v4 as uuidv4 } from 'uuid';
4
4
 
5
- function getLivePrice<T>(
6
- client: Client,
7
- symbols: string[],
8
- region: Region,
9
- streamId: string = uuidv4(),
10
- ): {
11
- events: AsyncIterable<T>,
12
- cancel: () => void
13
- } {
14
- const url = `${client["baseUrl"]}/api/v1/stock/price/live?filter=${symbols.join(',')}&region=${region}&stream=${streamId}`;
5
+ interface WebSocketUrlResponse {
6
+ url: string;
7
+ }
15
8
 
16
- return client.sendSSERequest<T>(url);
9
+ interface WebSocketUrlParams {
10
+ externalUserId: string;
17
11
  }
18
12
 
19
13
  export interface BISTStockLiveData {
@@ -28,7 +22,42 @@ export interface USStockLiveData {
28
22
  ap: number; // AskPrice
29
23
  }
30
24
 
31
- export class LivePriceClient extends Client {
25
+ function getSSELivePrice<T>(
26
+ client: Client,
27
+ symbols: string[],
28
+ region: Region,
29
+ streamId: string = uuidv4(),
30
+ ): {
31
+ events: AsyncIterable<T>,
32
+ cancel: () => void
33
+ } {
34
+ const url = `${client["baseUrl"]}/api/v1/stock/price/live?filter=${symbols.join(',')}&region=${region}&stream=${streamId}`;
35
+
36
+ return client.sendSSERequest<T>(url);
37
+ }
38
+
39
+ export class LivePriceWebSocketUrlClient extends Client {
40
+ async getWebSocketUrl(
41
+ externalUserId: string,
42
+ region: Region
43
+ ): Promise<string> {
44
+ const url = new URL(`${this["baseUrl"]}/api/v1/ws/url`);
45
+ url.searchParams.append("region", region);
46
+ url.searchParams.append("accessLevel", "KRMD1");
47
+
48
+ const params: WebSocketUrlParams = {
49
+ externalUserId,
50
+ };
51
+
52
+ const response = await this.sendRequest<WebSocketUrlResponse>({
53
+ method: "POST",
54
+ url: url.toString(),
55
+ data: params,
56
+ });
57
+
58
+ return response.url;
59
+ }
60
+
32
61
  getLivePriceForBIST(
33
62
  symbols: string[],
34
63
  region: Region,
@@ -37,7 +66,7 @@ export class LivePriceClient extends Client {
37
66
  events: AsyncIterable<BISTStockLiveData>,
38
67
  cancel: () => void
39
68
  } {
40
- return getLivePrice<BISTStockLiveData>(this, symbols, region, streamId);
69
+ return getSSELivePrice<BISTStockLiveData>(this, symbols, region, streamId);
41
70
  }
42
71
 
43
72
  getLivePriceForUS(
@@ -48,6 +77,6 @@ export class LivePriceClient extends Client {
48
77
  events: AsyncIterable<USStockLiveData>,
49
78
  cancel: () => void
50
79
  } {
51
- return getLivePrice<USStockLiveData>(this, symbols, region, streamId);
80
+ return getSSELivePrice<USStockLiveData>(this, symbols, region, streamId);
52
81
  }
53
- }
82
+ }
@@ -6,7 +6,6 @@ import { Region, Locale } from '../client/collections';
6
6
  import './client_test_suite';
7
7
 
8
8
  describe('FinancialRatios', () => {
9
- let client: Client;
10
9
  let financialClient: FinancialClient;
11
10
 
12
11
  beforeAll(() => {
@@ -0,0 +1,141 @@
1
+ import { Logger } from "winston";
2
+ import { LaplaceConfiguration } from "../utilities/configuration";
3
+ import { Region } from "../client/collections";
4
+ import "./client_test_suite";
5
+ import { LivePriceWebSocketUrlClient } from "../client/live-price";
6
+ import {
7
+ BISTStockLiveData,
8
+ LivePriceWebSocketClient,
9
+ } from "../client/live-price-web-socket";
10
+
11
+ describe("LivePrice", () => {
12
+ let livePriceUrlClient: LivePriceWebSocketUrlClient;
13
+ let url: string;
14
+ let ws: LivePriceWebSocketClient;
15
+
16
+ const TEST_CONSTANTS = {
17
+ JEST_TIMEOUT: 30000,
18
+ MAIN_TIMEOUT: 25000,
19
+ };
20
+
21
+ beforeAll(async () => {
22
+ const config = (global as any).testSuite.config as LaplaceConfiguration;
23
+ const logger: Logger = {
24
+ info: jest.fn(),
25
+ error: jest.fn(),
26
+ warn: jest.fn(),
27
+ debug: jest.fn(),
28
+ } as unknown as Logger;
29
+
30
+ livePriceUrlClient = new LivePriceWebSocketUrlClient(config, logger);
31
+ url = await livePriceUrlClient.getWebSocketUrl("2459", Region.Tr);
32
+
33
+ ws = new LivePriceWebSocketClient({
34
+ enableLogging: true,
35
+ });
36
+
37
+ await ws.connect(url);
38
+ });
39
+
40
+ afterAll(async () => {
41
+ try {
42
+ await ws.close();
43
+ } catch (error) {
44
+ console.error("Error closing websocket connection", error);
45
+ }
46
+ });
47
+
48
+ describe("BIST Live Price Tests", () => {
49
+ const symbols = ["TUPRS", "SASA", "THYAO", "GARAN", "YKBNK"];
50
+ // const newSymbols = ["AKBNK", "KCHOL"];
51
+
52
+ it(
53
+ "should receive data for initial and updated symbols",
54
+ async () => {
55
+ const receivedData: BISTStockLiveData[] = [];
56
+
57
+ let unsubscribe: (() => void) | null = ws.subscribe(symbols, (data) => {
58
+ console.log("RECEIVED DATA", data);
59
+ receivedData.push(data);
60
+ });
61
+
62
+ await new Promise((resolve) => setTimeout(resolve, 20000));
63
+
64
+ for (const symbol of symbols) {
65
+ const symbolData = receivedData.filter((data) => data.symbol === symbol);
66
+ expect(symbolData.length).toBeGreaterThan(0);
67
+ }
68
+
69
+ unsubscribe();
70
+ },
71
+ TEST_CONSTANTS.JEST_TIMEOUT
72
+ );
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
+ });
108
+
109
+ // const testLivePrice = async (
110
+ // symbols: string[],
111
+ // region: Region,
112
+ // getLivePriceFunc: (symbols: string[], region: Region) => AsyncGenerator<BISTStockLiveData | USStockLiveData, void, unknown>
113
+ // ) => {
114
+ // const livePriceGenerator = getLivePriceFunc.call(livePriceClient, symbols, region);
115
+ // let livePriceCount = 0;
116
+
117
+ // try {
118
+ // for await (const livePrice of livePriceGenerator) {
119
+ // expect(livePrice).not.toBeEmpty();
120
+ // livePriceCount++;
121
+ // if (livePriceCount > 3) {
122
+ // break;
123
+ // }
124
+ // }
125
+ // } catch (error) {
126
+ // throw new Error(`Error occurred during live price retrieval: ${error}`);
127
+ // }
128
+
129
+ // expect(livePriceCount).toBeGreaterThan(0);
130
+ // };
131
+
132
+ // test('BISTLivePrice', async () => {
133
+ // const symbols = ['TUPRS', 'SASA', 'THYAO', 'GARAN', 'YKBN'];
134
+ // await testLivePrice(symbols, Region.Tr, livePriceClient.getLivePriceForBIST);
135
+ // }, 10000);
136
+
137
+ // test('USLivePrice', async () => {
138
+ // const symbols = ['AAPL', 'GOOGL', 'MSFT', 'AMZN', 'META'];
139
+ // await testLivePrice(symbols, Region.Us, livePriceClient.getLivePriceForUS);
140
+ // }, 10000);
141
+ });
@@ -1,57 +0,0 @@
1
- // import { Logger } from 'winston';
2
- // import { LaplaceConfiguration } from '../utilities/configuration';
3
- // import { Client, createClient } from '../client/client';
4
- // import { LivePriceClient, BISTStockLiveData, USStockLiveData } from '../client/live_price';
5
- // import { Region } from '../client/collections';
6
- // import './client_test_suite';
7
-
8
- // describe('LivePrice', () => {
9
- // let client: Client;
10
- // let livePriceClient: LivePriceClient;
11
-
12
- // beforeAll(() => {
13
- // const config = (global as any).testSuite.config as LaplaceConfiguration;
14
- // const logger: Logger = {
15
- // info: jest.fn(),
16
- // error: jest.fn(),
17
- // warn: jest.fn(),
18
- // debug: jest.fn(),
19
- // } as unknown as Logger;
20
-
21
- // client = createClient(config, logger);
22
- // livePriceClient = new LivePriceClient(client);
23
- // });
24
-
25
- // const testLivePrice = async (
26
- // symbols: string[],
27
- // region: Region,
28
- // getLivePriceFunc: (symbols: string[], region: Region) => AsyncGenerator<BISTStockLiveData | USStockLiveData, void, unknown>
29
- // ) => {
30
- // const livePriceGenerator = getLivePriceFunc.call(livePriceClient, symbols, region);
31
- // let livePriceCount = 0;
32
-
33
- // try {
34
- // for await (const livePrice of livePriceGenerator) {
35
- // expect(livePrice).not.toBeEmpty();
36
- // livePriceCount++;
37
- // if (livePriceCount > 3) {
38
- // break;
39
- // }
40
- // }
41
- // } catch (error) {
42
- // throw new Error(`Error occurred during live price retrieval: ${error}`);
43
- // }
44
-
45
- // expect(livePriceCount).toBeGreaterThan(0);
46
- // };
47
-
48
- // test('BISTLivePrice', async () => {
49
- // const symbols = ['TUPRS', 'SASA', 'THYAO', 'GARAN', 'YKBN'];
50
- // await testLivePrice(symbols, Region.Tr, livePriceClient.getLivePriceForBIST);
51
- // }, 10000);
52
-
53
- // test('USLivePrice', async () => {
54
- // const symbols = ['AAPL', 'GOOGL', 'MSFT', 'AMZN', 'META'];
55
- // await testLivePrice(symbols, Region.Us, livePriceClient.getLivePriceForUS);
56
- // }, 10000);
57
- // });