@fullstackcraftllc/floe 0.0.1 → 0.0.3
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 +10 -210
- package/dist/adapters/index.js +64 -16
- package/dist/client/FloeClient.d.ts +411 -0
- package/dist/client/FloeClient.js +550 -0
- package/dist/client/brokers/SchwabClient.d.ts +2 -0
- package/dist/client/brokers/SchwabClient.js +6 -0
- package/dist/client/brokers/TradierClient.d.ts +393 -0
- package/dist/client/brokers/TradierClient.js +869 -0
- package/dist/index.d.ts +5 -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 +203 -0
- package/package.json +3 -3
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
import { NormalizedOption } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Aggressor side of a trade - determined by comparing trade price to NBBO
|
|
4
|
+
*/
|
|
5
|
+
export type AggressorSide = 'buy' | 'sell' | 'unknown';
|
|
6
|
+
/**
|
|
7
|
+
* Intraday trade information with aggressor classification
|
|
8
|
+
*/
|
|
9
|
+
export interface IntradayTrade {
|
|
10
|
+
/** OCC option symbol */
|
|
11
|
+
occSymbol: string;
|
|
12
|
+
/** Trade price */
|
|
13
|
+
price: number;
|
|
14
|
+
/** Trade size (number of contracts) */
|
|
15
|
+
size: number;
|
|
16
|
+
/** Bid at time of trade */
|
|
17
|
+
bid: number;
|
|
18
|
+
/** Ask at time of trade */
|
|
19
|
+
ask: number;
|
|
20
|
+
/** Aggressor side determined from price vs NBBO */
|
|
21
|
+
aggressorSide: AggressorSide;
|
|
22
|
+
/** Timestamp of the trade */
|
|
23
|
+
timestamp: number;
|
|
24
|
+
/** Estimated OI change: +size for buy aggressor (new longs), -size for sell aggressor (closing longs/new shorts) */
|
|
25
|
+
estimatedOIChange: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Tradier option chain item from REST API
|
|
29
|
+
* GET /v1/markets/options/chains
|
|
30
|
+
*/
|
|
31
|
+
interface TradierOptionChainItem {
|
|
32
|
+
symbol: string;
|
|
33
|
+
description: string;
|
|
34
|
+
exch: string;
|
|
35
|
+
type: string;
|
|
36
|
+
last: number | null;
|
|
37
|
+
change: number | null;
|
|
38
|
+
volume: number;
|
|
39
|
+
open: number | null;
|
|
40
|
+
high: number | null;
|
|
41
|
+
low: number | null;
|
|
42
|
+
close: number | null;
|
|
43
|
+
bid: number;
|
|
44
|
+
ask: number;
|
|
45
|
+
underlying: string;
|
|
46
|
+
strike: number;
|
|
47
|
+
change_percentage: number | null;
|
|
48
|
+
average_volume: number;
|
|
49
|
+
last_volume: number;
|
|
50
|
+
trade_date: number;
|
|
51
|
+
prevclose: number | null;
|
|
52
|
+
week_52_high: number;
|
|
53
|
+
week_52_low: number;
|
|
54
|
+
bidsize: number;
|
|
55
|
+
bidexch: string;
|
|
56
|
+
bid_date: number;
|
|
57
|
+
asksize: number;
|
|
58
|
+
askexch: string;
|
|
59
|
+
ask_date: number;
|
|
60
|
+
open_interest: number;
|
|
61
|
+
contract_size: number;
|
|
62
|
+
expiration_date: string;
|
|
63
|
+
expiration_type: string;
|
|
64
|
+
option_type: 'call' | 'put';
|
|
65
|
+
root_symbol: string;
|
|
66
|
+
greeks?: {
|
|
67
|
+
delta: number;
|
|
68
|
+
gamma: number;
|
|
69
|
+
theta: number;
|
|
70
|
+
vega: number;
|
|
71
|
+
rho: number;
|
|
72
|
+
phi: number;
|
|
73
|
+
bid_iv: number;
|
|
74
|
+
mid_iv: number;
|
|
75
|
+
ask_iv: number;
|
|
76
|
+
smv_vol: number;
|
|
77
|
+
updated_at: string;
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Event types emitted by TradierClient
|
|
82
|
+
*/
|
|
83
|
+
type TradierClientEventType = 'tickerUpdate' | 'optionUpdate' | 'optionTrade' | 'connected' | 'disconnected' | 'error';
|
|
84
|
+
/**
|
|
85
|
+
* Event listener callback type
|
|
86
|
+
*/
|
|
87
|
+
type TradierEventListener<T> = (data: T) => void;
|
|
88
|
+
/**
|
|
89
|
+
* TradierClient handles real-time streaming connections to the Tradier API.
|
|
90
|
+
*
|
|
91
|
+
* @remarks
|
|
92
|
+
* This client manages WebSocket connections to Tradier's streaming API,
|
|
93
|
+
* normalizes incoming quote and trade data, and emits events for upstream
|
|
94
|
+
* consumption by the FloeClient.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```typescript
|
|
98
|
+
* const client = new TradierClient('your-api-key');
|
|
99
|
+
*
|
|
100
|
+
* client.on('tickerUpdate', (ticker) => {
|
|
101
|
+
* console.log(`${ticker.symbol}: ${ticker.spot}`);
|
|
102
|
+
* });
|
|
103
|
+
*
|
|
104
|
+
* await client.connect();
|
|
105
|
+
* client.subscribe(['QQQ', 'AAPL 240119C00500000']);
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
export declare class TradierClient {
|
|
109
|
+
/** Tradier API authentication token */
|
|
110
|
+
private authKey;
|
|
111
|
+
/** Current streaming session */
|
|
112
|
+
private streamSession;
|
|
113
|
+
/** WebSocket connection */
|
|
114
|
+
private ws;
|
|
115
|
+
/** Connection state */
|
|
116
|
+
private connected;
|
|
117
|
+
/** Currently subscribed symbols (tickers and options) */
|
|
118
|
+
private subscribedSymbols;
|
|
119
|
+
/** Cached ticker data (for merging quote and trade events) */
|
|
120
|
+
private tickerCache;
|
|
121
|
+
/** Cached option data (for merging quote and trade events) */
|
|
122
|
+
private optionCache;
|
|
123
|
+
/**
|
|
124
|
+
* Base open interest from REST API - used as t=0 reference for live OI calculation
|
|
125
|
+
* Key: OCC symbol, Value: open interest at start of day / time of fetch
|
|
126
|
+
*/
|
|
127
|
+
private baseOpenInterest;
|
|
128
|
+
/**
|
|
129
|
+
* Cumulative estimated OI change from intraday trades
|
|
130
|
+
* Key: OCC symbol, Value: net estimated change (positive = more contracts opened)
|
|
131
|
+
*/
|
|
132
|
+
private cumulativeOIChange;
|
|
133
|
+
/**
|
|
134
|
+
* History of intraday trades with aggressor classification
|
|
135
|
+
* Key: OCC symbol, Value: array of trades
|
|
136
|
+
*/
|
|
137
|
+
private intradayTrades;
|
|
138
|
+
/** Event listeners */
|
|
139
|
+
private eventListeners;
|
|
140
|
+
/** Reconnection attempt counter */
|
|
141
|
+
private reconnectAttempts;
|
|
142
|
+
/** Maximum reconnection attempts */
|
|
143
|
+
private readonly maxReconnectAttempts;
|
|
144
|
+
/** Reconnection delay in ms (doubles with each attempt) */
|
|
145
|
+
private readonly baseReconnectDelay;
|
|
146
|
+
/** Tradier API base URL */
|
|
147
|
+
private readonly apiBaseUrl;
|
|
148
|
+
/** Tradier WebSocket URL */
|
|
149
|
+
private readonly wsUrl;
|
|
150
|
+
/**
|
|
151
|
+
* Creates a new TradierClient instance.
|
|
152
|
+
*
|
|
153
|
+
* @param authKey - Tradier API access token
|
|
154
|
+
*/
|
|
155
|
+
constructor(authKey: string);
|
|
156
|
+
/**
|
|
157
|
+
* Establishes a streaming connection to Tradier.
|
|
158
|
+
*
|
|
159
|
+
* @returns Promise that resolves when connected
|
|
160
|
+
* @throws {Error} If session creation or WebSocket connection fails
|
|
161
|
+
*/
|
|
162
|
+
connect(): Promise<void>;
|
|
163
|
+
/**
|
|
164
|
+
* Disconnects from the Tradier streaming API.
|
|
165
|
+
*/
|
|
166
|
+
disconnect(): void;
|
|
167
|
+
/**
|
|
168
|
+
* Subscribes to real-time updates for the specified symbols.
|
|
169
|
+
*
|
|
170
|
+
* @param symbols - Array of ticker symbols and/or OCC option symbols
|
|
171
|
+
*/
|
|
172
|
+
subscribe(symbols: string[]): void;
|
|
173
|
+
/**
|
|
174
|
+
* Unsubscribes from real-time updates for the specified symbols.
|
|
175
|
+
*
|
|
176
|
+
* @param symbols - Array of symbols to unsubscribe from
|
|
177
|
+
*
|
|
178
|
+
* @remarks
|
|
179
|
+
* Note: Tradier's streaming API doesn't support unsubscription for individual
|
|
180
|
+
* symbols. This method removes them from local tracking. To fully unsubscribe,
|
|
181
|
+
* you would need to disconnect and reconnect with the new symbol list.
|
|
182
|
+
*/
|
|
183
|
+
unsubscribe(symbols: string[]): void;
|
|
184
|
+
/**
|
|
185
|
+
* Returns whether the client is currently connected.
|
|
186
|
+
*/
|
|
187
|
+
isConnected(): boolean;
|
|
188
|
+
/**
|
|
189
|
+
* Fetches options chain data from Tradier REST API.
|
|
190
|
+
*
|
|
191
|
+
* @param symbol - Underlying symbol (e.g., 'QQQ')
|
|
192
|
+
* @param expiration - Expiration date in YYYY-MM-DD format
|
|
193
|
+
* @param greeks - Whether to include Greeks data (default: true)
|
|
194
|
+
* @returns Array of option chain items, or empty array on failure
|
|
195
|
+
*/
|
|
196
|
+
fetchOptionsChain(symbol: string, expiration: string, greeks?: boolean): Promise<TradierOptionChainItem[]>;
|
|
197
|
+
/**
|
|
198
|
+
* Fetches open interest and other static data for subscribed options via REST API.
|
|
199
|
+
* Call this after subscribing to options to populate open interest.
|
|
200
|
+
*
|
|
201
|
+
* @param occSymbols - Array of OCC option symbols to fetch data for
|
|
202
|
+
* @returns Promise that resolves when all data is fetched
|
|
203
|
+
*
|
|
204
|
+
* @remarks
|
|
205
|
+
* Open interest is only available via the REST API, not streaming.
|
|
206
|
+
* This method groups options by underlying and expiration to minimize API calls.
|
|
207
|
+
*/
|
|
208
|
+
fetchOpenInterest(occSymbols: string[]): Promise<void>;
|
|
209
|
+
/**
|
|
210
|
+
* Returns the cached option data for a symbol.
|
|
211
|
+
*
|
|
212
|
+
* @param occSymbol - OCC option symbol
|
|
213
|
+
* @returns Cached option data or undefined
|
|
214
|
+
*/
|
|
215
|
+
getOption(occSymbol: string): NormalizedOption | undefined;
|
|
216
|
+
/**
|
|
217
|
+
* Returns all cached options.
|
|
218
|
+
*
|
|
219
|
+
* @returns Map of OCC symbols to option data
|
|
220
|
+
*/
|
|
221
|
+
getAllOptions(): Map<string, NormalizedOption>;
|
|
222
|
+
/**
|
|
223
|
+
* Registers an event listener.
|
|
224
|
+
*
|
|
225
|
+
* @param event - Event type to listen for
|
|
226
|
+
* @param listener - Callback function
|
|
227
|
+
*/
|
|
228
|
+
on<T>(event: TradierClientEventType, listener: TradierEventListener<T>): this;
|
|
229
|
+
/**
|
|
230
|
+
* Removes an event listener.
|
|
231
|
+
*
|
|
232
|
+
* @param event - Event type
|
|
233
|
+
* @param listener - Callback function to remove
|
|
234
|
+
*/
|
|
235
|
+
off<T>(event: TradierClientEventType, listener: TradierEventListener<T>): this;
|
|
236
|
+
/**
|
|
237
|
+
* Creates a streaming session with Tradier API.
|
|
238
|
+
*/
|
|
239
|
+
private createStreamSession;
|
|
240
|
+
/**
|
|
241
|
+
* Connects to the Tradier WebSocket.
|
|
242
|
+
*/
|
|
243
|
+
private connectWebSocket;
|
|
244
|
+
/**
|
|
245
|
+
* Attempts to reconnect with exponential backoff.
|
|
246
|
+
*/
|
|
247
|
+
private attemptReconnect;
|
|
248
|
+
/**
|
|
249
|
+
* Handles incoming WebSocket messages.
|
|
250
|
+
*/
|
|
251
|
+
private handleMessage;
|
|
252
|
+
/**
|
|
253
|
+
* Handles quote events (bid/ask updates).
|
|
254
|
+
*/
|
|
255
|
+
private handleQuoteEvent;
|
|
256
|
+
/**
|
|
257
|
+
* Handles trade events (last price/volume updates).
|
|
258
|
+
*/
|
|
259
|
+
private handleTradeEvent;
|
|
260
|
+
/**
|
|
261
|
+
* Handles timesale events (trade with bid/ask at time of sale).
|
|
262
|
+
* This is particularly useful for options where quote events may be sparse.
|
|
263
|
+
*/
|
|
264
|
+
private handleTimesaleEvent;
|
|
265
|
+
/**
|
|
266
|
+
* Updates ticker data from a quote event.
|
|
267
|
+
*/
|
|
268
|
+
private updateTickerFromQuote;
|
|
269
|
+
/**
|
|
270
|
+
* Updates ticker data from a trade event.
|
|
271
|
+
*/
|
|
272
|
+
private updateTickerFromTrade;
|
|
273
|
+
/**
|
|
274
|
+
* Updates option data from a quote event.
|
|
275
|
+
*/
|
|
276
|
+
private updateOptionFromQuote;
|
|
277
|
+
/**
|
|
278
|
+
* Updates option data from a trade event.
|
|
279
|
+
*/
|
|
280
|
+
private updateOptionFromTrade;
|
|
281
|
+
/**
|
|
282
|
+
* Updates ticker data from a timesale event.
|
|
283
|
+
* Timesale events include bid/ask at the time of the trade.
|
|
284
|
+
*/
|
|
285
|
+
private updateTickerFromTimesale;
|
|
286
|
+
/**
|
|
287
|
+
* Updates option data from a timesale event.
|
|
288
|
+
* Timesale events include bid/ask at the time of the trade, enabling aggressor side detection.
|
|
289
|
+
*
|
|
290
|
+
* This is the primary method for calculating live open interest:
|
|
291
|
+
* - Aggressor side is determined by comparing trade price to NBBO
|
|
292
|
+
* - Buy aggressor (lifting ask) typically indicates new long positions → OI increases
|
|
293
|
+
* - Sell aggressor (hitting bid) typically indicates closing longs or new shorts → OI decreases
|
|
294
|
+
*/
|
|
295
|
+
private updateOptionFromTimesale;
|
|
296
|
+
/**
|
|
297
|
+
* Determines the aggressor side of a trade by comparing trade price to NBBO.
|
|
298
|
+
*
|
|
299
|
+
* @param tradePrice - The executed trade price
|
|
300
|
+
* @param bid - The bid price at time of trade
|
|
301
|
+
* @param ask - The ask price at time of trade
|
|
302
|
+
* @returns The aggressor side: 'buy' if lifting offer, 'sell' if hitting bid, 'unknown' if mid
|
|
303
|
+
*
|
|
304
|
+
* @remarks
|
|
305
|
+
* The aggressor is the party that initiated the trade by crossing the spread:
|
|
306
|
+
* - Buy aggressor: Buyer lifts the offer (trades at or above ask) → bullish intent
|
|
307
|
+
* - Sell aggressor: Seller hits the bid (trades at or below bid) → bearish intent
|
|
308
|
+
* - Unknown: Trade occurred mid-market (could be internalized, crossed, or negotiated)
|
|
309
|
+
*/
|
|
310
|
+
private determineAggressorSide;
|
|
311
|
+
/**
|
|
312
|
+
* Calculates the estimated open interest change from a single trade.
|
|
313
|
+
*
|
|
314
|
+
* @param aggressorSide - The aggressor side of the trade
|
|
315
|
+
* @param size - Number of contracts traded
|
|
316
|
+
* @param optionType - Whether this is a call or put
|
|
317
|
+
* @returns Estimated OI change (positive = OI increase, negative = OI decrease)
|
|
318
|
+
*
|
|
319
|
+
* @remarks
|
|
320
|
+
* This uses a simplified heuristic based on typical market behavior:
|
|
321
|
+
*
|
|
322
|
+
* For CALLS:
|
|
323
|
+
* - Buy aggressor (lifting offer) → typically bullish, opening new longs → +OI
|
|
324
|
+
* - Sell aggressor (hitting bid) → typically closing longs or bearish new shorts → -OI
|
|
325
|
+
*
|
|
326
|
+
* For PUTS:
|
|
327
|
+
* - Buy aggressor (lifting offer) → typically bearish/hedging, opening new longs → +OI
|
|
328
|
+
* - Sell aggressor (hitting bid) → typically closing longs → -OI
|
|
329
|
+
*
|
|
330
|
+
* Note: This is an estimate. Without knowing if trades are opening or closing,
|
|
331
|
+
* we use aggressor side as a proxy. SpotGamma and similar providers use
|
|
332
|
+
* more sophisticated models that may incorporate position sizing, strike
|
|
333
|
+
* selection patterns, and other heuristics.
|
|
334
|
+
*/
|
|
335
|
+
private calculateOIChangeFromTrade;
|
|
336
|
+
/**
|
|
337
|
+
* Calculates the live (intraday) open interest estimate for an option.
|
|
338
|
+
*
|
|
339
|
+
* @param occSymbol - OCC option symbol
|
|
340
|
+
* @returns Live OI estimate = base OI + cumulative estimated changes
|
|
341
|
+
*
|
|
342
|
+
* @remarks
|
|
343
|
+
* Live Open Interest = Base OI (from REST at t=0) + Cumulative OI Changes (from trades)
|
|
344
|
+
*
|
|
345
|
+
* This provides a real-time estimate of open interest that updates throughout
|
|
346
|
+
* the trading day as trades occur. The accuracy depends on:
|
|
347
|
+
* 1. The accuracy of aggressor side detection
|
|
348
|
+
* 2. The assumption that aggressors are typically opening new positions
|
|
349
|
+
*
|
|
350
|
+
* The official OI is only updated overnight by the OCC clearing house,
|
|
351
|
+
* so this estimate fills the gap during trading hours.
|
|
352
|
+
*/
|
|
353
|
+
private calculateLiveOpenInterest;
|
|
354
|
+
/**
|
|
355
|
+
* Returns the intraday trades for an option with aggressor classification.
|
|
356
|
+
*
|
|
357
|
+
* @param occSymbol - OCC option symbol
|
|
358
|
+
* @returns Array of intraday trades, or empty array if none
|
|
359
|
+
*/
|
|
360
|
+
getIntradayTrades(occSymbol: string): IntradayTrade[];
|
|
361
|
+
/**
|
|
362
|
+
* Returns summary statistics for intraday option flow.
|
|
363
|
+
*
|
|
364
|
+
* @param occSymbol - OCC option symbol
|
|
365
|
+
* @returns Object with buy/sell volume, net OI change, and trade count
|
|
366
|
+
*/
|
|
367
|
+
getFlowSummary(occSymbol: string): {
|
|
368
|
+
buyVolume: number;
|
|
369
|
+
sellVolume: number;
|
|
370
|
+
unknownVolume: number;
|
|
371
|
+
netOIChange: number;
|
|
372
|
+
tradeCount: number;
|
|
373
|
+
};
|
|
374
|
+
/**
|
|
375
|
+
* Resets intraday tracking data. Call this at market open or when re-fetching base OI.
|
|
376
|
+
*
|
|
377
|
+
* @param occSymbols - Optional specific symbols to reset. If not provided, resets all.
|
|
378
|
+
*/
|
|
379
|
+
resetIntradayData(occSymbols?: string[]): void;
|
|
380
|
+
/**
|
|
381
|
+
* Checks if a symbol is an OCC option symbol.
|
|
382
|
+
*/
|
|
383
|
+
private isOptionSymbol;
|
|
384
|
+
/**
|
|
385
|
+
* Emits an event to all registered listeners.
|
|
386
|
+
*/
|
|
387
|
+
private emit;
|
|
388
|
+
/**
|
|
389
|
+
* Simple sleep utility.
|
|
390
|
+
*/
|
|
391
|
+
private sleep;
|
|
392
|
+
}
|
|
393
|
+
export {};
|