laplace-api 4.0.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.
@@ -1,108 +1,235 @@
1
1
  import { Client } from "./client";
2
2
  import { Region } from "./collections";
3
- import { v4 as uuidv4 } from 'uuid';
4
- import { LivePriceFeed } from "./live-price-web-socket";
3
+ import { v4 as uuidv4 } from "uuid";
5
4
 
6
- interface WebSocketUrlResponse {
7
- url: string;
8
- }
5
+ export type MessageType = "pr" | "state_change" | "heartbeat" | "ob";
9
6
 
10
- interface WebSocketUrlParams {
11
- externalUserId: string;
12
- feeds: LivePriceFeed[];
7
+ // Stream Message Wrapper - v2 formatter wraps all messages in this structure
8
+ export interface StreamMessage<T> {
9
+ t: MessageType;
10
+ d: T;
13
11
  }
14
12
 
15
- export interface BISTStockLiveData {
16
- s: string; // Symbol
13
+ export interface BISTStockPriceData {
14
+ s: string; // Symbol
17
15
  ch: number; // DailyPercentChange
18
16
  p: number; // ClosePrice
17
+ d: number; // Date
18
+ }
19
+
20
+ export interface USStockPriceData {
21
+ s: string; // Symbol
22
+ p: number; // Price
23
+ d: number; // Date
19
24
  }
20
25
 
21
- export interface USStockLiveData {
22
- s: string; // Symbol
23
- bp: number; // BidPrice
24
- ap: number; // AskPrice
26
+ export type BISTStockStreamData = StreamMessage<BISTStockPriceData>;
27
+ export type USStockStreamData = StreamMessage<USStockPriceData>;
28
+
29
+ export enum OrderbookLevelSide {
30
+ Bid = "bid",
31
+ Ask = "ask"
25
32
  }
26
33
 
27
- export enum AccessorType {
28
- User = "user"
34
+ export interface OrderbookLevel {
35
+ level: number;
36
+ vol: number;
37
+ orders: number;
38
+ p: number;
39
+ side: OrderbookLevelSide;
40
+ }
41
+
42
+ export interface OrderbookDeletedLevel {
43
+ level: number;
44
+ side: OrderbookLevelSide;
45
+ }
46
+
47
+ export interface OrderbookLiveData {
48
+ updated?: OrderbookLevel[];
49
+ deleted?: OrderbookDeletedLevel[];
50
+ symbol: string;
51
+ }
52
+
53
+ export enum PriceDataType {
54
+ Live = "live",
55
+ Delayed = "delayed",
56
+ Orderbook = "orderbook",
57
+ }
58
+
59
+ export interface ILivePriceClient<T> {
60
+ close(): void;
61
+ receive(): AsyncIterable<T>;
62
+ subscribe(symbols: string[]): Promise<void>;
63
+ }
64
+
65
+ class LivePriceClientImpl<T> implements ILivePriceClient<T> {
66
+ private client: Client;
67
+ private region: Region;
68
+ private dataType: PriceDataType;
69
+ private symbols: string[] = [];
70
+ private closed = false;
71
+ private currentStream: AsyncIterable<T> | null = null;
72
+ private cancelFn: (() => void) | null = null;
73
+
74
+ constructor(client: Client, region: Region, dataType: PriceDataType) {
75
+ this.client = client;
76
+ this.region = region;
77
+ this.dataType = dataType;
78
+ }
79
+
80
+ close(): void {
81
+ if (this.closed) return;
82
+
83
+ this.closed = true;
84
+ if (this.cancelFn) {
85
+ this.cancelFn();
86
+ }
87
+ }
88
+
89
+ receive(): AsyncIterable<T> {
90
+ if (!this.currentStream) {
91
+ throw new Error("Not subscribed. Call subscribe() first.");
92
+ }
93
+ return this.currentStream;
94
+ }
95
+
96
+ async subscribe(symbols: string[]): Promise<void> {
97
+ // Cancel existing connection
98
+ if (this.cancelFn) {
99
+ this.cancelFn();
100
+ }
101
+
102
+ const streamId = uuidv4();
103
+ let url: string;
104
+
105
+ switch (this.dataType) {
106
+ case PriceDataType.Live:
107
+ url = `${
108
+ this.client["baseUrl"]
109
+ }/api/v2/stock/price/live?filter=${symbols.join(",")}&region=${
110
+ this.region
111
+ }&stream=${streamId}`;
112
+ break;
113
+ case PriceDataType.Delayed:
114
+ url = `${
115
+ this.client["baseUrl"]
116
+ }/api/v1/stock/price/delayed?filter=${symbols.join(",")}&region=${
117
+ this.region
118
+ }&stream=${streamId}`;
119
+ break;
120
+ case PriceDataType.Orderbook:
121
+ url = `${
122
+ this.client["baseUrl"]
123
+ }/api/v1/stock/orderbook/live?filter=${symbols.join(",")}&region=${
124
+ this.region
125
+ }&stream=${streamId}`;
126
+ break;
127
+ }
128
+
129
+ const { events, cancel } = this.client.sendSSERequest<T>(url);
130
+
131
+ this.currentStream = events;
132
+ this.cancelFn = cancel;
133
+ this.symbols = symbols;
134
+ this.closed = false;
135
+ }
136
+ }
137
+
138
+ export function getLivePrice<T>(
139
+ client: Client,
140
+ symbols: string[],
141
+ region: Region
142
+ ): ILivePriceClient<T> {
143
+ if (!client) {
144
+ throw new Error("Client cannot be null");
145
+ }
146
+
147
+ const livePriceClient = new LivePriceClientImpl<T>(client, region, PriceDataType.Live);
148
+ livePriceClient.subscribe(symbols).catch((error) => {
149
+ console.error("Failed to initialize live price client", error);
150
+ });
151
+
152
+ return livePriceClient;
29
153
  }
30
154
 
31
- interface UpdateUserDetailsParams {
32
- externalUserID: string;
33
- firstName?: string;
34
- lastName?: string;
35
- address?: string;
36
- city?: string;
37
- countryCode?: string;
38
- accessorType?: AccessorType;
39
- active: boolean;
155
+ export function getDelayedPrice<T>(
156
+ client: Client,
157
+ symbols: string[],
158
+ region: Region,
159
+ ): ILivePriceClient<T> {
160
+ if (!client) {
161
+ throw new Error("Client cannot be null");
162
+ }
163
+
164
+ const livePriceClient = new LivePriceClientImpl<T>(client, region, PriceDataType.Delayed);
165
+ livePriceClient.subscribe(symbols).catch((error) => {
166
+ console.error("Failed to initialize live price client", error);
167
+ });
168
+
169
+ return livePriceClient;
40
170
  }
41
171
 
42
- function getSSELivePrice<T>(
172
+ function getOrderbook<T>(
43
173
  client: Client,
44
174
  symbols: string[],
45
175
  region: Region,
46
- streamId: string = uuidv4(),
47
- ): {
48
- events: AsyncIterable<T>,
49
- cancel: () => void
50
- } {
51
- const url = `${client["baseUrl"]}/api/v1/stock/price/live?filter=${symbols.join(',')}&region=${region}&stream=${streamId}`;
176
+ ): ILivePriceClient<T> {
177
+ if (!client) {
178
+ throw new Error("Client cannot be null");
179
+ }
180
+
181
+ const orderbookClient = new LivePriceClientImpl<T>(client, region, PriceDataType.Orderbook);
182
+ orderbookClient.subscribe(symbols).catch((error) => {
183
+ console.error("Failed to initialize orderbook client", error);
184
+ });
52
185
 
53
- return client.sendSSERequest<T>(url);
186
+ return orderbookClient;
187
+ }
188
+
189
+ export function getLivePriceForBIST(
190
+ client: Client,
191
+ symbols: string[]
192
+ ): ILivePriceClient<BISTStockStreamData> {
193
+ return getLivePrice<BISTStockStreamData>(client, symbols, Region.Tr);
194
+ }
195
+
196
+ export function getLivePriceForUS(
197
+ client: Client,
198
+ symbols: string[]
199
+ ): ILivePriceClient<USStockStreamData> {
200
+ return getLivePrice<USStockStreamData>(client, symbols, Region.Us);
201
+ }
202
+
203
+ export function getDelayedPriceForBIST(
204
+ client: Client,
205
+ symbols: string[]
206
+ ): ILivePriceClient<BISTStockStreamData> {
207
+ return getDelayedPrice<BISTStockStreamData>(client, symbols, Region.Tr);
208
+ }
209
+
210
+ export function getOrderbookForBIST(
211
+ client: Client,
212
+ symbols: string[]
213
+ ): ILivePriceClient<OrderbookLiveData> {
214
+ return getOrderbook<OrderbookLiveData>(client, symbols, Region.Tr);
54
215
  }
55
216
 
56
217
  export class LivePriceClient extends Client {
57
- async getWebSocketUrl(
58
- externalUserId: string,
59
- feeds: LivePriceFeed[]
60
- ): Promise<string> {
61
- const url = new URL(`${this["baseUrl"]}/api/v2/ws/url`);
62
-
63
- const params: WebSocketUrlParams = {
64
- externalUserId,
65
- feeds
66
- };
67
-
68
- const response = await this.sendRequest<WebSocketUrlResponse>({
69
- method: "POST",
70
- url: url.toString(),
71
- data: params,
72
- });
73
-
74
- return response.url;
218
+ getLivePriceForBIST(symbols: string[]): ILivePriceClient<BISTStockStreamData> {
219
+ return getLivePriceForBIST(this, symbols);
75
220
  }
76
221
 
77
- async updateUserDetails(params: UpdateUserDetailsParams): Promise<void> {
78
- const url = new URL(`${this["baseUrl"]}/api/v1/ws/user`);
79
-
80
- await this.sendRequest<void>({
81
- method: "PUT",
82
- url: url.toString(),
83
- data: params,
84
- });
222
+ getLivePriceForUS(symbols: string[]): ILivePriceClient<USStockStreamData> {
223
+ return getLivePriceForUS(this, symbols);
85
224
  }
86
225
 
87
- getLivePriceForBIST(
88
- symbols: string[],
89
- region: Region,
90
- streamId?: string,
91
- ): {
92
- events: AsyncIterable<BISTStockLiveData>,
93
- cancel: () => void
94
- } {
95
- return getSSELivePrice<BISTStockLiveData>(this, symbols, region, streamId);
226
+ getDelayedPriceForBIST(
227
+ symbols: string[],
228
+ ): ILivePriceClient<BISTStockStreamData> {
229
+ return getDelayedPriceForBIST(this, symbols);
96
230
  }
97
231
 
98
- getLivePriceForUS(
99
- symbols: string[],
100
- region: Region,
101
- streamId?: string,
102
- ): {
103
- events: AsyncIterable<USStockLiveData>,
104
- cancel: () => void
105
- } {
106
- return getSSELivePrice<USStockLiveData>(this, symbols, region, streamId);
232
+ getOrderbookForBIST(symbols: string[]): ILivePriceClient<OrderbookLiveData> {
233
+ return getOrderbookForBIST(this, symbols);
107
234
  }
108
235
  }
@@ -0,0 +1,75 @@
1
+ import { Client } from "./client";
2
+
3
+ export interface Politician {
4
+ id: number;
5
+ politicianName: string;
6
+ totalHoldings: number;
7
+ lastUpdated: Date;
8
+ }
9
+
10
+ export interface Holding {
11
+ politicianName: string;
12
+ symbol: string;
13
+ company: string;
14
+ holding: string;
15
+ allocation: string;
16
+ lastUpdated: Date;
17
+ }
18
+
19
+ export interface HoldingShort {
20
+ symbol: string;
21
+ company: string;
22
+ holding: string;
23
+ allocation: string;
24
+ }
25
+
26
+ export interface TopHolding {
27
+ symbol: string;
28
+ company: string;
29
+ politicians: TopHoldingPolitician[];
30
+ count: number;
31
+ }
32
+
33
+ export interface TopHoldingPolitician {
34
+ name: string;
35
+ holding: string;
36
+ allocation: string;
37
+ }
38
+
39
+ export interface PoliticianDetail {
40
+ id: number;
41
+ name: string;
42
+ holdings: HoldingShort[];
43
+ totalHoldings: number;
44
+ lastUpdated: Date;
45
+ }
46
+
47
+ export class PoliticianClient extends Client {
48
+ async getAllPolitician(): Promise<Politician[]> {
49
+ return await this.sendRequest<Politician[]>({
50
+ method: 'GET',
51
+ url: `/api/v1/politician`,
52
+ });
53
+ }
54
+
55
+ async getPoliticianHoldingBySymbol(symbol: string): Promise<Holding[]> {
56
+ return await this.sendRequest<Holding[]>({
57
+ method: 'GET',
58
+ url: `/api/v1/holding/${symbol}`
59
+ })
60
+ }
61
+
62
+ async getAllTopHoldings(): Promise<TopHolding[]> {
63
+ return await this.sendRequest<TopHolding[]>({
64
+ method: 'GET',
65
+ url: `/api/v1/top-holding`
66
+ })
67
+ }
68
+
69
+ async getPoliticianDetail(id: number): Promise<PoliticianDetail> {
70
+ return await this.sendRequest<PoliticianDetail>({
71
+ method: 'GET',
72
+ url: `/api/v1/politician/${id}`
73
+ })
74
+ }
75
+ }
@@ -1,3 +1,4 @@
1
+ import { PaginatedResponse } from './capital_increase';
1
2
  import { Client } from './client';
2
3
  import { Region, Locale } from './collections';
3
4
  import { LaplaceHTTPError } from './errors';
@@ -122,6 +123,32 @@ export interface TickSizeRule {
122
123
  tickSize: number;
123
124
  }
124
125
 
126
+ export interface EarningsTranscriptListItem {
127
+ symbol: string;
128
+ year: number;
129
+ quarter: number;
130
+ date: string;
131
+ fiscal_year: number;
132
+ }
133
+
134
+ export interface EarningsTranscriptWithSummary {
135
+ symbol: string;
136
+ year: number;
137
+ quarter: number;
138
+ date: string;
139
+ content: string;
140
+ summary?: string;
141
+ has_summary: boolean;
142
+ }
143
+
144
+ export interface MarketState {
145
+ id: number;
146
+ marketSymbol?: string | null;
147
+ state: string;
148
+ lastTimestamp: string;
149
+ stockSymbol?: string | null;
150
+ }
151
+
125
152
  export class StockClient extends Client {
126
153
  async getAllStocks(region: Region, page: number|null = null, pageSize: number|null = null): Promise<Stock[]> {
127
154
  return this.sendRequest<Stock[]>({
@@ -205,4 +232,50 @@ export class StockClient extends Client {
205
232
  params: { symbol, region },
206
233
  });
207
234
  }
235
+
236
+ async getEarningsTranscripts(symbol: string, region: Region): Promise<EarningsTranscriptListItem[]> {
237
+ return this.sendRequest<EarningsTranscriptListItem[]>({
238
+ method: 'GET',
239
+ url: '/api/v1/earnings/transcripts',
240
+ params: { symbol, region },
241
+ });
242
+ }
243
+
244
+ async getEarningsTranscript(symbol: string, year: number, quarter: number): Promise<EarningsTranscriptWithSummary> {
245
+ return this.sendRequest<EarningsTranscriptWithSummary>({
246
+ method: 'GET',
247
+ url: '/api/v1/earnings/transcript',
248
+ params: { symbol, year, quarter },
249
+ });
250
+ }
251
+
252
+ async getStockStateAll(page: number, size: number, region: Region): Promise<PaginatedResponse<MarketState>> {
253
+ return this.sendRequest<PaginatedResponse<MarketState>>({
254
+ method: 'GET',
255
+ url: '/api/v1/state/stock/all',
256
+ params: { page, size, region },
257
+ });
258
+ }
259
+
260
+ async getStockState(symbol: string): Promise<MarketState> {
261
+ return this.sendRequest<MarketState>({
262
+ method: 'GET',
263
+ url: `/api/v1/state/stock/${symbol}`,
264
+ });
265
+ }
266
+
267
+ async getStateAll(page: number, size: number, region: Region): Promise<PaginatedResponse<MarketState>> {
268
+ return this.sendRequest<PaginatedResponse<MarketState>>({
269
+ method: 'GET',
270
+ url: '/api/v1/state/all',
271
+ params: { page, size, region },
272
+ });
273
+ }
274
+
275
+ async getState(symbol: string): Promise<MarketState> {
276
+ return this.sendRequest<MarketState>({
277
+ method: 'GET',
278
+ url: `/api/v1/state/${symbol}`,
279
+ });
280
+ }
208
281
  }