@fullstackcraftllc/floe 0.0.4 → 0.0.5
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 +5 -4
- package/dist/client/FloeClient.d.ts +23 -2
- package/dist/client/FloeClient.js +114 -2
- package/dist/client/brokers/SchwabClient.d.ts +448 -0
- package/dist/client/brokers/SchwabClient.js +1052 -0
- package/dist/client/brokers/TastyTradeClient.d.ts +4 -0
- package/dist/client/brokers/TastyTradeClient.js +19 -0
- package/dist/client/brokers/TradeStationClient.d.ts +361 -0
- package/dist/client/brokers/TradeStationClient.js +880 -0
- package/dist/client/brokers/TradierClient.d.ts +7 -1
- package/dist/client/brokers/TradierClient.js +18 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -1
- package/package.json +2 -2
|
@@ -1,2 +1,450 @@
|
|
|
1
|
+
import { NormalizedOption } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Schwab option chain response
|
|
4
|
+
*/
|
|
5
|
+
interface SchwabOptionChainResponse {
|
|
6
|
+
symbol: string;
|
|
7
|
+
status: string;
|
|
8
|
+
underlying: {
|
|
9
|
+
symbol: string;
|
|
10
|
+
description: string;
|
|
11
|
+
change: number;
|
|
12
|
+
percentChange: number;
|
|
13
|
+
close: number;
|
|
14
|
+
quoteTime: number;
|
|
15
|
+
tradeTime: number;
|
|
16
|
+
bid: number;
|
|
17
|
+
ask: number;
|
|
18
|
+
last: number;
|
|
19
|
+
mark: number;
|
|
20
|
+
markChange: number;
|
|
21
|
+
markPercentChange: number;
|
|
22
|
+
bidSize: number;
|
|
23
|
+
askSize: number;
|
|
24
|
+
highPrice: number;
|
|
25
|
+
lowPrice: number;
|
|
26
|
+
openPrice: number;
|
|
27
|
+
totalVolume: number;
|
|
28
|
+
exchangeName: string;
|
|
29
|
+
fiftyTwoWeekHigh: number;
|
|
30
|
+
fiftyTwoWeekLow: number;
|
|
31
|
+
delayed: boolean;
|
|
32
|
+
};
|
|
33
|
+
strategy: string;
|
|
34
|
+
interval: number;
|
|
35
|
+
isDelayed: boolean;
|
|
36
|
+
isIndex: boolean;
|
|
37
|
+
interestRate: number;
|
|
38
|
+
underlyingPrice: number;
|
|
39
|
+
volatility: number;
|
|
40
|
+
daysToExpiration: number;
|
|
41
|
+
numberOfContracts: number;
|
|
42
|
+
assetMainType: string;
|
|
43
|
+
assetSubType: string;
|
|
44
|
+
isChainTruncated: boolean;
|
|
45
|
+
callExpDateMap: Record<string, Record<string, SchwabOptionContract[]>>;
|
|
46
|
+
putExpDateMap: Record<string, Record<string, SchwabOptionContract[]>>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Schwab option contract from chain
|
|
50
|
+
*/
|
|
51
|
+
interface SchwabOptionContract {
|
|
52
|
+
putCall: 'CALL' | 'PUT';
|
|
53
|
+
symbol: string;
|
|
54
|
+
description: string;
|
|
55
|
+
exchangeName: string;
|
|
56
|
+
bid: number;
|
|
57
|
+
ask: number;
|
|
58
|
+
last: number;
|
|
59
|
+
mark: number;
|
|
60
|
+
bidSize: number;
|
|
61
|
+
askSize: number;
|
|
62
|
+
bidAskSize: string;
|
|
63
|
+
lastSize: number;
|
|
64
|
+
highPrice: number;
|
|
65
|
+
lowPrice: number;
|
|
66
|
+
openPrice: number;
|
|
67
|
+
closePrice: number;
|
|
68
|
+
totalVolume: number;
|
|
69
|
+
tradeDate: number | null;
|
|
70
|
+
tradeTimeInLong: number;
|
|
71
|
+
quoteTimeInLong: number;
|
|
72
|
+
netChange: number;
|
|
73
|
+
volatility: number;
|
|
74
|
+
delta: number;
|
|
75
|
+
gamma: number;
|
|
76
|
+
theta: number;
|
|
77
|
+
vega: number;
|
|
78
|
+
rho: number;
|
|
79
|
+
openInterest: number;
|
|
80
|
+
timeValue: number;
|
|
81
|
+
theoreticalOptionValue: number;
|
|
82
|
+
theoreticalVolatility: number;
|
|
83
|
+
optionDeliverablesList: unknown;
|
|
84
|
+
strikePrice: number;
|
|
85
|
+
expirationDate: string;
|
|
86
|
+
daysToExpiration: number;
|
|
87
|
+
expirationType: string;
|
|
88
|
+
lastTradingDay: number;
|
|
89
|
+
multiplier: number;
|
|
90
|
+
settlementType: string;
|
|
91
|
+
deliverableNote: string;
|
|
92
|
+
percentChange: number;
|
|
93
|
+
markChange: number;
|
|
94
|
+
markPercentChange: number;
|
|
95
|
+
intrinsicValue: number;
|
|
96
|
+
extrinsicValue: number;
|
|
97
|
+
optionRoot: string;
|
|
98
|
+
exerciseType: string;
|
|
99
|
+
high52Week: number;
|
|
100
|
+
low52Week: number;
|
|
101
|
+
nonStandard: boolean;
|
|
102
|
+
pennyPilot: boolean;
|
|
103
|
+
inTheMoney: boolean;
|
|
104
|
+
mini: boolean;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Aggressor side of a trade
|
|
108
|
+
*/
|
|
109
|
+
export type AggressorSide = 'buy' | 'sell' | 'unknown';
|
|
110
|
+
/**
|
|
111
|
+
* Intraday trade information with aggressor classification
|
|
112
|
+
*/
|
|
113
|
+
export interface IntradayTrade {
|
|
114
|
+
/** OCC option symbol */
|
|
115
|
+
occSymbol: string;
|
|
116
|
+
/** Trade price */
|
|
117
|
+
price: number;
|
|
118
|
+
/** Trade size (number of contracts) */
|
|
119
|
+
size: number;
|
|
120
|
+
/** Bid at time of trade */
|
|
121
|
+
bid: number;
|
|
122
|
+
/** Ask at time of trade */
|
|
123
|
+
ask: number;
|
|
124
|
+
/** Aggressor side determined from price vs NBBO */
|
|
125
|
+
aggressorSide: AggressorSide;
|
|
126
|
+
/** Timestamp of the trade */
|
|
127
|
+
timestamp: number;
|
|
128
|
+
/** Estimated OI change */
|
|
129
|
+
estimatedOIChange: number;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Event types emitted by SchwabClient
|
|
133
|
+
*/
|
|
134
|
+
type SchwabClientEventType = 'tickerUpdate' | 'optionUpdate' | 'optionTrade' | 'connected' | 'disconnected' | 'error';
|
|
135
|
+
/**
|
|
136
|
+
* Event listener callback type
|
|
137
|
+
*/
|
|
138
|
+
type SchwabEventListener<T> = (data: T) => void;
|
|
139
|
+
/**
|
|
140
|
+
* SchwabClient handles real-time streaming connections to the Charles Schwab API
|
|
141
|
+
* via WebSockets.
|
|
142
|
+
*
|
|
143
|
+
* @remarks
|
|
144
|
+
* This client manages WebSocket connections to Schwab's streaming API,
|
|
145
|
+
* normalizes incoming quote and book data, and emits events for upstream
|
|
146
|
+
* consumption by the FloeClient.
|
|
147
|
+
*
|
|
148
|
+
* Authentication flow:
|
|
149
|
+
* 1. Use OAuth access token to call get_user_preferences endpoint
|
|
150
|
+
* 2. Extract streaming credentials (customerId, correlId, channel, functionId, socketUrl)
|
|
151
|
+
* 3. Connect to WebSocket and send ADMIN/LOGIN request with access token
|
|
152
|
+
* 4. Subscribe to LEVELONE_OPTIONS for quotes and OPTIONS_BOOK for order book
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* const client = new SchwabClient({
|
|
157
|
+
* accessToken: 'your-oauth-access-token'
|
|
158
|
+
* });
|
|
159
|
+
*
|
|
160
|
+
* client.on('tickerUpdate', (ticker) => {
|
|
161
|
+
* console.log(`${ticker.symbol}: ${ticker.spot}`);
|
|
162
|
+
* });
|
|
163
|
+
*
|
|
164
|
+
* await client.connect();
|
|
165
|
+
* client.subscribe(['SPY', 'SPY 240517C00500000']); // Equity and option
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
1
168
|
export declare class SchwabClient {
|
|
169
|
+
/** Schwab OAuth access token */
|
|
170
|
+
private accessToken;
|
|
171
|
+
/** WebSocket connection */
|
|
172
|
+
private ws;
|
|
173
|
+
/** Connection state */
|
|
174
|
+
private connected;
|
|
175
|
+
/** Logged in state */
|
|
176
|
+
private loggedIn;
|
|
177
|
+
/** Streaming credentials */
|
|
178
|
+
private streamCustomerId;
|
|
179
|
+
private streamCorrelId;
|
|
180
|
+
private streamChannel;
|
|
181
|
+
private streamFunctionId;
|
|
182
|
+
private streamSocketUrl;
|
|
183
|
+
/** Request ID counter */
|
|
184
|
+
private requestId;
|
|
185
|
+
/** Currently subscribed symbols */
|
|
186
|
+
private subscribedSymbols;
|
|
187
|
+
/** Map from Schwab symbol to OCC symbol */
|
|
188
|
+
private schwabToOccMap;
|
|
189
|
+
/** Map from OCC symbol to Schwab symbol */
|
|
190
|
+
private occToSchwabMap;
|
|
191
|
+
/** Cached ticker data */
|
|
192
|
+
private tickerCache;
|
|
193
|
+
/** Cached option data */
|
|
194
|
+
private optionCache;
|
|
195
|
+
/** Base open interest from REST API */
|
|
196
|
+
private baseOpenInterest;
|
|
197
|
+
/** Cumulative estimated OI change from intraday trades */
|
|
198
|
+
private cumulativeOIChange;
|
|
199
|
+
/** History of intraday trades */
|
|
200
|
+
private intradayTrades;
|
|
201
|
+
/** Event listeners */
|
|
202
|
+
private eventListeners;
|
|
203
|
+
/** Reconnection attempt counter */
|
|
204
|
+
private reconnectAttempts;
|
|
205
|
+
/** Maximum reconnection attempts */
|
|
206
|
+
private readonly maxReconnectAttempts;
|
|
207
|
+
/** Reconnection delay in ms */
|
|
208
|
+
private readonly baseReconnectDelay;
|
|
209
|
+
/** Keepalive interval handle */
|
|
210
|
+
private keepaliveInterval;
|
|
211
|
+
/** Schwab API base URL */
|
|
212
|
+
private readonly apiBaseUrl;
|
|
213
|
+
/** Whether to log verbose debug information */
|
|
214
|
+
private readonly verbose;
|
|
215
|
+
/**
|
|
216
|
+
* Creates a new SchwabClient instance.
|
|
217
|
+
*
|
|
218
|
+
* @param options - Client configuration options
|
|
219
|
+
* @param options.accessToken - Schwab OAuth access token (required)
|
|
220
|
+
* @param options.verbose - Whether to log verbose debug information (default: false)
|
|
221
|
+
*/
|
|
222
|
+
constructor(options: {
|
|
223
|
+
accessToken: string;
|
|
224
|
+
verbose?: boolean;
|
|
225
|
+
});
|
|
226
|
+
/**
|
|
227
|
+
* Establishes a streaming connection to Schwab.
|
|
228
|
+
*
|
|
229
|
+
* @returns Promise that resolves when connected and logged in
|
|
230
|
+
* @throws {Error} If credentials retrieval or WebSocket connection fails
|
|
231
|
+
*/
|
|
232
|
+
connect(): Promise<void>;
|
|
233
|
+
/**
|
|
234
|
+
* Disconnects from the Schwab streaming API.
|
|
235
|
+
*/
|
|
236
|
+
disconnect(): void;
|
|
237
|
+
/**
|
|
238
|
+
* Subscribes to real-time updates for the specified symbols.
|
|
239
|
+
*
|
|
240
|
+
* @param symbols - Array of ticker symbols and/or OCC option symbols
|
|
241
|
+
*
|
|
242
|
+
* @remarks
|
|
243
|
+
* For options, you can pass OCC format symbols (e.g., 'SPY240119C00500000')
|
|
244
|
+
* or Schwab format with spaces (e.g., 'SPY 240119C00500000').
|
|
245
|
+
* The client will handle conversion automatically.
|
|
246
|
+
*/
|
|
247
|
+
subscribe(symbols: string[]): void;
|
|
248
|
+
/**
|
|
249
|
+
* Unsubscribes from real-time updates for the specified symbols.
|
|
250
|
+
*
|
|
251
|
+
* @param symbols - Array of symbols to unsubscribe from
|
|
252
|
+
*/
|
|
253
|
+
unsubscribe(symbols: string[]): void;
|
|
254
|
+
/**
|
|
255
|
+
* Returns whether the client is currently connected.
|
|
256
|
+
*/
|
|
257
|
+
isConnected(): boolean;
|
|
258
|
+
/**
|
|
259
|
+
* Fetches option chain from Schwab REST API.
|
|
260
|
+
* This provides the base open interest data.
|
|
261
|
+
*
|
|
262
|
+
* @param symbol - Underlying symbol (e.g., 'SPY')
|
|
263
|
+
* @param options - Optional parameters for filtering the chain
|
|
264
|
+
* @returns Promise resolving to the option chain response
|
|
265
|
+
*/
|
|
266
|
+
fetchOptionChain(symbol: string, options?: {
|
|
267
|
+
contractType?: 'CALL' | 'PUT' | 'ALL';
|
|
268
|
+
strikeCount?: number;
|
|
269
|
+
includeUnderlyingQuote?: boolean;
|
|
270
|
+
fromDate?: string;
|
|
271
|
+
toDate?: string;
|
|
272
|
+
}): Promise<SchwabOptionChainResponse | null>;
|
|
273
|
+
/**
|
|
274
|
+
* Fetches open interest and other static data for subscribed options.
|
|
275
|
+
*
|
|
276
|
+
* @param occSymbols - Array of OCC option symbols to fetch data for
|
|
277
|
+
*/
|
|
278
|
+
fetchOpenInterest(occSymbols: string[]): Promise<void>;
|
|
279
|
+
/**
|
|
280
|
+
* Returns cached option data for a symbol.
|
|
281
|
+
*/
|
|
282
|
+
getOption(occSymbol: string): NormalizedOption | undefined;
|
|
283
|
+
/**
|
|
284
|
+
* Returns all cached options.
|
|
285
|
+
*/
|
|
286
|
+
getAllOptions(): Map<string, NormalizedOption>;
|
|
287
|
+
/**
|
|
288
|
+
* Registers an event listener.
|
|
289
|
+
*/
|
|
290
|
+
on<T>(event: SchwabClientEventType, listener: SchwabEventListener<T>): this;
|
|
291
|
+
/**
|
|
292
|
+
* Removes an event listener.
|
|
293
|
+
*/
|
|
294
|
+
off<T>(event: SchwabClientEventType, listener: SchwabEventListener<T>): this;
|
|
295
|
+
/**
|
|
296
|
+
* Returns intraday trades for an option.
|
|
297
|
+
*/
|
|
298
|
+
getIntradayTrades(occSymbol: string): IntradayTrade[];
|
|
299
|
+
/**
|
|
300
|
+
* Returns flow summary for an option.
|
|
301
|
+
*/
|
|
302
|
+
getFlowSummary(occSymbol: string): {
|
|
303
|
+
buyVolume: number;
|
|
304
|
+
sellVolume: number;
|
|
305
|
+
unknownVolume: number;
|
|
306
|
+
netOIChange: number;
|
|
307
|
+
tradeCount: number;
|
|
308
|
+
};
|
|
309
|
+
/**
|
|
310
|
+
* Resets intraday tracking data.
|
|
311
|
+
*/
|
|
312
|
+
resetIntradayData(occSymbols?: string[]): void;
|
|
313
|
+
/**
|
|
314
|
+
* Gets user preferences containing streaming info from Schwab.
|
|
315
|
+
*/
|
|
316
|
+
private getUserPreferences;
|
|
317
|
+
/**
|
|
318
|
+
* Returns authorization headers for API calls.
|
|
319
|
+
*/
|
|
320
|
+
private getAuthHeaders;
|
|
321
|
+
/**
|
|
322
|
+
* Connects to Schwab WebSocket.
|
|
323
|
+
*/
|
|
324
|
+
private connectWebSocket;
|
|
325
|
+
/**
|
|
326
|
+
* Sends login request to Schwab streaming.
|
|
327
|
+
*/
|
|
328
|
+
private sendLogin;
|
|
329
|
+
/**
|
|
330
|
+
* Sends logout request to Schwab streaming.
|
|
331
|
+
*/
|
|
332
|
+
private sendLogout;
|
|
333
|
+
/**
|
|
334
|
+
* Subscribes to LEVELONE_EQUITIES service.
|
|
335
|
+
*/
|
|
336
|
+
private subscribeLevelOneEquity;
|
|
337
|
+
/**
|
|
338
|
+
* Unsubscribes from LEVELONE_EQUITIES service.
|
|
339
|
+
*/
|
|
340
|
+
private unsubscribeLevelOneEquity;
|
|
341
|
+
/**
|
|
342
|
+
* Subscribes to LEVELONE_OPTIONS service for level 1 option quotes.
|
|
343
|
+
*/
|
|
344
|
+
private subscribeLevelOneOptions;
|
|
345
|
+
/**
|
|
346
|
+
* Unsubscribes from LEVELONE_OPTIONS service.
|
|
347
|
+
*/
|
|
348
|
+
private unsubscribeLevelOneOptions;
|
|
349
|
+
/**
|
|
350
|
+
* Subscribes to OPTIONS_BOOK service for level 2 order book.
|
|
351
|
+
* This provides "live" open interest intraday.
|
|
352
|
+
*/
|
|
353
|
+
private subscribeOptionsBook;
|
|
354
|
+
/**
|
|
355
|
+
* Unsubscribes from OPTIONS_BOOK service.
|
|
356
|
+
*/
|
|
357
|
+
private unsubscribeOptionsBook;
|
|
358
|
+
/**
|
|
359
|
+
* Makes a streaming request object.
|
|
360
|
+
*/
|
|
361
|
+
private makeRequest;
|
|
362
|
+
/**
|
|
363
|
+
* Handles incoming WebSocket messages.
|
|
364
|
+
*/
|
|
365
|
+
private handleMessage;
|
|
366
|
+
/**
|
|
367
|
+
* Handles a response message (command acknowledgment).
|
|
368
|
+
*/
|
|
369
|
+
private handleResponse;
|
|
370
|
+
/**
|
|
371
|
+
* Handles streaming data messages.
|
|
372
|
+
*/
|
|
373
|
+
private handleDataMessage;
|
|
374
|
+
/**
|
|
375
|
+
* Handles LEVELONE_EQUITIES data.
|
|
376
|
+
*/
|
|
377
|
+
private handleLevelOneEquity;
|
|
378
|
+
/**
|
|
379
|
+
* Handles LEVELONE_OPTIONS data.
|
|
380
|
+
*/
|
|
381
|
+
private handleLevelOneOption;
|
|
382
|
+
/**
|
|
383
|
+
* Handles OPTIONS_BOOK data (level 2 order book).
|
|
384
|
+
* This provides depth of market which can indicate intraday activity.
|
|
385
|
+
*/
|
|
386
|
+
private handleOptionsBook;
|
|
387
|
+
/**
|
|
388
|
+
* Records a trade and updates OI tracking.
|
|
389
|
+
*/
|
|
390
|
+
private recordTrade;
|
|
391
|
+
/**
|
|
392
|
+
* Processes a contract from the option chain response.
|
|
393
|
+
*/
|
|
394
|
+
private processChainContract;
|
|
395
|
+
/**
|
|
396
|
+
* Starts keepalive interval.
|
|
397
|
+
*/
|
|
398
|
+
private startKeepalive;
|
|
399
|
+
/**
|
|
400
|
+
* Determines aggressor side from trade price vs NBBO.
|
|
401
|
+
*/
|
|
402
|
+
private determineAggressorSide;
|
|
403
|
+
/**
|
|
404
|
+
* Calculates estimated OI change from trade.
|
|
405
|
+
*/
|
|
406
|
+
private calculateOIChangeFromTrade;
|
|
407
|
+
/**
|
|
408
|
+
* Calculates live open interest.
|
|
409
|
+
*/
|
|
410
|
+
private calculateLiveOpenInterest;
|
|
411
|
+
/**
|
|
412
|
+
* Converts Schwab option symbol to OCC format.
|
|
413
|
+
* Schwab format: "AAPL 240517C00170000" (6-char padded underlying)
|
|
414
|
+
*/
|
|
415
|
+
private schwabToOcc;
|
|
416
|
+
/**
|
|
417
|
+
* Normalizes an OCC symbol to consistent format.
|
|
418
|
+
* Removes extra spaces, ensures proper formatting.
|
|
419
|
+
*/
|
|
420
|
+
private normalizeOccSymbol;
|
|
421
|
+
/**
|
|
422
|
+
* Converts OCC symbol to Schwab format (space-padded).
|
|
423
|
+
*/
|
|
424
|
+
private toSchwabOptionSymbol;
|
|
425
|
+
/**
|
|
426
|
+
* Checks if symbol is an option symbol.
|
|
427
|
+
*/
|
|
428
|
+
private isOptionSymbol;
|
|
429
|
+
/**
|
|
430
|
+
* Attempts to reconnect with exponential backoff.
|
|
431
|
+
*/
|
|
432
|
+
private attemptReconnect;
|
|
433
|
+
/**
|
|
434
|
+
* Sends a message to the WebSocket.
|
|
435
|
+
*/
|
|
436
|
+
private sendMessage;
|
|
437
|
+
/**
|
|
438
|
+
* Emits an event to all listeners.
|
|
439
|
+
*/
|
|
440
|
+
private emit;
|
|
441
|
+
/**
|
|
442
|
+
* Converts value to number, handling NaN and null.
|
|
443
|
+
*/
|
|
444
|
+
private toNumber;
|
|
445
|
+
/**
|
|
446
|
+
* Sleep utility.
|
|
447
|
+
*/
|
|
448
|
+
private sleep;
|
|
2
449
|
}
|
|
450
|
+
export {};
|