@fullstackcraftllc/floe 0.0.1 → 0.0.2
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/README.md +9 -209
- package/dist/adapters/index.js +64 -16
- package/dist/client/FloeClient.d.ts +352 -0
- package/dist/client/FloeClient.js +465 -0
- package/dist/client/brokers/TradierClient.d.ts +161 -0
- package/dist/client/brokers/TradierClient.js +434 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +14 -1
- package/dist/types/index.d.ts +35 -0
- package/dist/utils/occ.d.ts +164 -0
- package/dist/utils/occ.js +202 -0
- package/package.json +3 -3
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FloeClient = exports.Broker = void 0;
|
|
4
|
+
const TradierClient_1 = require("./brokers/TradierClient");
|
|
5
|
+
/**
|
|
6
|
+
* Supported broker integrations for the FloeClient.
|
|
7
|
+
* @enum {string}
|
|
8
|
+
*/
|
|
9
|
+
var Broker;
|
|
10
|
+
(function (Broker) {
|
|
11
|
+
/** Tradier brokerage API */
|
|
12
|
+
Broker["TRADIER"] = "tradier";
|
|
13
|
+
// Future brokers can be added here
|
|
14
|
+
})(Broker || (exports.Broker = Broker = {}));
|
|
15
|
+
/**
|
|
16
|
+
* FloeClient provides a unified, broker-agnostic interface for subscribing to
|
|
17
|
+
* real-time market data including stock tickers and options.
|
|
18
|
+
*
|
|
19
|
+
* @remarks
|
|
20
|
+
* The client normalizes data from various brokers into a consistent format,
|
|
21
|
+
* allowing consumers to switch brokers without changing their application code.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* const client = new FloeClient();
|
|
26
|
+
*
|
|
27
|
+
* // Connect to a broker
|
|
28
|
+
* client.connect(Broker.TRADIER, 'your-api-key');
|
|
29
|
+
*
|
|
30
|
+
* // Subscribe to updates using the event emitter pattern
|
|
31
|
+
* client.on('tickerUpdate', (ticker) => {
|
|
32
|
+
* console.log(`${ticker.symbol}: ${ticker.price}`);
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* // Or use the callback pattern
|
|
36
|
+
* client.onTickerDataChange((ticker) => {
|
|
37
|
+
* console.log(`${ticker.symbol}: ${ticker.price}`);
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* // Subscribe to specific tickers
|
|
41
|
+
* client.subscribeToTickers(['AAPL', 'GOOGL', 'MSFT']);
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
class FloeClient {
|
|
45
|
+
/**
|
|
46
|
+
* Creates a new FloeClient instance.
|
|
47
|
+
*
|
|
48
|
+
* @remarks
|
|
49
|
+
* The client is created in a disconnected state. Call {@link connect} to
|
|
50
|
+
* establish a connection to a broker before subscribing to data.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* const client = new FloeClient();
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
constructor() {
|
|
58
|
+
/** Currently connected broker, or null if not connected */
|
|
59
|
+
this.currentBroker = null;
|
|
60
|
+
/** List of ticker symbols currently subscribed to */
|
|
61
|
+
this.currentSubscribedTickers = [];
|
|
62
|
+
/** List of option symbols (OCC format) currently subscribed to */
|
|
63
|
+
this.currentSubscribedOptions = [];
|
|
64
|
+
/** Cache of the latest normalized ticker data */
|
|
65
|
+
this.normalizedTickers = [];
|
|
66
|
+
/** Cache of the latest normalized option data */
|
|
67
|
+
this.normalizedOptions = [];
|
|
68
|
+
/** Tradier broker client instance */
|
|
69
|
+
this.tradierClient = null;
|
|
70
|
+
/** Event listeners registry for the EventEmitter pattern */
|
|
71
|
+
this.eventListeners = new Map();
|
|
72
|
+
/** Callback for ticker data changes (legacy callback pattern) */
|
|
73
|
+
this.tickerDataCallback = null;
|
|
74
|
+
/** Callback for option data changes (legacy callback pattern) */
|
|
75
|
+
this.optionDataCallback = null;
|
|
76
|
+
// Initialize event listener maps for each event type
|
|
77
|
+
this.eventListeners.set('tickerUpdate', new Set());
|
|
78
|
+
this.eventListeners.set('optionUpdate', new Set());
|
|
79
|
+
this.eventListeners.set('error', new Set());
|
|
80
|
+
this.eventListeners.set('connected', new Set());
|
|
81
|
+
this.eventListeners.set('disconnected', new Set());
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Establishes a connection to a broker's API.
|
|
85
|
+
*
|
|
86
|
+
* @param broker - The broker to connect to (e.g., Broker.TRADIER)
|
|
87
|
+
* @param authKey - The API authentication key or token for the broker
|
|
88
|
+
*
|
|
89
|
+
* @throws {Error} Throws if the specified broker is not supported
|
|
90
|
+
*
|
|
91
|
+
* @remarks
|
|
92
|
+
* Must be called before subscribing to any market data. Only one broker
|
|
93
|
+
* connection is active at a time; calling connect again will switch brokers.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```typescript
|
|
97
|
+
* await client.connect(Broker.TRADIER, 'your-tradier-api-key');
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
async connect(broker, authKey) {
|
|
101
|
+
this.currentBroker = broker;
|
|
102
|
+
// Connection logic to the broker's API using the authKey
|
|
103
|
+
switch (broker.toLowerCase()) {
|
|
104
|
+
case Broker.TRADIER:
|
|
105
|
+
this.tradierClient = new TradierClient_1.TradierClient(authKey);
|
|
106
|
+
// Wire up TradierClient events to FloeClient events
|
|
107
|
+
this.tradierClient.on('tickerUpdate', (ticker) => {
|
|
108
|
+
this.emit('tickerUpdate', ticker);
|
|
109
|
+
});
|
|
110
|
+
this.tradierClient.on('optionUpdate', (option) => {
|
|
111
|
+
this.emit('optionUpdate', option);
|
|
112
|
+
});
|
|
113
|
+
this.tradierClient.on('error', (error) => {
|
|
114
|
+
this.emit('error', error);
|
|
115
|
+
});
|
|
116
|
+
this.tradierClient.on('disconnected', () => {
|
|
117
|
+
this.emit('disconnected', { broker, reason: 'WebSocket disconnected' });
|
|
118
|
+
});
|
|
119
|
+
// Connect to the streaming API
|
|
120
|
+
await this.tradierClient.connect();
|
|
121
|
+
break;
|
|
122
|
+
default:
|
|
123
|
+
throw new Error(`Unsupported broker: ${broker}`);
|
|
124
|
+
}
|
|
125
|
+
this.emit('connected', { broker });
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Disconnects from the current broker.
|
|
129
|
+
*
|
|
130
|
+
* @remarks
|
|
131
|
+
* Closes the WebSocket connection and clears all subscriptions.
|
|
132
|
+
*
|
|
133
|
+
* @example
|
|
134
|
+
* ```typescript
|
|
135
|
+
* client.disconnect();
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
138
|
+
disconnect() {
|
|
139
|
+
if (this.tradierClient) {
|
|
140
|
+
this.tradierClient.disconnect();
|
|
141
|
+
this.tradierClient = null;
|
|
142
|
+
}
|
|
143
|
+
const broker = this.currentBroker;
|
|
144
|
+
this.currentBroker = null;
|
|
145
|
+
this.currentSubscribedTickers = [];
|
|
146
|
+
this.currentSubscribedOptions = [];
|
|
147
|
+
if (broker) {
|
|
148
|
+
this.emit('disconnected', { broker, reason: 'Client disconnect' });
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Subscribes to real-time updates for the specified stock ticker symbols.
|
|
153
|
+
*
|
|
154
|
+
* @param tickers - Array of ticker symbols to subscribe to (e.g., ['AAPL', 'GOOGL'])
|
|
155
|
+
*
|
|
156
|
+
* @throws {Error} Throws if no broker connection has been established
|
|
157
|
+
*
|
|
158
|
+
* @remarks
|
|
159
|
+
* Ticker updates will be delivered via the 'tickerUpdate' event or through
|
|
160
|
+
* the callback registered with {@link onTickerDataChange}.
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* ```typescript
|
|
164
|
+
* client.subscribeToTickers(['AAPL', 'GOOGL', 'MSFT']);
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
subscribeToTickers(tickers) {
|
|
168
|
+
this.currentSubscribedTickers.push(...tickers);
|
|
169
|
+
switch (this.currentBroker) {
|
|
170
|
+
case Broker.TRADIER:
|
|
171
|
+
this.tradierClient?.subscribe(tickers);
|
|
172
|
+
break;
|
|
173
|
+
default:
|
|
174
|
+
throw new Error(`Unsupported broker: ${this.currentBroker}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Subscribes to real-time updates for the specified option contracts.
|
|
179
|
+
*
|
|
180
|
+
* @param symbols - Array of option symbols in OCC format
|
|
181
|
+
* (e.g., ['AAPL230120C00150000'] for AAPL $150 Call expiring Jan 20, 2023)
|
|
182
|
+
*
|
|
183
|
+
* @throws {Error} Throws if no broker connection has been established
|
|
184
|
+
*
|
|
185
|
+
* @remarks
|
|
186
|
+
* Option symbols must be in the standard OCC (Options Clearing Corporation) format:
|
|
187
|
+
* - Root symbol (up to 6 characters, left-padded)
|
|
188
|
+
* - Expiration date (YYMMDD)
|
|
189
|
+
* - Option type (C for call, P for put)
|
|
190
|
+
* - Strike price (8 digits, price × 1000, left-padded with zeros)
|
|
191
|
+
*
|
|
192
|
+
* Option updates will be delivered via the 'optionUpdate' event or through
|
|
193
|
+
* the callback registered with {@link onOptionDataChange}.
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* ```typescript
|
|
197
|
+
* // Subscribe to AAPL $150 Call expiring Jan 20, 2023
|
|
198
|
+
* client.subscribeToOptions(['AAPL230120C00150000']);
|
|
199
|
+
* ```
|
|
200
|
+
*/
|
|
201
|
+
subscribeToOptions(symbols) {
|
|
202
|
+
this.currentSubscribedOptions.push(...symbols);
|
|
203
|
+
switch (this.currentBroker) {
|
|
204
|
+
case Broker.TRADIER:
|
|
205
|
+
this.tradierClient?.subscribe(symbols);
|
|
206
|
+
break;
|
|
207
|
+
default:
|
|
208
|
+
throw new Error(`Unsupported broker: ${this.currentBroker}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Unsubscribes from real-time updates for the specified stock ticker symbols.
|
|
213
|
+
*
|
|
214
|
+
* @param tickers - Array of ticker symbols to unsubscribe from
|
|
215
|
+
*
|
|
216
|
+
* @throws {Error} Throws if no broker connection has been established
|
|
217
|
+
*
|
|
218
|
+
* @remarks
|
|
219
|
+
* After unsubscribing, no further updates will be received for these tickers.
|
|
220
|
+
* Has no effect if the specified tickers were not previously subscribed.
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```typescript
|
|
224
|
+
* client.unsubscribeFromTickers(['AAPL', 'GOOGL']);
|
|
225
|
+
* ```
|
|
226
|
+
*/
|
|
227
|
+
unsubscribeFromTickers(tickers) {
|
|
228
|
+
this.currentSubscribedTickers = this.currentSubscribedTickers.filter(ticker => !tickers.includes(ticker));
|
|
229
|
+
switch (this.currentBroker) {
|
|
230
|
+
case Broker.TRADIER:
|
|
231
|
+
this.tradierClient?.unsubscribe(tickers);
|
|
232
|
+
break;
|
|
233
|
+
default:
|
|
234
|
+
throw new Error(`Unsupported broker: ${this.currentBroker}`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Unsubscribes from real-time updates for the specified option contracts.
|
|
239
|
+
*
|
|
240
|
+
* @param symbols - Array of option symbols in OCC format to unsubscribe from
|
|
241
|
+
*
|
|
242
|
+
* @throws {Error} Throws if no broker connection has been established
|
|
243
|
+
*
|
|
244
|
+
* @remarks
|
|
245
|
+
* After unsubscribing, no further updates will be received for these options.
|
|
246
|
+
* Has no effect if the specified options were not previously subscribed.
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* ```typescript
|
|
250
|
+
* client.unsubscribeFromOptions(['AAPL230120C00150000']);
|
|
251
|
+
* ```
|
|
252
|
+
*/
|
|
253
|
+
unsubscribeFromOptions(symbols) {
|
|
254
|
+
this.currentSubscribedOptions = this.currentSubscribedOptions.filter(symbol => !symbols.includes(symbol));
|
|
255
|
+
switch (this.currentBroker) {
|
|
256
|
+
case Broker.TRADIER:
|
|
257
|
+
this.tradierClient?.unsubscribe(symbols);
|
|
258
|
+
break;
|
|
259
|
+
default:
|
|
260
|
+
throw new Error(`Unsupported broker: ${this.currentBroker}`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// ==================== Event Emitter Pattern ====================
|
|
264
|
+
/**
|
|
265
|
+
* Registers an event listener for the specified event type.
|
|
266
|
+
*
|
|
267
|
+
* @template T - The event type
|
|
268
|
+
* @param event - The event type to listen for
|
|
269
|
+
* @param listener - The callback function to invoke when the event occurs
|
|
270
|
+
* @returns The FloeClient instance for method chaining
|
|
271
|
+
*
|
|
272
|
+
* @remarks
|
|
273
|
+
* Multiple listeners can be registered for the same event type.
|
|
274
|
+
* Use {@link off} to remove a listener when it's no longer needed.
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* ```typescript
|
|
278
|
+
* client
|
|
279
|
+
* .on('tickerUpdate', (ticker) => console.log(ticker))
|
|
280
|
+
* .on('error', (error) => console.error(error));
|
|
281
|
+
* ```
|
|
282
|
+
*/
|
|
283
|
+
on(event, listener) {
|
|
284
|
+
const listeners = this.eventListeners.get(event);
|
|
285
|
+
if (listeners) {
|
|
286
|
+
listeners.add(listener);
|
|
287
|
+
}
|
|
288
|
+
return this;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Removes an event listener for the specified event type.
|
|
292
|
+
*
|
|
293
|
+
* @template T - The event type
|
|
294
|
+
* @param event - The event type to stop listening for
|
|
295
|
+
* @param listener - The callback function to remove
|
|
296
|
+
* @returns The FloeClient instance for method chaining
|
|
297
|
+
*
|
|
298
|
+
* @remarks
|
|
299
|
+
* The listener must be the exact same function reference that was passed to {@link on}.
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* ```typescript
|
|
303
|
+
* const handler = (ticker) => console.log(ticker);
|
|
304
|
+
* client.on('tickerUpdate', handler);
|
|
305
|
+
* // Later...
|
|
306
|
+
* client.off('tickerUpdate', handler);
|
|
307
|
+
* ```
|
|
308
|
+
*/
|
|
309
|
+
off(event, listener) {
|
|
310
|
+
const listeners = this.eventListeners.get(event);
|
|
311
|
+
if (listeners) {
|
|
312
|
+
listeners.delete(listener);
|
|
313
|
+
}
|
|
314
|
+
return this;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Registers a one-time event listener that automatically removes itself after firing.
|
|
318
|
+
*
|
|
319
|
+
* @template T - The event type
|
|
320
|
+
* @param event - The event type to listen for
|
|
321
|
+
* @param listener - The callback function to invoke once when the event occurs
|
|
322
|
+
* @returns The FloeClient instance for method chaining
|
|
323
|
+
*
|
|
324
|
+
* @example
|
|
325
|
+
* ```typescript
|
|
326
|
+
* client.once('connected', ({ broker }) => {
|
|
327
|
+
* console.log(`Connected to ${broker}`);
|
|
328
|
+
* });
|
|
329
|
+
* ```
|
|
330
|
+
*/
|
|
331
|
+
once(event, listener) {
|
|
332
|
+
const onceWrapper = ((data) => {
|
|
333
|
+
this.off(event, onceWrapper);
|
|
334
|
+
listener(data);
|
|
335
|
+
});
|
|
336
|
+
return this.on(event, onceWrapper);
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Emits an event to all registered listeners.
|
|
340
|
+
*
|
|
341
|
+
* @template T - The event type
|
|
342
|
+
* @param event - The event type to emit
|
|
343
|
+
* @param data - The event payload
|
|
344
|
+
*
|
|
345
|
+
* @internal
|
|
346
|
+
* @remarks
|
|
347
|
+
* This method is used internally to dispatch events. It also triggers
|
|
348
|
+
* legacy callback handlers for backwards compatibility.
|
|
349
|
+
*/
|
|
350
|
+
emit(event, data) {
|
|
351
|
+
const listeners = this.eventListeners.get(event);
|
|
352
|
+
if (listeners) {
|
|
353
|
+
listeners.forEach(listener => {
|
|
354
|
+
try {
|
|
355
|
+
listener(data);
|
|
356
|
+
}
|
|
357
|
+
catch (error) {
|
|
358
|
+
// Emit error event if a listener throws (but avoid infinite loops)
|
|
359
|
+
if (event !== 'error') {
|
|
360
|
+
this.emit('error', error instanceof Error ? error : new Error(String(error)));
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
// Also trigger legacy callbacks for backwards compatibility
|
|
366
|
+
if (event === 'tickerUpdate' && this.tickerDataCallback) {
|
|
367
|
+
this.tickerDataCallback(data);
|
|
368
|
+
}
|
|
369
|
+
if (event === 'optionUpdate' && this.optionDataCallback) {
|
|
370
|
+
this.optionDataCallback(data);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
// ==================== Callback Pattern (Legacy) ====================
|
|
374
|
+
/**
|
|
375
|
+
* Registers a callback to be invoked whenever ticker data is updated.
|
|
376
|
+
*
|
|
377
|
+
* @param callback - Function to call with the updated ticker data
|
|
378
|
+
*
|
|
379
|
+
* @deprecated Prefer using {@link on}('tickerUpdate', callback) for new code.
|
|
380
|
+
* The event emitter pattern supports multiple listeners and provides
|
|
381
|
+
* better lifecycle management.
|
|
382
|
+
*
|
|
383
|
+
* @remarks
|
|
384
|
+
* Only one callback can be registered at a time. Calling this method again
|
|
385
|
+
* will replace the previous callback. For multiple listeners, use {@link on}.
|
|
386
|
+
*
|
|
387
|
+
* @example
|
|
388
|
+
* ```typescript
|
|
389
|
+
* client.onTickerDataChange((ticker) => {
|
|
390
|
+
* console.log(`${ticker.symbol} updated: ${ticker.price}`);
|
|
391
|
+
* });
|
|
392
|
+
* ```
|
|
393
|
+
*/
|
|
394
|
+
onTickerDataChange(callback) {
|
|
395
|
+
this.tickerDataCallback = callback;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Registers a callback to be invoked whenever option data is updated.
|
|
399
|
+
*
|
|
400
|
+
* @param callback - Function to call with the updated option data
|
|
401
|
+
*
|
|
402
|
+
* @deprecated Prefer using {@link on}('optionUpdate', callback) for new code.
|
|
403
|
+
* The event emitter pattern supports multiple listeners and provides
|
|
404
|
+
* better lifecycle management.
|
|
405
|
+
*
|
|
406
|
+
* @remarks
|
|
407
|
+
* Only one callback can be registered at a time. Calling this method again
|
|
408
|
+
* will replace the previous callback. For multiple listeners, use {@link on}.
|
|
409
|
+
*
|
|
410
|
+
* @example
|
|
411
|
+
* ```typescript
|
|
412
|
+
* client.onOptionDataChange((option) => {
|
|
413
|
+
* console.log(`${option.symbol} bid: ${option.bid}, ask: ${option.ask}`);
|
|
414
|
+
* });
|
|
415
|
+
* ```
|
|
416
|
+
*/
|
|
417
|
+
onOptionDataChange(callback) {
|
|
418
|
+
this.optionDataCallback = callback;
|
|
419
|
+
}
|
|
420
|
+
// ==================== Utility Methods ====================
|
|
421
|
+
/**
|
|
422
|
+
* Returns the list of currently subscribed ticker symbols.
|
|
423
|
+
*
|
|
424
|
+
* @returns Array of ticker symbols currently subscribed to
|
|
425
|
+
*
|
|
426
|
+
* @example
|
|
427
|
+
* ```typescript
|
|
428
|
+
* const tickers = client.getSubscribedTickers();
|
|
429
|
+
* console.log(`Subscribed to: ${tickers.join(', ')}`);
|
|
430
|
+
* ```
|
|
431
|
+
*/
|
|
432
|
+
getSubscribedTickers() {
|
|
433
|
+
return [...this.currentSubscribedTickers];
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Returns the list of currently subscribed option symbols.
|
|
437
|
+
*
|
|
438
|
+
* @returns Array of option symbols (OCC format) currently subscribed to
|
|
439
|
+
*
|
|
440
|
+
* @example
|
|
441
|
+
* ```typescript
|
|
442
|
+
* const options = client.getSubscribedOptions();
|
|
443
|
+
* console.log(`Subscribed to ${options.length} options`);
|
|
444
|
+
* ```
|
|
445
|
+
*/
|
|
446
|
+
getSubscribedOptions() {
|
|
447
|
+
return [...this.currentSubscribedOptions];
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* Returns whether the client is currently connected to a broker.
|
|
451
|
+
*
|
|
452
|
+
* @returns True if connected to a broker, false otherwise
|
|
453
|
+
*
|
|
454
|
+
* @example
|
|
455
|
+
* ```typescript
|
|
456
|
+
* if (client.isConnected()) {
|
|
457
|
+
* client.subscribeToTickers(['AAPL']);
|
|
458
|
+
* }
|
|
459
|
+
* ```
|
|
460
|
+
*/
|
|
461
|
+
isConnected() {
|
|
462
|
+
return this.currentBroker !== null;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
exports.FloeClient = FloeClient;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event types emitted by TradierClient
|
|
3
|
+
*/
|
|
4
|
+
type TradierClientEventType = 'tickerUpdate' | 'optionUpdate' | 'connected' | 'disconnected' | 'error';
|
|
5
|
+
/**
|
|
6
|
+
* Event listener callback type
|
|
7
|
+
*/
|
|
8
|
+
type TradierEventListener<T> = (data: T) => void;
|
|
9
|
+
/**
|
|
10
|
+
* TradierClient handles real-time streaming connections to the Tradier API.
|
|
11
|
+
*
|
|
12
|
+
* @remarks
|
|
13
|
+
* This client manages WebSocket connections to Tradier's streaming API,
|
|
14
|
+
* normalizes incoming quote and trade data, and emits events for upstream
|
|
15
|
+
* consumption by the FloeClient.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const client = new TradierClient('your-api-key');
|
|
20
|
+
*
|
|
21
|
+
* client.on('tickerUpdate', (ticker) => {
|
|
22
|
+
* console.log(`${ticker.symbol}: ${ticker.spot}`);
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* await client.connect();
|
|
26
|
+
* client.subscribe(['QQQ', 'AAPL 240119C00500000']);
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare class TradierClient {
|
|
30
|
+
/** Tradier API authentication token */
|
|
31
|
+
private authKey;
|
|
32
|
+
/** Current streaming session */
|
|
33
|
+
private streamSession;
|
|
34
|
+
/** WebSocket connection */
|
|
35
|
+
private ws;
|
|
36
|
+
/** Connection state */
|
|
37
|
+
private connected;
|
|
38
|
+
/** Currently subscribed symbols (tickers and options) */
|
|
39
|
+
private subscribedSymbols;
|
|
40
|
+
/** Cached ticker data (for merging quote and trade events) */
|
|
41
|
+
private tickerCache;
|
|
42
|
+
/** Cached option data (for merging quote and trade events) */
|
|
43
|
+
private optionCache;
|
|
44
|
+
/** Event listeners */
|
|
45
|
+
private eventListeners;
|
|
46
|
+
/** Reconnection attempt counter */
|
|
47
|
+
private reconnectAttempts;
|
|
48
|
+
/** Maximum reconnection attempts */
|
|
49
|
+
private readonly maxReconnectAttempts;
|
|
50
|
+
/** Reconnection delay in ms (doubles with each attempt) */
|
|
51
|
+
private readonly baseReconnectDelay;
|
|
52
|
+
/** Tradier API base URL */
|
|
53
|
+
private readonly apiBaseUrl;
|
|
54
|
+
/** Tradier WebSocket URL */
|
|
55
|
+
private readonly wsUrl;
|
|
56
|
+
/**
|
|
57
|
+
* Creates a new TradierClient instance.
|
|
58
|
+
*
|
|
59
|
+
* @param authKey - Tradier API access token
|
|
60
|
+
*/
|
|
61
|
+
constructor(authKey: string);
|
|
62
|
+
/**
|
|
63
|
+
* Establishes a streaming connection to Tradier.
|
|
64
|
+
*
|
|
65
|
+
* @returns Promise that resolves when connected
|
|
66
|
+
* @throws {Error} If session creation or WebSocket connection fails
|
|
67
|
+
*/
|
|
68
|
+
connect(): Promise<void>;
|
|
69
|
+
/**
|
|
70
|
+
* Disconnects from the Tradier streaming API.
|
|
71
|
+
*/
|
|
72
|
+
disconnect(): void;
|
|
73
|
+
/**
|
|
74
|
+
* Subscribes to real-time updates for the specified symbols.
|
|
75
|
+
*
|
|
76
|
+
* @param symbols - Array of ticker symbols and/or OCC option symbols
|
|
77
|
+
*/
|
|
78
|
+
subscribe(symbols: string[]): void;
|
|
79
|
+
/**
|
|
80
|
+
* Unsubscribes from real-time updates for the specified symbols.
|
|
81
|
+
*
|
|
82
|
+
* @param symbols - Array of symbols to unsubscribe from
|
|
83
|
+
*
|
|
84
|
+
* @remarks
|
|
85
|
+
* Note: Tradier's streaming API doesn't support unsubscription for individual
|
|
86
|
+
* symbols. This method removes them from local tracking. To fully unsubscribe,
|
|
87
|
+
* you would need to disconnect and reconnect with the new symbol list.
|
|
88
|
+
*/
|
|
89
|
+
unsubscribe(symbols: string[]): void;
|
|
90
|
+
/**
|
|
91
|
+
* Returns whether the client is currently connected.
|
|
92
|
+
*/
|
|
93
|
+
isConnected(): boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Registers an event listener.
|
|
96
|
+
*
|
|
97
|
+
* @param event - Event type to listen for
|
|
98
|
+
* @param listener - Callback function
|
|
99
|
+
*/
|
|
100
|
+
on<T>(event: TradierClientEventType, listener: TradierEventListener<T>): this;
|
|
101
|
+
/**
|
|
102
|
+
* Removes an event listener.
|
|
103
|
+
*
|
|
104
|
+
* @param event - Event type
|
|
105
|
+
* @param listener - Callback function to remove
|
|
106
|
+
*/
|
|
107
|
+
off<T>(event: TradierClientEventType, listener: TradierEventListener<T>): this;
|
|
108
|
+
/**
|
|
109
|
+
* Creates a streaming session with Tradier API.
|
|
110
|
+
*/
|
|
111
|
+
private createStreamSession;
|
|
112
|
+
/**
|
|
113
|
+
* Connects to the Tradier WebSocket.
|
|
114
|
+
*/
|
|
115
|
+
private connectWebSocket;
|
|
116
|
+
/**
|
|
117
|
+
* Attempts to reconnect with exponential backoff.
|
|
118
|
+
*/
|
|
119
|
+
private attemptReconnect;
|
|
120
|
+
/**
|
|
121
|
+
* Handles incoming WebSocket messages.
|
|
122
|
+
*/
|
|
123
|
+
private handleMessage;
|
|
124
|
+
/**
|
|
125
|
+
* Handles quote events (bid/ask updates).
|
|
126
|
+
*/
|
|
127
|
+
private handleQuoteEvent;
|
|
128
|
+
/**
|
|
129
|
+
* Handles trade events (last price/volume updates).
|
|
130
|
+
*/
|
|
131
|
+
private handleTradeEvent;
|
|
132
|
+
/**
|
|
133
|
+
* Updates ticker data from a quote event.
|
|
134
|
+
*/
|
|
135
|
+
private updateTickerFromQuote;
|
|
136
|
+
/**
|
|
137
|
+
* Updates ticker data from a trade event.
|
|
138
|
+
*/
|
|
139
|
+
private updateTickerFromTrade;
|
|
140
|
+
/**
|
|
141
|
+
* Updates option data from a quote event.
|
|
142
|
+
*/
|
|
143
|
+
private updateOptionFromQuote;
|
|
144
|
+
/**
|
|
145
|
+
* Updates option data from a trade event.
|
|
146
|
+
*/
|
|
147
|
+
private updateOptionFromTrade;
|
|
148
|
+
/**
|
|
149
|
+
* Checks if a symbol is an OCC option symbol.
|
|
150
|
+
*/
|
|
151
|
+
private isOptionSymbol;
|
|
152
|
+
/**
|
|
153
|
+
* Emits an event to all registered listeners.
|
|
154
|
+
*/
|
|
155
|
+
private emit;
|
|
156
|
+
/**
|
|
157
|
+
* Simple sleep utility.
|
|
158
|
+
*/
|
|
159
|
+
private sleep;
|
|
160
|
+
}
|
|
161
|
+
export {};
|