laplace-api 4.8.0 → 5.1.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 +1 -1
- package/src/client/broker.ts +17 -17
- package/src/client/capital_increase.ts +9 -10
- package/src/client/client.ts +40 -40
- package/src/client/collections.ts +26 -14
- package/src/client/custom_theme.ts +15 -14
- package/src/client/financial_fundamentals.ts +29 -27
- package/src/client/financial_ratios.ts +29 -47
- package/src/client/funds.ts +10 -5
- package/src/client/key-insights.ts +1 -1
- package/src/client/live-price-web-socket.ts +3 -1
- package/src/client/live-price.ts +18 -44
- package/src/client/news.ts +40 -56
- package/src/client/search.ts +13 -9
- package/src/client/stocks.ts +42 -12
- package/src/test/broker.test.ts +580 -453
- package/src/test/capital_increase.test.ts +131 -82
- package/src/test/collections.test.ts +489 -268
- package/src/test/custom_theme.test.ts +250 -144
- package/src/test/financial_fundamentals.test.ts +171 -202
- package/src/test/financial_ratios.test.ts +222 -170
- package/src/test/funds.test.ts +231 -162
- package/src/test/helpers.ts +23 -27
- package/src/test/key-insight.test.ts +71 -36
- package/src/test/live-price.test.ts +135 -1
- package/src/test/news.test.ts +320 -177
- package/src/test/politician.test.ts +176 -187
- package/src/test/readme.test.ts +12 -13
- package/src/test/search.test.ts +144 -170
- package/src/test/stocks.test.ts +306 -370
- package/src/utilities/test.env +0 -2
|
@@ -2,77 +2,59 @@ import { Logger } from 'winston';
|
|
|
2
2
|
import { LaplaceConfiguration } from '../utilities/configuration';
|
|
3
3
|
import {
|
|
4
4
|
FinancialFundamentalsClient,
|
|
5
|
-
TopMoverDirection
|
|
6
|
-
StockDividend,
|
|
7
|
-
StockStats,
|
|
8
|
-
TopMover
|
|
5
|
+
TopMoverDirection
|
|
9
6
|
} from '../client/financial_fundamentals';
|
|
10
7
|
import './client_test_suite';
|
|
11
8
|
import { Region } from '../client/collections';
|
|
12
9
|
import { AssetType, AssetClass } from '../client/stocks';
|
|
13
10
|
|
|
14
|
-
const mockDividendsResponse
|
|
11
|
+
const mockDividendsResponse = [
|
|
15
12
|
{
|
|
16
|
-
date: "
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
{
|
|
26
|
-
date: "2023-03-15T10:00:00Z",
|
|
27
|
-
netAmount: 7.0,
|
|
28
|
-
netRatio: 0.07,
|
|
29
|
-
grossAmount: 8.0,
|
|
30
|
-
grossRatio: 0.08,
|
|
31
|
-
priceThen: 380.0,
|
|
32
|
-
stoppageRatio: 0.15,
|
|
33
|
-
stoppageAmount: 1.0
|
|
13
|
+
"date": "2019-12-18T06:16:00Z",
|
|
14
|
+
"currency": "TRY",
|
|
15
|
+
"netAmount": 0.00007635,
|
|
16
|
+
"netRatio": 0.000396200399251687,
|
|
17
|
+
"grossAmount": 0.000509,
|
|
18
|
+
"grossRatio": 0.00264133599501125,
|
|
19
|
+
"priceThen": 19.399,
|
|
20
|
+
"stoppageRatio": 0.85,
|
|
21
|
+
"stoppageAmount": 0.00043265
|
|
34
22
|
}
|
|
35
23
|
];
|
|
36
24
|
|
|
37
|
-
const mockStockStatsResponse
|
|
25
|
+
const mockStockStatsResponse = [
|
|
38
26
|
{
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
"
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
latestPrice:
|
|
54
|
-
dailyChange: 0.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
dayOpen:
|
|
60
|
-
eps:
|
|
27
|
+
"previousClose": 307,
|
|
28
|
+
"ytdReturn": 0.339439655172414,
|
|
29
|
+
"yearlyReturn": 2.6855575955102,
|
|
30
|
+
"marketCap": 1425000000000,
|
|
31
|
+
"peRatio": 60.2794409292471,
|
|
32
|
+
"pbRatio": 7.32754994352451,
|
|
33
|
+
"yearLow": 80.56935,
|
|
34
|
+
"yearHigh": 339.25,
|
|
35
|
+
"3YearReturn": 4.65564820832651,
|
|
36
|
+
"5YearReturn": 17.2118318670087,
|
|
37
|
+
"3MonthReturn": 0.682320503304819,
|
|
38
|
+
"monthlyReturn": -0.0792592592592593,
|
|
39
|
+
"weeklyReturn": 0.0375626043405676,
|
|
40
|
+
"symbol": "ASELS",
|
|
41
|
+
"latestPrice": 310.75,
|
|
42
|
+
"dailyChange": 0.012214983713355,
|
|
43
|
+
"dayHigh": 314.75,
|
|
44
|
+
"dayLow": 306,
|
|
45
|
+
"lowerPriceLimit": 276.5,
|
|
46
|
+
"upperPriceLimit": 337.5,
|
|
47
|
+
"dayOpen": 307.25,
|
|
48
|
+
"eps": 4.89223038095817
|
|
61
49
|
}
|
|
62
50
|
];
|
|
63
51
|
|
|
64
|
-
const mockTopMoversResponse
|
|
65
|
-
{
|
|
66
|
-
symbol: "TUPRS",
|
|
67
|
-
change: 5.8,
|
|
68
|
-
assetClass: AssetClass.Equity,
|
|
69
|
-
assetType: AssetType.Stock
|
|
70
|
-
},
|
|
52
|
+
const mockTopMoversResponse = [
|
|
71
53
|
{
|
|
72
|
-
symbol: "
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
54
|
+
"symbol": "ISKPL",
|
|
55
|
+
"assetClass": "equity",
|
|
56
|
+
"assetType": "stock",
|
|
57
|
+
"change": 10
|
|
76
58
|
}
|
|
77
59
|
];
|
|
78
60
|
|
|
@@ -100,7 +82,8 @@ describe('FinancialFundamentals', () => {
|
|
|
100
82
|
expect(typeof firstDividend.date).toBe("string");
|
|
101
83
|
expect(() => new Date(firstDividend.date)).not.toThrow();
|
|
102
84
|
expect(new Date(firstDividend.date).getTime()).not.toBeNaN();
|
|
103
|
-
|
|
85
|
+
|
|
86
|
+
expect(typeof firstDividend.currency).toBe("string");
|
|
104
87
|
expect(typeof firstDividend.netAmount).toBe("number");
|
|
105
88
|
expect(typeof firstDividend.netRatio).toBe("number");
|
|
106
89
|
expect(typeof firstDividend.grossAmount).toBe("number");
|
|
@@ -115,7 +98,7 @@ describe('FinancialFundamentals', () => {
|
|
|
115
98
|
expect(resp).not.toBeEmpty();
|
|
116
99
|
expect(resp.length).toBe(1);
|
|
117
100
|
|
|
118
|
-
|
|
101
|
+
const currentStockStats = resp[0];
|
|
119
102
|
expect(currentStockStats).not.toBeEmpty();
|
|
120
103
|
expect(currentStockStats.symbol).toBe('TUPRS');
|
|
121
104
|
expect(currentStockStats.previousClose).toBeGreaterThan(0.0);
|
|
@@ -147,7 +130,7 @@ describe('FinancialFundamentals', () => {
|
|
|
147
130
|
const pageSize = 20;
|
|
148
131
|
|
|
149
132
|
async function testTopMovers(direction: TopMoverDirection, shouldBePositive: boolean) {
|
|
150
|
-
const result = await stockClient.getTopMovers(region,
|
|
133
|
+
const result = await stockClient.getTopMovers(region, pageSize, direction, page, AssetType.Stock, AssetClass.Equity);
|
|
151
134
|
|
|
152
135
|
expect(Array.isArray(result)).toBe(true);
|
|
153
136
|
expect(result.length).toBeGreaterThan(0);
|
|
@@ -184,173 +167,159 @@ describe('FinancialFundamentals', () => {
|
|
|
184
167
|
});
|
|
185
168
|
|
|
186
169
|
describe("Mock Tests", () => {
|
|
170
|
+
let client: FinancialFundamentalsClient;
|
|
171
|
+
let cli: { request: jest.Mock };
|
|
172
|
+
|
|
187
173
|
beforeEach(() => {
|
|
188
|
-
jest.
|
|
174
|
+
cli = { request: jest.fn() };
|
|
175
|
+
|
|
176
|
+
const config = (global as any).testSuite.config as LaplaceConfiguration;
|
|
177
|
+
const logger: Logger = {
|
|
178
|
+
info: jest.fn(),
|
|
179
|
+
error: jest.fn(),
|
|
180
|
+
warn: jest.fn(),
|
|
181
|
+
debug: jest.fn(),
|
|
182
|
+
} as unknown as Logger;
|
|
183
|
+
|
|
184
|
+
client = new FinancialFundamentalsClient(config, logger, cli as any);
|
|
189
185
|
});
|
|
190
|
-
|
|
186
|
+
|
|
191
187
|
describe("getStockDividends", () => {
|
|
192
|
-
test("
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const resp = await
|
|
196
|
-
|
|
197
|
-
expect(
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
expect(
|
|
201
|
-
expect(
|
|
202
|
-
expect(
|
|
203
|
-
|
|
204
|
-
expect(
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
expect(
|
|
208
|
-
|
|
209
|
-
expect(
|
|
188
|
+
test("calls correct endpoint/params and matches raw response", async () => {
|
|
189
|
+
cli.request.mockResolvedValueOnce({ data: mockDividendsResponse });
|
|
190
|
+
|
|
191
|
+
const resp = await client.getStockDividends("TUPRS", Region.Tr);
|
|
192
|
+
|
|
193
|
+
expect(cli.request).toHaveBeenCalledTimes(1);
|
|
194
|
+
const call = cli.request.mock.calls[0][0];
|
|
195
|
+
|
|
196
|
+
expect(call.method).toBe("GET");
|
|
197
|
+
expect(call.url).toBe("/api/v2/stock/dividends");
|
|
198
|
+
expect(call.params).toEqual({ symbol: "TUPRS", region: Region.Tr });
|
|
199
|
+
|
|
200
|
+
expect(resp).toHaveLength(1);
|
|
201
|
+
const d = resp[0];
|
|
202
|
+
|
|
203
|
+
expect(d.date).toBe("2019-12-18T06:16:00Z");
|
|
204
|
+
expect(d.currency).toBe("TRY");
|
|
205
|
+
expect(d.netAmount).toBe(0.00007635);
|
|
206
|
+
expect(d.netRatio).toBe(0.000396200399251687);
|
|
207
|
+
expect(d.grossAmount).toBe(0.000509);
|
|
208
|
+
expect(d.grossRatio).toBe(0.00264133599501125);
|
|
209
|
+
expect(d.priceThen).toBe(19.399);
|
|
210
|
+
expect(d.stoppageRatio).toBe(0.85);
|
|
211
|
+
expect(d.stoppageAmount).toBe(0.00043265);
|
|
210
212
|
});
|
|
211
|
-
|
|
212
|
-
test("
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
213
|
+
|
|
214
|
+
test("bubbles up request error", async () => {
|
|
215
|
+
cli.request.mockRejectedValueOnce(new Error("Invalid symbol"));
|
|
216
|
+
|
|
217
|
+
await expect(client.getStockDividends("INVALID", Region.Tr)).rejects.toThrow(
|
|
218
|
+
"Invalid symbol"
|
|
219
|
+
);
|
|
217
220
|
});
|
|
218
221
|
});
|
|
219
|
-
|
|
222
|
+
|
|
220
223
|
describe("getStockStats", () => {
|
|
221
|
-
test("
|
|
222
|
-
|
|
224
|
+
test("calls correct endpoint/params and matches raw response", async () => {
|
|
225
|
+
cli.request.mockResolvedValueOnce({ data: mockStockStatsResponse });
|
|
223
226
|
|
|
224
|
-
const resp = await
|
|
227
|
+
const resp = await client.getStockStats(["ASELS"], Region.Tr);
|
|
225
228
|
|
|
226
|
-
expect(
|
|
227
|
-
|
|
228
|
-
const stats = resp[0];
|
|
229
|
-
expect(stats.symbol).toBe("TUPRS");
|
|
230
|
-
expect(stats.previousClose).toBe(425.5);
|
|
231
|
-
expect(stats.marketCap).toBe(106375000000);
|
|
232
|
-
expect(stats.peRatio).toBe(5.8);
|
|
233
|
-
expect(stats.pbRatio).toBe(2.1);
|
|
234
|
-
expect(stats.yearLow).toBe(320.5);
|
|
235
|
-
expect(stats.yearHigh).toBe(450.2);
|
|
236
|
-
expect(stats.weeklyReturn).toBe(0.025);
|
|
237
|
-
expect(stats.monthlyReturn).toBe(0.058);
|
|
238
|
-
expect(stats["3MonthReturn"]).toBe(0.125);
|
|
239
|
-
expect(stats.ytdReturn).toBe(0.15);
|
|
240
|
-
expect(stats.yearlyReturn).toBe(0.45);
|
|
241
|
-
expect(stats["3YearReturn"]).toBe(1.25);
|
|
242
|
-
expect(stats["5YearReturn"]).toBe(2.85);
|
|
243
|
-
expect(stats.latestPrice).toBe(428.5);
|
|
244
|
-
expect(stats.dailyChange).toBe(0.007);
|
|
245
|
-
expect(stats.dayLow).toBe(424.0);
|
|
246
|
-
expect(stats.dayHigh).toBe(429.5);
|
|
247
|
-
expect(stats.upperPriceLimit).toBe(468.05);
|
|
248
|
-
expect(stats.lowerPriceLimit).toBe(382.95);
|
|
249
|
-
expect(stats.dayOpen).toBe(426.0);
|
|
250
|
-
expect(stats.eps).toBe(73.45);
|
|
229
|
+
expect(cli.request).toHaveBeenCalledTimes(1);
|
|
230
|
+
const call = cli.request.mock.calls[0][0];
|
|
251
231
|
|
|
252
|
-
expect(
|
|
232
|
+
expect(call.method).toBe("GET");
|
|
233
|
+
expect(call.url).toBe("/api/v2/stock/stats");
|
|
234
|
+
expect(call.params).toEqual({ symbols: "ASELS", region: Region.Tr });
|
|
235
|
+
|
|
236
|
+
expect(resp).toHaveLength(1);
|
|
237
|
+
const s = resp[0];
|
|
238
|
+
|
|
239
|
+
expect(s.symbol).toBe("ASELS");
|
|
240
|
+
|
|
241
|
+
expect(s.previousClose).toBe(307);
|
|
242
|
+
expect(s.ytdReturn).toBe(0.339439655172414);
|
|
243
|
+
expect(s.yearlyReturn).toBe(2.6855575955102);
|
|
244
|
+
|
|
245
|
+
expect(s.marketCap).toBe(1425000000000);
|
|
246
|
+
expect(s.peRatio).toBe(60.2794409292471);
|
|
247
|
+
expect(s.pbRatio).toBe(7.32754994352451);
|
|
248
|
+
|
|
249
|
+
expect(s.yearLow).toBe(80.56935);
|
|
250
|
+
expect(s.yearHigh).toBe(339.25);
|
|
251
|
+
|
|
252
|
+
expect(s["3YearReturn"]).toBe(4.65564820832651);
|
|
253
|
+
expect(s["5YearReturn"]).toBe(17.2118318670087);
|
|
254
|
+
expect(s["3MonthReturn"]).toBe(0.682320503304819);
|
|
255
|
+
|
|
256
|
+
expect(s.monthlyReturn).toBe(-0.0792592592592593);
|
|
257
|
+
expect(s.weeklyReturn).toBe(0.0375626043405676);
|
|
258
|
+
|
|
259
|
+
expect(s.latestPrice).toBe(310.75);
|
|
260
|
+
expect(s.dailyChange).toBe(0.012214983713355);
|
|
261
|
+
|
|
262
|
+
expect(s.dayHigh).toBe(314.75);
|
|
263
|
+
expect(s.dayLow).toBe(306);
|
|
264
|
+
expect(s.dayOpen).toBe(307.25);
|
|
265
|
+
|
|
266
|
+
expect(s.lowerPriceLimit).toBe(276.5);
|
|
267
|
+
expect(s.upperPriceLimit).toBe(337.5);
|
|
268
|
+
|
|
269
|
+
expect(s.eps).toBe(4.89223038095817);
|
|
253
270
|
});
|
|
254
|
-
|
|
255
|
-
test("
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
];
|
|
260
|
-
jest.spyOn(stockClient, 'getStockStats').mockResolvedValue(multipleStatsResponse);
|
|
261
|
-
|
|
262
|
-
const resp = await stockClient.getStockStats(["TUPRS", "SASA"], Region.Tr);
|
|
263
|
-
expect(resp).toHaveLength(2);
|
|
264
|
-
expect(resp[0].symbol).toBe("TUPRS");
|
|
265
|
-
expect(resp[1].symbol).toBe("SASA");
|
|
271
|
+
|
|
272
|
+
test("bubbles up request error", async () => {
|
|
273
|
+
cli.request.mockRejectedValueOnce(new Error("Invalid symbols"));
|
|
274
|
+
|
|
275
|
+
await expect(client.getStockStats([""], Region.Tr)).rejects.toThrow("Invalid symbols");
|
|
266
276
|
});
|
|
267
277
|
});
|
|
268
|
-
|
|
278
|
+
|
|
269
279
|
describe("getTopMovers", () => {
|
|
270
|
-
test("
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
const resp = await stockClient.getTopMovers(
|
|
274
|
-
Region.Tr,
|
|
275
|
-
0,
|
|
276
|
-
10,
|
|
277
|
-
TopMoverDirection.Gainers,
|
|
278
|
-
AssetType.Stock,
|
|
279
|
-
AssetClass.Equity
|
|
280
|
-
);
|
|
280
|
+
test("calls correct endpoint/params and matches raw response", async () => {
|
|
281
|
+
cli.request.mockResolvedValueOnce({ data: mockTopMoversResponse });
|
|
281
282
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
const firstMover = resp[0];
|
|
285
|
-
expect(firstMover.symbol).toBe("TUPRS");
|
|
286
|
-
expect(firstMover.change).toBe(5.8);
|
|
287
|
-
expect(firstMover.assetClass).toBe(AssetClass.Equity);
|
|
288
|
-
expect(firstMover.assetType).toBe(AssetType.Stock);
|
|
289
|
-
|
|
290
|
-
expect(resp.every(mover => mover.change > 0)).toBe(true);
|
|
291
|
-
|
|
292
|
-
expect(stockClient.getTopMovers).toHaveBeenCalledWith(
|
|
283
|
+
const resp = await client.getTopMovers(
|
|
293
284
|
Region.Tr,
|
|
294
|
-
0,
|
|
295
285
|
10,
|
|
296
286
|
TopMoverDirection.Gainers,
|
|
297
|
-
AssetType.Stock,
|
|
298
|
-
AssetClass.Equity
|
|
299
|
-
);
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
test("should return losers with mock data", async () => {
|
|
303
|
-
const losersResponse = mockTopMoversResponse.map(mover => ({
|
|
304
|
-
...mover,
|
|
305
|
-
change: -Math.abs(mover.change)
|
|
306
|
-
}));
|
|
307
|
-
jest.spyOn(stockClient, 'getTopMovers').mockResolvedValue(losersResponse);
|
|
308
|
-
|
|
309
|
-
const resp = await stockClient.getTopMovers(
|
|
310
|
-
Region.Tr,
|
|
311
|
-
0,
|
|
312
|
-
10,
|
|
313
|
-
TopMoverDirection.Losers,
|
|
314
|
-
AssetType.Stock,
|
|
315
|
-
AssetClass.Equity
|
|
316
|
-
);
|
|
317
|
-
|
|
318
|
-
expect(resp.every(mover => mover.change < 0)).toBe(true);
|
|
319
|
-
|
|
320
|
-
expect(stockClient.getTopMovers).toHaveBeenCalledWith(
|
|
321
|
-
Region.Tr,
|
|
322
287
|
0,
|
|
323
|
-
10,
|
|
324
|
-
TopMoverDirection.Losers,
|
|
325
|
-
AssetType.Stock,
|
|
326
|
-
AssetClass.Equity
|
|
327
|
-
);
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
test("should handle pagination", async () => {
|
|
331
|
-
jest.spyOn(stockClient, 'getTopMovers').mockResolvedValue([mockTopMoversResponse[0]]);
|
|
332
|
-
|
|
333
|
-
const resp = await stockClient.getTopMovers(
|
|
334
|
-
Region.Tr,
|
|
335
|
-
1,
|
|
336
|
-
1,
|
|
337
|
-
TopMoverDirection.Gainers,
|
|
338
288
|
AssetType.Stock,
|
|
339
289
|
AssetClass.Equity
|
|
340
290
|
);
|
|
341
291
|
|
|
292
|
+
expect(cli.request).toHaveBeenCalledTimes(1);
|
|
293
|
+
const call = cli.request.mock.calls[0][0];
|
|
294
|
+
|
|
295
|
+
expect(call.method).toBe("GET");
|
|
296
|
+
expect(call.url).toBe("/api/v2/stock/top-movers");
|
|
297
|
+
expect(call.params).toEqual({
|
|
298
|
+
region: Region.Tr,
|
|
299
|
+
pageSize: 10,
|
|
300
|
+
direction: TopMoverDirection.Gainers,
|
|
301
|
+
page: 0,
|
|
302
|
+
assetType: AssetType.Stock,
|
|
303
|
+
assetClass: AssetClass.Equity,
|
|
304
|
+
});
|
|
305
|
+
|
|
342
306
|
expect(resp).toHaveLength(1);
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
expect(
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
);
|
|
307
|
+
const m = resp[0];
|
|
308
|
+
|
|
309
|
+
expect(m.symbol).toBe("ISKPL");
|
|
310
|
+
expect(m.change).toBe(10);
|
|
311
|
+
expect(m.assetType).toBe("stock");
|
|
312
|
+
expect(m.assetClass).toBe("equity");
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
test("bubbles up request error", async () => {
|
|
316
|
+
cli.request.mockRejectedValueOnce(new Error("Bad request"));
|
|
317
|
+
|
|
318
|
+
await expect(
|
|
319
|
+
client.getTopMovers(Region.Tr, 10, TopMoverDirection.Gainers)
|
|
320
|
+
).rejects.toThrow("Bad request");
|
|
353
321
|
});
|
|
354
322
|
});
|
|
355
323
|
});
|
|
324
|
+
|
|
356
325
|
});
|