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