laplace-api 3.1.0 → 4.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/.github/workflows/publish.yml +37 -0
- package/.github/workflows/test.yml +25 -0
- package/README.md +461 -2
- package/package.json +1 -1
- package/src/client/broker.ts +79 -99
- package/src/client/capital_increase.ts +17 -22
- package/src/client/collections.ts +61 -40
- package/src/client/financial_fundamentals.ts +40 -35
- package/src/client/financial_ratios.ts +168 -128
- package/src/client/funds.ts +139 -0
- package/src/client/key-insights.ts +17 -0
- package/src/client/live-price-web-socket.ts +84 -11
- package/src/client/live-price.ts +210 -58
- package/src/client/politician.ts +75 -0
- package/src/client/stocks.ts +85 -2
- package/src/test/broker.test.ts +581 -170
- package/src/test/capital_increase.test.ts +266 -15
- package/src/test/collections.test.ts +460 -17
- package/src/test/custom_theme.test.ts +256 -65
- package/src/test/financial_fundamentals.test.ts +301 -45
- package/src/test/financial_ratios.test.ts +376 -75
- package/src/test/funds.test.ts +317 -0
- package/src/test/helpers.ts +58 -0
- package/src/test/key-insight.test.ts +110 -0
- package/src/test/live-price.test.ts +427 -67
- package/src/test/politician.test.ts +253 -0
- package/src/test/readme.test.ts +483 -0
- package/src/test/search.test.ts +308 -23
- package/src/test/stocks.test.ts +800 -70
- package/src/utilities/configuration.ts +23 -10
- package/src/utilities/test.env +2 -2
package/src/test/broker.test.ts
CHANGED
|
@@ -3,14 +3,103 @@ import { Region } from "../client/collections";
|
|
|
3
3
|
import { LaplaceConfiguration } from "../utilities/configuration";
|
|
4
4
|
import "./client_test_suite";
|
|
5
5
|
import {
|
|
6
|
-
BaseBrokerStats,
|
|
7
6
|
BrokerClient,
|
|
8
7
|
BrokerSort,
|
|
8
|
+
SortDirection,
|
|
9
9
|
BrokerStats,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
Broker,
|
|
11
|
+
BrokerStock,
|
|
12
|
+
BrokerList,
|
|
13
|
+
BrokerItem,
|
|
13
14
|
} from "../client/broker";
|
|
15
|
+
import { AssetType, AssetClass } from "../client/stocks";
|
|
16
|
+
import { PaginatedResponse } from "../client/capital_increase";
|
|
17
|
+
|
|
18
|
+
const mockBroker: Broker = {
|
|
19
|
+
id: 1001,
|
|
20
|
+
symbol: "BIYKR",
|
|
21
|
+
name: "BİYİKLI YATIRIM",
|
|
22
|
+
longName: "Bıyıklı Yatırım Menkul Değerler A.Ş.",
|
|
23
|
+
logo: "https://example.com/biykr.png"
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const mockBroker2: Broker = {
|
|
27
|
+
id: 1002,
|
|
28
|
+
symbol: "GEDIK",
|
|
29
|
+
name: "GEDİK YATIRIM",
|
|
30
|
+
longName: "Gedik Yatırım Menkul Değerler A.Ş.",
|
|
31
|
+
logo: "https://example.com/gedik.png"
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const mockBroker3: Broker = {
|
|
35
|
+
id: 1001,
|
|
36
|
+
symbol: "BIYKR",
|
|
37
|
+
name: "BİYİKLI YATIRIM",
|
|
38
|
+
longName: "Bıyıklı Yatırım Menkul Değerler A.Ş.",
|
|
39
|
+
logo: "https://example.com/biykr.png",
|
|
40
|
+
supportedAssetClasses: [AssetClass.Equity]
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const mockBroker4: Broker = {
|
|
44
|
+
id: 1002,
|
|
45
|
+
symbol: "GEDIK",
|
|
46
|
+
name: "GEDİK YATIRIM",
|
|
47
|
+
longName: "Gedik Yatırım Menkul Değerler A.Ş.",
|
|
48
|
+
logo: "https://example.com/gedik.png",
|
|
49
|
+
supportedAssetClasses: [AssetClass.Equity]
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const mockStock: BrokerStock = {
|
|
53
|
+
id: "61dd0d6f0ec2114146342fd0",
|
|
54
|
+
symbol: "TUPRS",
|
|
55
|
+
name: "Tüpraş",
|
|
56
|
+
assetType: AssetType.Stock,
|
|
57
|
+
assetClass: AssetClass.Equity
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const mockStock2: BrokerStock = {
|
|
61
|
+
id: "61dd0d6f0ec2114146342fd1",
|
|
62
|
+
symbol: "GARAN",
|
|
63
|
+
name: "Garanti Bankası",
|
|
64
|
+
assetType: AssetType.Stock,
|
|
65
|
+
assetClass: AssetClass.Equity
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const mockBrokerStats: BrokerStats = {
|
|
69
|
+
totalBuyAmount: 1000000,
|
|
70
|
+
totalSellAmount: 800000,
|
|
71
|
+
netAmount: 200000,
|
|
72
|
+
totalBuyVolume: 50000,
|
|
73
|
+
totalSellVolume: 40000,
|
|
74
|
+
totalVolume: 90000,
|
|
75
|
+
totalAmount: 1800000,
|
|
76
|
+
averageCost: 20.5
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const mockBrokerItem: BrokerItem = {
|
|
80
|
+
...mockBrokerStats,
|
|
81
|
+
broker: mockBroker,
|
|
82
|
+
stock: mockStock
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const mockBrokerItem2: BrokerItem = {
|
|
86
|
+
...mockBrokerStats,
|
|
87
|
+
totalBuyAmount: 900000,
|
|
88
|
+
totalSellAmount: 700000,
|
|
89
|
+
broker: mockBroker2,
|
|
90
|
+
stock: mockStock2
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const mockBrokerList: BrokerList = {
|
|
94
|
+
recordCount: 2,
|
|
95
|
+
items: [mockBrokerItem, mockBrokerItem2],
|
|
96
|
+
totalStats: mockBrokerStats
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const mockBrokersPaginatedResponse: PaginatedResponse<Broker> = {
|
|
100
|
+
recordCount: 2,
|
|
101
|
+
items: [mockBroker3, mockBroker4]
|
|
102
|
+
};
|
|
14
103
|
|
|
15
104
|
describe("BrokerClient", () => {
|
|
16
105
|
let brokerClient: BrokerClient;
|
|
@@ -32,35 +121,23 @@ describe("BrokerClient", () => {
|
|
|
32
121
|
const fromDate = "2025-05-20";
|
|
33
122
|
const toDate = "2025-05-28";
|
|
34
123
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
expect(typeof response.recordCount).toBe("number");
|
|
47
|
-
|
|
48
|
-
const stats = response.totalStats;
|
|
49
|
-
expect(stats).toMatchObject<BaseBrokerStats>({
|
|
50
|
-
totalBuyAmount: expect.any(Number),
|
|
51
|
-
totalSellAmount: expect.any(Number),
|
|
52
|
-
netAmount: expect.any(Number),
|
|
53
|
-
totalBuyVolume: expect.any(Number),
|
|
54
|
-
totalSellVolume: expect.any(Number),
|
|
55
|
-
totalVolume: expect.any(Number),
|
|
56
|
-
totalAmount: expect.any(Number),
|
|
57
|
-
});
|
|
124
|
+
describe("Integration Tests", () => {
|
|
125
|
+
test("getMarketBrokers returns valid and fully typed data", async () => {
|
|
126
|
+
const response = await brokerClient.getMarketBrokers(
|
|
127
|
+
Region.Tr,
|
|
128
|
+
BrokerSort.TotalVolume,
|
|
129
|
+
SortDirection.Desc,
|
|
130
|
+
"2025-05-27",
|
|
131
|
+
"2025-05-28",
|
|
132
|
+
0,
|
|
133
|
+
5
|
|
134
|
+
);
|
|
58
135
|
|
|
59
|
-
|
|
60
|
-
|
|
136
|
+
expect(response).toBeDefined();
|
|
137
|
+
expect(typeof response.recordCount).toBe("number");
|
|
61
138
|
|
|
62
|
-
|
|
63
|
-
expect(
|
|
139
|
+
const stats = response.totalStats;
|
|
140
|
+
expect(stats).toMatchObject<BrokerStats>({
|
|
64
141
|
totalBuyAmount: expect.any(Number),
|
|
65
142
|
totalSellAmount: expect.any(Number),
|
|
66
143
|
netAmount: expect.any(Number),
|
|
@@ -68,30 +145,50 @@ describe("BrokerClient", () => {
|
|
|
68
145
|
totalSellVolume: expect.any(Number),
|
|
69
146
|
totalVolume: expect.any(Number),
|
|
70
147
|
totalAmount: expect.any(Number),
|
|
71
|
-
broker: {
|
|
72
|
-
id: expect.any(Number),
|
|
73
|
-
symbol: expect.any(String),
|
|
74
|
-
name: expect.any(String),
|
|
75
|
-
longName: expect.any(String),
|
|
76
|
-
logo: expect.any(String),
|
|
77
|
-
},
|
|
78
148
|
});
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
149
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
region,
|
|
85
|
-
fromDate,
|
|
86
|
-
toDate,
|
|
87
|
-
BrokerSort.Volume
|
|
88
|
-
);
|
|
150
|
+
expect(Array.isArray(response.items)).toBe(true);
|
|
151
|
+
expect(response.items.length).toBeGreaterThan(0);
|
|
89
152
|
|
|
90
|
-
|
|
153
|
+
for (const item of response.items) {
|
|
154
|
+
expect(item).toMatchObject<BrokerStats>({
|
|
155
|
+
totalBuyAmount: expect.any(Number),
|
|
156
|
+
totalSellAmount: expect.any(Number),
|
|
157
|
+
netAmount: expect.any(Number),
|
|
158
|
+
totalBuyVolume: expect.any(Number),
|
|
159
|
+
totalSellVolume: expect.any(Number),
|
|
160
|
+
totalVolume: expect.any(Number),
|
|
161
|
+
totalAmount: expect.any(Number),
|
|
162
|
+
});
|
|
91
163
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
164
|
+
if (item.broker) {
|
|
165
|
+
expect(item.broker).toMatchObject({
|
|
166
|
+
id: expect.any(Number),
|
|
167
|
+
symbol: expect.any(String),
|
|
168
|
+
name: expect.any(String),
|
|
169
|
+
longName: expect.any(String),
|
|
170
|
+
logo: expect.any(String),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
test("getMarketStocks returns valid stock data", async () => {
|
|
177
|
+
const response = await brokerClient.getMarketStocks(
|
|
178
|
+
region,
|
|
179
|
+
BrokerSort.TotalVolume,
|
|
180
|
+
SortDirection.Desc,
|
|
181
|
+
fromDate,
|
|
182
|
+
toDate,
|
|
183
|
+
0,
|
|
184
|
+
5
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
expect(response).toBeDefined();
|
|
188
|
+
expect(typeof response.recordCount).toBe("number");
|
|
189
|
+
|
|
190
|
+
const stats = response.totalStats;
|
|
191
|
+
expect(stats).toMatchObject<BrokerStats>({
|
|
95
192
|
totalBuyAmount: expect.any(Number),
|
|
96
193
|
totalSellAmount: expect.any(Number),
|
|
97
194
|
netAmount: expect.any(Number),
|
|
@@ -100,13 +197,49 @@ describe("BrokerClient", () => {
|
|
|
100
197
|
totalVolume: expect.any(Number),
|
|
101
198
|
totalAmount: expect.any(Number),
|
|
102
199
|
});
|
|
103
|
-
}
|
|
104
200
|
|
|
105
|
-
|
|
106
|
-
|
|
201
|
+
expect(Array.isArray(response.items)).toBe(true);
|
|
202
|
+
|
|
203
|
+
for (const item of response.items) {
|
|
204
|
+
expect(item).toMatchObject<BrokerStats>({
|
|
205
|
+
totalBuyAmount: expect.any(Number),
|
|
206
|
+
totalSellAmount: expect.any(Number),
|
|
207
|
+
netAmount: expect.any(Number),
|
|
208
|
+
totalBuyVolume: expect.any(Number),
|
|
209
|
+
totalSellVolume: expect.any(Number),
|
|
210
|
+
totalVolume: expect.any(Number),
|
|
211
|
+
totalAmount: expect.any(Number),
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
if (item.stock) {
|
|
215
|
+
expect(item.stock).toMatchObject({
|
|
216
|
+
id: expect.any(String),
|
|
217
|
+
symbol: expect.any(String),
|
|
218
|
+
name: expect.any(String),
|
|
219
|
+
assetType: expect.any(String),
|
|
220
|
+
assetClass: expect.any(String),
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
test("getBrokersByStock returns brokers for specific stock", async () => {
|
|
227
|
+
const response = await brokerClient.getBrokersByStock(
|
|
228
|
+
"TUPRS",
|
|
229
|
+
region,
|
|
230
|
+
BrokerSort.TotalVolume,
|
|
231
|
+
SortDirection.Desc,
|
|
232
|
+
fromDate,
|
|
233
|
+
toDate,
|
|
234
|
+
0,
|
|
235
|
+
5
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
expect(response).toBeDefined();
|
|
239
|
+
expect(typeof response.recordCount).toBe("number");
|
|
107
240
|
|
|
108
|
-
|
|
109
|
-
expect(
|
|
241
|
+
const stats = response.totalStats;
|
|
242
|
+
expect(stats).toMatchObject<BrokerStats>({
|
|
110
243
|
totalBuyAmount: expect.any(Number),
|
|
111
244
|
totalSellAmount: expect.any(Number),
|
|
112
245
|
netAmount: expect.any(Number),
|
|
@@ -114,45 +247,54 @@ describe("BrokerClient", () => {
|
|
|
114
247
|
totalSellVolume: expect.any(Number),
|
|
115
248
|
totalVolume: expect.any(Number),
|
|
116
249
|
totalAmount: expect.any(Number),
|
|
117
|
-
broker: {
|
|
118
|
-
id: expect.any(Number),
|
|
119
|
-
symbol: expect.any(String),
|
|
120
|
-
name: expect.any(String),
|
|
121
|
-
longName: expect.any(String),
|
|
122
|
-
logo: expect.any(String),
|
|
123
|
-
},
|
|
124
250
|
});
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
251
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
252
|
+
expect(Array.isArray(response.items)).toBe(true);
|
|
253
|
+
|
|
254
|
+
for (const item of response.items) {
|
|
255
|
+
expect(item).toMatchObject<BrokerStats>({
|
|
256
|
+
totalBuyAmount: expect.any(Number),
|
|
257
|
+
totalSellAmount: expect.any(Number),
|
|
258
|
+
netAmount: expect.any(Number),
|
|
259
|
+
totalBuyVolume: expect.any(Number),
|
|
260
|
+
totalSellVolume: expect.any(Number),
|
|
261
|
+
totalVolume: expect.any(Number),
|
|
262
|
+
totalAmount: expect.any(Number),
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
if (item.broker) {
|
|
266
|
+
expect(item.broker).toMatchObject({
|
|
267
|
+
id: expect.any(Number),
|
|
268
|
+
symbol: expect.any(String),
|
|
269
|
+
name: expect.any(String),
|
|
270
|
+
longName: expect.any(String),
|
|
271
|
+
logo: expect.any(String),
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if ("averageCost" in item) {
|
|
276
|
+
expect(item.averageCost).toEqual(expect.any(Number));
|
|
277
|
+
}
|
|
278
|
+
}
|
|
151
279
|
});
|
|
152
280
|
|
|
153
|
-
for
|
|
154
|
-
|
|
155
|
-
|
|
281
|
+
test("getStocksByBroker returns stocks for specific broker", async () => {
|
|
282
|
+
const response = await brokerClient.getStocksByBroker(
|
|
283
|
+
"BIYKR",
|
|
284
|
+
region,
|
|
285
|
+
BrokerSort.TotalVolume,
|
|
286
|
+
SortDirection.Desc,
|
|
287
|
+
fromDate,
|
|
288
|
+
toDate,
|
|
289
|
+
0,
|
|
290
|
+
5
|
|
291
|
+
);
|
|
292
|
+
|
|
293
|
+
expect(response).toBeDefined();
|
|
294
|
+
expect(typeof response.recordCount).toBe("number");
|
|
295
|
+
|
|
296
|
+
const stats = response.totalStats;
|
|
297
|
+
expect(stats).toMatchObject<BrokerStats>({
|
|
156
298
|
totalBuyAmount: expect.any(Number),
|
|
157
299
|
totalSellAmount: expect.any(Number),
|
|
158
300
|
netAmount: expect.any(Number),
|
|
@@ -160,103 +302,372 @@ describe("BrokerClient", () => {
|
|
|
160
302
|
totalSellVolume: expect.any(Number),
|
|
161
303
|
totalVolume: expect.any(Number),
|
|
162
304
|
totalAmount: expect.any(Number),
|
|
163
|
-
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
expect(Array.isArray(response.items)).toBe(true);
|
|
308
|
+
|
|
309
|
+
for (const item of response.items) {
|
|
310
|
+
expect(item).toMatchObject<BrokerStats>({
|
|
311
|
+
totalBuyAmount: expect.any(Number),
|
|
312
|
+
totalSellAmount: expect.any(Number),
|
|
313
|
+
netAmount: expect.any(Number),
|
|
314
|
+
totalBuyVolume: expect.any(Number),
|
|
315
|
+
totalSellVolume: expect.any(Number),
|
|
316
|
+
totalVolume: expect.any(Number),
|
|
317
|
+
totalAmount: expect.any(Number),
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
if (item.stock) {
|
|
321
|
+
expect(item.stock).toMatchObject({
|
|
322
|
+
id: expect.any(String),
|
|
323
|
+
symbol: expect.any(String),
|
|
324
|
+
name: expect.any(String),
|
|
325
|
+
assetType: expect.any(String),
|
|
326
|
+
assetClass: expect.any(String),
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
test("getBrokers with assetClass parameter", async () => {
|
|
333
|
+
const response = await brokerClient.getBrokers(
|
|
334
|
+
Region.Tr,
|
|
335
|
+
0,
|
|
336
|
+
10,
|
|
337
|
+
AssetClass.Equity
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
expect(response).toBeDefined();
|
|
341
|
+
expect(typeof response.recordCount).toBe("number");
|
|
342
|
+
expect(Array.isArray(response.items)).toBe(true);
|
|
343
|
+
|
|
344
|
+
for (const broker of response.items) {
|
|
345
|
+
expect(broker).toMatchObject({
|
|
164
346
|
id: expect.any(Number),
|
|
165
347
|
symbol: expect.any(String),
|
|
166
348
|
name: expect.any(String),
|
|
167
349
|
longName: expect.any(String),
|
|
168
350
|
logo: expect.any(String),
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
test("getTopStockBrokers returns fully typed top & rest stats with averageCost", async () => {
|
|
175
|
-
const response = await brokerClient.getTopStockBrokers(
|
|
176
|
-
region,
|
|
177
|
-
fromDate,
|
|
178
|
-
toDate,
|
|
179
|
-
BrokerSort.Volume,
|
|
180
|
-
"TUPRS"
|
|
181
|
-
);
|
|
351
|
+
});
|
|
352
|
+
expect(Array.isArray(broker.supportedAssetClasses)).toBe(true);
|
|
353
|
+
expect(broker.supportedAssetClasses).toEqual([AssetClass.Equity]);
|
|
354
|
+
}
|
|
355
|
+
});
|
|
182
356
|
|
|
183
|
-
|
|
357
|
+
test("getBrokers without assetClass parameter", async () => {
|
|
358
|
+
const response = await brokerClient.getBrokers(
|
|
359
|
+
Region.Tr,
|
|
360
|
+
0,
|
|
361
|
+
10
|
|
362
|
+
);
|
|
184
363
|
|
|
185
|
-
|
|
186
|
-
expect(
|
|
187
|
-
|
|
188
|
-
totalSellAmount: expect.any(Number),
|
|
189
|
-
netAmount: expect.any(Number),
|
|
190
|
-
totalBuyVolume: expect.any(Number),
|
|
191
|
-
totalSellVolume: expect.any(Number),
|
|
192
|
-
totalVolume: expect.any(Number),
|
|
193
|
-
totalAmount: expect.any(Number),
|
|
194
|
-
averageCost: expect.any(Number),
|
|
195
|
-
});
|
|
196
|
-
}
|
|
364
|
+
expect(response).toBeDefined();
|
|
365
|
+
expect(typeof response.recordCount).toBe("number");
|
|
366
|
+
expect(Array.isArray(response.items)).toBe(true);
|
|
197
367
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
averageCost: expect.any(Number),
|
|
201
|
-
totalBuyAmount: expect.any(Number),
|
|
202
|
-
totalSellAmount: expect.any(Number),
|
|
203
|
-
netAmount: expect.any(Number),
|
|
204
|
-
totalBuyVolume: expect.any(Number),
|
|
205
|
-
totalSellVolume: expect.any(Number),
|
|
206
|
-
totalVolume: expect.any(Number),
|
|
207
|
-
totalAmount: expect.any(Number),
|
|
208
|
-
broker: {
|
|
368
|
+
for (const broker of response.items) {
|
|
369
|
+
expect(broker).toMatchObject({
|
|
209
370
|
id: expect.any(Number),
|
|
210
371
|
symbol: expect.any(String),
|
|
211
372
|
name: expect.any(String),
|
|
212
373
|
longName: expect.any(String),
|
|
213
374
|
logo: expect.any(String),
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
});
|
|
217
378
|
});
|
|
218
379
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
toDate,
|
|
224
|
-
BrokerSort.Volume,
|
|
225
|
-
"BIYKR"
|
|
226
|
-
);
|
|
380
|
+
describe("Mock Tests", () => {
|
|
381
|
+
beforeEach(() => {
|
|
382
|
+
jest.clearAllMocks();
|
|
383
|
+
});
|
|
227
384
|
|
|
228
|
-
|
|
385
|
+
describe("getMarketBrokers", () => {
|
|
386
|
+
test("should return market brokers with stats", async () => {
|
|
387
|
+
jest.spyOn(brokerClient, 'getMarketBrokers').mockResolvedValue(mockBrokerList);
|
|
229
388
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
389
|
+
const response = await brokerClient.getMarketBrokers(
|
|
390
|
+
Region.Tr,
|
|
391
|
+
BrokerSort.TotalVolume,
|
|
392
|
+
SortDirection.Desc,
|
|
393
|
+
fromDate,
|
|
394
|
+
toDate,
|
|
395
|
+
0,
|
|
396
|
+
5
|
|
397
|
+
);
|
|
398
|
+
|
|
399
|
+
expect(response.recordCount).toBe(2);
|
|
400
|
+
expect(response.items).toHaveLength(2);
|
|
401
|
+
expect(response.totalStats).toEqual(mockBrokerStats);
|
|
402
|
+
|
|
403
|
+
const firstItem = response.items[0];
|
|
404
|
+
expect(firstItem.broker?.symbol).toBe("BIYKR");
|
|
405
|
+
expect(firstItem.totalBuyAmount).toBe(1000000);
|
|
406
|
+
expect(firstItem.totalSellAmount).toBe(800000);
|
|
407
|
+
|
|
408
|
+
expect(brokerClient.getMarketBrokers).toHaveBeenCalledWith(
|
|
409
|
+
Region.Tr,
|
|
410
|
+
BrokerSort.TotalVolume,
|
|
411
|
+
SortDirection.Desc,
|
|
412
|
+
fromDate,
|
|
413
|
+
toDate,
|
|
414
|
+
0,
|
|
415
|
+
5
|
|
416
|
+
);
|
|
239
417
|
});
|
|
240
|
-
}
|
|
241
418
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
419
|
+
test("should handle empty response", async () => {
|
|
420
|
+
const emptyResponse: BrokerList = {
|
|
421
|
+
recordCount: 0,
|
|
422
|
+
items: [],
|
|
423
|
+
totalStats: {
|
|
424
|
+
totalBuyAmount: 0,
|
|
425
|
+
totalSellAmount: 0,
|
|
426
|
+
netAmount: 0,
|
|
427
|
+
totalBuyVolume: 0,
|
|
428
|
+
totalSellVolume: 0,
|
|
429
|
+
totalVolume: 0,
|
|
430
|
+
totalAmount: 0
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
jest.spyOn(brokerClient, 'getMarketBrokers').mockResolvedValue(emptyResponse);
|
|
434
|
+
|
|
435
|
+
const response = await brokerClient.getMarketBrokers(
|
|
436
|
+
Region.Tr,
|
|
437
|
+
BrokerSort.TotalVolume,
|
|
438
|
+
SortDirection.Desc,
|
|
439
|
+
fromDate,
|
|
440
|
+
toDate,
|
|
441
|
+
0,
|
|
442
|
+
5
|
|
443
|
+
);
|
|
444
|
+
|
|
445
|
+
expect(response.recordCount).toBe(0);
|
|
446
|
+
expect(response.items).toHaveLength(0);
|
|
447
|
+
expect(response.totalStats.totalAmount).toBe(0);
|
|
448
|
+
});
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
describe("getMarketStocks", () => {
|
|
452
|
+
test("should return market stocks with stats", async () => {
|
|
453
|
+
jest.spyOn(brokerClient, 'getMarketStocks').mockResolvedValue(mockBrokerList);
|
|
454
|
+
|
|
455
|
+
const response = await brokerClient.getMarketStocks(
|
|
456
|
+
Region.Tr,
|
|
457
|
+
BrokerSort.TotalVolume,
|
|
458
|
+
SortDirection.Desc,
|
|
459
|
+
fromDate,
|
|
460
|
+
toDate,
|
|
461
|
+
0,
|
|
462
|
+
5
|
|
463
|
+
);
|
|
464
|
+
|
|
465
|
+
expect(response.recordCount).toBe(2);
|
|
466
|
+
expect(response.items).toHaveLength(2);
|
|
467
|
+
expect(response.totalStats).toEqual(mockBrokerStats);
|
|
468
|
+
|
|
469
|
+
const firstItem = response.items[0];
|
|
470
|
+
expect(firstItem.stock?.symbol).toBe("TUPRS");
|
|
471
|
+
expect(firstItem.stock?.assetType).toBe(AssetType.Stock);
|
|
472
|
+
expect(firstItem.stock?.assetClass).toBe(AssetClass.Equity);
|
|
473
|
+
|
|
474
|
+
expect(brokerClient.getMarketStocks).toHaveBeenCalledWith(
|
|
475
|
+
Region.Tr,
|
|
476
|
+
BrokerSort.TotalVolume,
|
|
477
|
+
SortDirection.Desc,
|
|
478
|
+
fromDate,
|
|
479
|
+
toDate,
|
|
480
|
+
0,
|
|
481
|
+
5
|
|
482
|
+
);
|
|
483
|
+
});
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
describe("getBrokersByStock", () => {
|
|
487
|
+
test("should return brokers for specific stock", async () => {
|
|
488
|
+
jest.spyOn(brokerClient, 'getBrokersByStock').mockResolvedValue(mockBrokerList);
|
|
489
|
+
|
|
490
|
+
const response = await brokerClient.getBrokersByStock(
|
|
491
|
+
"TUPRS",
|
|
492
|
+
Region.Tr,
|
|
493
|
+
BrokerSort.TotalVolume,
|
|
494
|
+
SortDirection.Desc,
|
|
495
|
+
fromDate,
|
|
496
|
+
toDate,
|
|
497
|
+
0,
|
|
498
|
+
5
|
|
499
|
+
);
|
|
500
|
+
|
|
501
|
+
expect(response.recordCount).toBe(2);
|
|
502
|
+
expect(response.items).toHaveLength(2);
|
|
503
|
+
expect(response.totalStats).toEqual(mockBrokerStats);
|
|
504
|
+
|
|
505
|
+
const firstItem = response.items[0];
|
|
506
|
+
expect(firstItem.broker?.symbol).toBe("BIYKR");
|
|
507
|
+
expect(firstItem.averageCost).toBe(20.5);
|
|
508
|
+
|
|
509
|
+
expect(brokerClient.getBrokersByStock).toHaveBeenCalledWith(
|
|
510
|
+
"TUPRS",
|
|
511
|
+
Region.Tr,
|
|
512
|
+
BrokerSort.TotalVolume,
|
|
513
|
+
SortDirection.Desc,
|
|
514
|
+
fromDate,
|
|
515
|
+
toDate,
|
|
516
|
+
0,
|
|
517
|
+
5
|
|
518
|
+
);
|
|
259
519
|
});
|
|
260
|
-
|
|
520
|
+
|
|
521
|
+
test("should handle invalid stock symbol", async () => {
|
|
522
|
+
jest.spyOn(brokerClient, 'getBrokersByStock').mockRejectedValue(new Error("Invalid stock symbol"));
|
|
523
|
+
|
|
524
|
+
await expect(brokerClient.getBrokersByStock(
|
|
525
|
+
"INVALID",
|
|
526
|
+
Region.Tr,
|
|
527
|
+
BrokerSort.TotalVolume,
|
|
528
|
+
SortDirection.Desc,
|
|
529
|
+
fromDate,
|
|
530
|
+
toDate,
|
|
531
|
+
0,
|
|
532
|
+
5
|
|
533
|
+
)).rejects.toThrow("Invalid stock symbol");
|
|
534
|
+
});
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
describe("getStocksByBroker", () => {
|
|
538
|
+
test("should return stocks for specific broker", async () => {
|
|
539
|
+
jest.spyOn(brokerClient, 'getStocksByBroker').mockResolvedValue(mockBrokerList);
|
|
540
|
+
|
|
541
|
+
const response = await brokerClient.getStocksByBroker(
|
|
542
|
+
"BIYKR",
|
|
543
|
+
Region.Tr,
|
|
544
|
+
BrokerSort.TotalVolume,
|
|
545
|
+
SortDirection.Desc,
|
|
546
|
+
fromDate,
|
|
547
|
+
toDate,
|
|
548
|
+
0,
|
|
549
|
+
5
|
|
550
|
+
);
|
|
551
|
+
|
|
552
|
+
expect(response.recordCount).toBe(2);
|
|
553
|
+
expect(response.items).toHaveLength(2);
|
|
554
|
+
expect(response.totalStats).toEqual(mockBrokerStats);
|
|
555
|
+
|
|
556
|
+
const firstItem = response.items[0];
|
|
557
|
+
expect(firstItem.stock?.symbol).toBe("TUPRS");
|
|
558
|
+
expect(firstItem.stock?.assetType).toBe(AssetType.Stock);
|
|
559
|
+
|
|
560
|
+
expect(brokerClient.getStocksByBroker).toHaveBeenCalledWith(
|
|
561
|
+
"BIYKR",
|
|
562
|
+
Region.Tr,
|
|
563
|
+
BrokerSort.TotalVolume,
|
|
564
|
+
SortDirection.Desc,
|
|
565
|
+
fromDate,
|
|
566
|
+
toDate,
|
|
567
|
+
0,
|
|
568
|
+
5
|
|
569
|
+
);
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
test("should handle invalid broker symbol", async () => {
|
|
573
|
+
jest.spyOn(brokerClient, 'getStocksByBroker').mockRejectedValue(new Error("Invalid broker symbol"));
|
|
574
|
+
|
|
575
|
+
await expect(brokerClient.getStocksByBroker(
|
|
576
|
+
"INVALID",
|
|
577
|
+
Region.Tr,
|
|
578
|
+
BrokerSort.TotalVolume,
|
|
579
|
+
SortDirection.Desc,
|
|
580
|
+
fromDate,
|
|
581
|
+
toDate,
|
|
582
|
+
0,
|
|
583
|
+
5
|
|
584
|
+
)).rejects.toThrow("Invalid broker symbol");
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
describe("getBrokers", () => {
|
|
589
|
+
test("should return paginated broker list", async () => {
|
|
590
|
+
jest.spyOn(brokerClient, 'getBrokers').mockResolvedValue(mockBrokersPaginatedResponse);
|
|
591
|
+
|
|
592
|
+
const response = await brokerClient.getBrokers(
|
|
593
|
+
Region.Tr,
|
|
594
|
+
0,
|
|
595
|
+
5,
|
|
596
|
+
AssetClass.Equity
|
|
597
|
+
);
|
|
598
|
+
|
|
599
|
+
expect(response.recordCount).toBe(2);
|
|
600
|
+
expect(response.items).toHaveLength(2);
|
|
601
|
+
|
|
602
|
+
const firstBroker = response.items[0];
|
|
603
|
+
expect(firstBroker.id).toBe(1001);
|
|
604
|
+
expect(firstBroker.symbol).toBe("BIYKR");
|
|
605
|
+
expect(firstBroker.name).toBe("BİYİKLI YATIRIM");
|
|
606
|
+
expect(firstBroker.longName).toBe("Bıyıklı Yatırım Menkul Değerler A.Ş.");
|
|
607
|
+
expect(firstBroker.logo).toBe("https://example.com/biykr.png");
|
|
608
|
+
expect(firstBroker.supportedAssetClasses).toEqual([AssetClass.Equity]);
|
|
609
|
+
|
|
610
|
+
expect(brokerClient.getBrokers).toHaveBeenCalledWith(
|
|
611
|
+
Region.Tr,
|
|
612
|
+
0,
|
|
613
|
+
5,
|
|
614
|
+
AssetClass.Equity
|
|
615
|
+
);
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
test("should handle getBrokers without assetClass parameter", async () => {
|
|
619
|
+
jest.spyOn(brokerClient, 'getBrokers').mockResolvedValue(mockBrokersPaginatedResponse);
|
|
620
|
+
|
|
621
|
+
const response = await brokerClient.getBrokers(
|
|
622
|
+
Region.Tr,
|
|
623
|
+
0,
|
|
624
|
+
5
|
|
625
|
+
);
|
|
626
|
+
|
|
627
|
+
expect(response.recordCount).toBe(2);
|
|
628
|
+
expect(response.items).toHaveLength(2);
|
|
629
|
+
|
|
630
|
+
const firstBroker = response.items[0];
|
|
631
|
+
expect(firstBroker.id).toBe(1001);
|
|
632
|
+
expect(firstBroker.symbol).toBe("BIYKR");
|
|
633
|
+
expect(firstBroker.name).toBe("BİYİKLI YATIRIM");
|
|
634
|
+
expect(firstBroker.longName).toBe("Bıyıklı Yatırım Menkul Değerler A.Ş.");
|
|
635
|
+
expect(firstBroker.logo).toBe("https://example.com/biykr.png");
|
|
636
|
+
|
|
637
|
+
expect(brokerClient.getBrokers).toHaveBeenCalledWith(
|
|
638
|
+
Region.Tr,
|
|
639
|
+
0,
|
|
640
|
+
5
|
|
641
|
+
);
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
test("should handle empty brokers response", async () => {
|
|
645
|
+
const emptyResponse: PaginatedResponse<Broker> = {
|
|
646
|
+
recordCount: 0,
|
|
647
|
+
items: []
|
|
648
|
+
};
|
|
649
|
+
jest.spyOn(brokerClient, 'getBrokers').mockResolvedValue(emptyResponse);
|
|
650
|
+
|
|
651
|
+
const response = await brokerClient.getBrokers(
|
|
652
|
+
Region.Tr,
|
|
653
|
+
0,
|
|
654
|
+
10
|
|
655
|
+
);
|
|
656
|
+
|
|
657
|
+
expect(response.recordCount).toBe(0);
|
|
658
|
+
expect(response.items).toHaveLength(0);
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
test("should handle getBrokers error", async () => {
|
|
662
|
+
jest.spyOn(brokerClient, 'getBrokers').mockRejectedValue(new Error("Unsupported asset class"));
|
|
663
|
+
|
|
664
|
+
await expect(brokerClient.getBrokers(
|
|
665
|
+
Region.Tr,
|
|
666
|
+
0,
|
|
667
|
+
10,
|
|
668
|
+
AssetClass.Crypto
|
|
669
|
+
)).rejects.toThrow("Unsupported asset class");
|
|
670
|
+
});
|
|
671
|
+
});
|
|
261
672
|
});
|
|
262
|
-
});
|
|
673
|
+
});
|