@fullstackcraftllc/floe 0.0.3 → 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.
@@ -147,12 +147,18 @@ export declare class TradierClient {
147
147
  private readonly apiBaseUrl;
148
148
  /** Tradier WebSocket URL */
149
149
  private readonly wsUrl;
150
+ /** Whether to log verbose debug information */
151
+ private readonly verbose;
150
152
  /**
151
153
  * Creates a new TradierClient instance.
152
154
  *
153
155
  * @param authKey - Tradier API access token
156
+ * @param options - Optional configuration options
157
+ * @param options.verbose - Whether to log verbose debug information (default: false)
154
158
  */
155
- constructor(authKey: string);
159
+ constructor(authKey: string, options?: {
160
+ verbose?: boolean;
161
+ });
156
162
  /**
157
163
  * Establishes a streaming connection to Tradier.
158
164
  *
@@ -34,8 +34,10 @@ class TradierClient {
34
34
  * Creates a new TradierClient instance.
35
35
  *
36
36
  * @param authKey - Tradier API access token
37
+ * @param options - Optional configuration options
38
+ * @param options.verbose - Whether to log verbose debug information (default: false)
37
39
  */
38
- constructor(authKey) {
40
+ constructor(authKey, options) {
39
41
  /** Current streaming session */
40
42
  this.streamSession = null;
41
43
  /** WebSocket connection */
@@ -76,6 +78,7 @@ class TradierClient {
76
78
  /** Tradier WebSocket URL */
77
79
  this.wsUrl = 'wss://ws.tradier.com/v1/markets/events';
78
80
  this.authKey = authKey;
81
+ this.verbose = options?.verbose ?? false;
79
82
  // Initialize event listener maps
80
83
  this.eventListeners.set('tickerUpdate', new Set());
81
84
  this.eventListeners.set('optionUpdate', new Set());
@@ -237,6 +240,9 @@ class TradierClient {
237
240
  if (symbols.has(item.symbol)) {
238
241
  // Store base open interest for live OI calculation (t=0 reference)
239
242
  this.baseOpenInterest.set(item.symbol, item.open_interest);
243
+ if (this.verbose) {
244
+ console.log(`[Tradier:OI] Base OI set for ${item.symbol}: ${item.open_interest}`);
245
+ }
240
246
  // Initialize cumulative OI change if not already set
241
247
  if (!this.cumulativeOIChange.has(item.symbol)) {
242
248
  this.cumulativeOIChange.set(item.symbol, 0);
@@ -373,6 +379,9 @@ class TradierClient {
373
379
  this.ws.onopen = () => {
374
380
  this.connected = true;
375
381
  this.reconnectAttempts = 0;
382
+ if (this.verbose) {
383
+ console.log('[Tradier:WS] Connected to streaming API');
384
+ }
376
385
  this.emit('connected', undefined);
377
386
  // Subscribe to any queued symbols
378
387
  if (this.subscribedSymbols.size > 0 && this.streamSession) {
@@ -411,6 +420,9 @@ class TradierClient {
411
420
  }
412
421
  this.reconnectAttempts++;
413
422
  const delay = this.baseReconnectDelay * Math.pow(2, this.reconnectAttempts - 1);
423
+ if (this.verbose) {
424
+ console.log(`[Tradier:WS] Reconnection attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts} in ${delay}ms`);
425
+ }
414
426
  await this.sleep(delay);
415
427
  try {
416
428
  await this.connect();
@@ -652,6 +664,11 @@ class TradierClient {
652
664
  // Update cumulative OI change
653
665
  const currentChange = this.cumulativeOIChange.get(occSymbol) ?? 0;
654
666
  this.cumulativeOIChange.set(occSymbol, currentChange + estimatedOIChange);
667
+ if (this.verbose && estimatedOIChange !== 0) {
668
+ const baseOI = this.baseOpenInterest.get(occSymbol) ?? 0;
669
+ const newLiveOI = Math.max(0, baseOI + currentChange + estimatedOIChange);
670
+ console.log(`[Tradier:OI] ${occSymbol} trade: price=${last.toFixed(2)}, size=${size}, aggressor=${aggressorSide}, OI change=${estimatedOIChange > 0 ? '+' : ''}${estimatedOIChange}, liveOI=${newLiveOI} (base=${baseOI}, cumulative=${currentChange + estimatedOIChange})`);
671
+ }
655
672
  // Record the trade for analysis
656
673
  const trade = {
657
674
  occSymbol,
@@ -0,0 +1,148 @@
1
+ import { NormalizedOption } from '../types';
2
+ /**
3
+ * Strike-level probability from the implied PDF
4
+ */
5
+ export interface StrikeProbability {
6
+ /** Strike price */
7
+ strike: number;
8
+ /** Probability density at this strike (normalized to sum to 1) */
9
+ probability: number;
10
+ }
11
+ /**
12
+ * Implied probability distribution derived from option prices
13
+ * using Breeden-Litzenberger style numerical differentiation
14
+ */
15
+ export interface ImpliedProbabilityDistribution {
16
+ /** Underlying symbol */
17
+ symbol: string;
18
+ /** Expiration timestamp in milliseconds */
19
+ expiryDate: number;
20
+ /** Timestamp when the distribution was calculated (milliseconds) */
21
+ calculationTimestamp: number;
22
+ /** Current underlying price */
23
+ underlyingPrice: number;
24
+ /** Strike probabilities (the PDF) */
25
+ strikeProbabilities: StrikeProbability[];
26
+ /** Most likely price (mode of the distribution) */
27
+ mostLikelyPrice: number;
28
+ /** Median price (50th percentile) */
29
+ medianPrice: number;
30
+ /** Expected value (mean) of the distribution */
31
+ expectedValue: number;
32
+ /** Expected move (standard deviation) */
33
+ expectedMove: number;
34
+ /** Tail skew ratio (right tail / left tail relative to mean) */
35
+ tailSkew: number;
36
+ /** Cumulative probability of finishing above current spot */
37
+ cumulativeProbabilityAboveSpot: number;
38
+ /** Cumulative probability of finishing below current spot */
39
+ cumulativeProbabilityBelowSpot: number;
40
+ }
41
+ /**
42
+ * Result of estimating implied probability distribution
43
+ */
44
+ export type ImpliedPDFResult = {
45
+ success: true;
46
+ distribution: ImpliedProbabilityDistribution;
47
+ } | {
48
+ success: false;
49
+ error: string;
50
+ };
51
+ /**
52
+ * Estimate an implied probability density function (PDF) for a single expiry
53
+ * using Breeden-Litzenberger style numerical differentiation of call prices.
54
+ *
55
+ * This method computes the second derivative of call option prices with respect
56
+ * to strike price, which under risk-neutral pricing gives the probability density
57
+ * of the underlying ending at each strike.
58
+ *
59
+ * @param symbol - Underlying ticker symbol
60
+ * @param underlyingPrice - Current spot/mark price of the underlying
61
+ * @param callOptions - Array of call options for a single expiry (must have bid > 0 and ask > 0)
62
+ * @returns ImpliedProbabilityDistribution with strike-level probabilities and summary statistics
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * const result = estimateImpliedProbabilityDistribution(
67
+ * 'QQQ',
68
+ * 500.00,
69
+ * callOptionsForExpiry
70
+ * );
71
+ *
72
+ * if (result.success) {
73
+ * console.log('Mode:', result.distribution.mostLikelyPrice);
74
+ * console.log('Expected move:', result.distribution.expectedMove);
75
+ * }
76
+ * ```
77
+ */
78
+ export declare function estimateImpliedProbabilityDistribution(symbol: string, underlyingPrice: number, callOptions: NormalizedOption[]): ImpliedPDFResult;
79
+ /**
80
+ * Estimate implied probability distributions for all expirations in an option chain
81
+ *
82
+ * @param symbol - Underlying ticker symbol
83
+ * @param underlyingPrice - Current spot/mark price of the underlying
84
+ * @param options - Array of all options (calls and puts, all expirations)
85
+ * @returns Array of ImpliedProbabilityDistribution for each expiration
86
+ *
87
+ * @example
88
+ * ```typescript
89
+ * const distributions = estimateImpliedProbabilityDistributions(
90
+ * 'QQQ',
91
+ * 500.00,
92
+ * chain.options
93
+ * );
94
+ *
95
+ * for (const dist of distributions) {
96
+ * console.log(`Expiry: ${new Date(dist.expiryDate).toISOString()}`);
97
+ * console.log(`Mode: ${dist.mostLikelyPrice}`);
98
+ * }
99
+ * ```
100
+ */
101
+ export declare function estimateImpliedProbabilityDistributions(symbol: string, underlyingPrice: number, options: NormalizedOption[]): ImpliedProbabilityDistribution[];
102
+ /**
103
+ * Get the probability of the underlying finishing between two price levels
104
+ *
105
+ * @param distribution - Implied probability distribution
106
+ * @param lowerBound - Lower price bound
107
+ * @param upperBound - Upper price bound
108
+ * @returns Probability of finishing between the bounds
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * // Probability of QQQ finishing between 490 and 510
113
+ * const prob = getProbabilityInRange(distribution, 490, 510);
114
+ * console.log(`${(prob * 100).toFixed(1)}% chance of finishing in range`);
115
+ * ```
116
+ */
117
+ export declare function getProbabilityInRange(distribution: ImpliedProbabilityDistribution, lowerBound: number, upperBound: number): number;
118
+ /**
119
+ * Get the cumulative probability up to a given price level
120
+ *
121
+ * @param distribution - Implied probability distribution
122
+ * @param price - Price level
123
+ * @returns Cumulative probability of finishing at or below the price
124
+ *
125
+ * @example
126
+ * ```typescript
127
+ * // Probability of QQQ finishing at or below 495
128
+ * const prob = getCumulativeProbability(distribution, 495);
129
+ * console.log(`${(prob * 100).toFixed(1)}% chance of finishing <= 495`);
130
+ * ```
131
+ */
132
+ export declare function getCumulativeProbability(distribution: ImpliedProbabilityDistribution, price: number): number;
133
+ /**
134
+ * Get the quantile (inverse CDF) for a given probability
135
+ *
136
+ * @param distribution - Implied probability distribution
137
+ * @param probability - Probability value between 0 and 1
138
+ * @returns Strike price at the given probability quantile
139
+ *
140
+ * @example
141
+ * ```typescript
142
+ * // Find the 5th and 95th percentile strikes
143
+ * const p5 = getQuantile(distribution, 0.05);
144
+ * const p95 = getQuantile(distribution, 0.95);
145
+ * console.log(`90% confidence interval: [${p5}, ${p95}]`);
146
+ * ```
147
+ */
148
+ export declare function getQuantile(distribution: ImpliedProbabilityDistribution, probability: number): number;
@@ -1 +1,278 @@
1
1
  "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.estimateImpliedProbabilityDistribution = estimateImpliedProbabilityDistribution;
4
+ exports.estimateImpliedProbabilityDistributions = estimateImpliedProbabilityDistributions;
5
+ exports.getProbabilityInRange = getProbabilityInRange;
6
+ exports.getCumulativeProbability = getCumulativeProbability;
7
+ exports.getQuantile = getQuantile;
8
+ /**
9
+ * Estimate an implied probability density function (PDF) for a single expiry
10
+ * using Breeden-Litzenberger style numerical differentiation of call prices.
11
+ *
12
+ * This method computes the second derivative of call option prices with respect
13
+ * to strike price, which under risk-neutral pricing gives the probability density
14
+ * of the underlying ending at each strike.
15
+ *
16
+ * @param symbol - Underlying ticker symbol
17
+ * @param underlyingPrice - Current spot/mark price of the underlying
18
+ * @param callOptions - Array of call options for a single expiry (must have bid > 0 and ask > 0)
19
+ * @returns ImpliedProbabilityDistribution with strike-level probabilities and summary statistics
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const result = estimateImpliedProbabilityDistribution(
24
+ * 'QQQ',
25
+ * 500.00,
26
+ * callOptionsForExpiry
27
+ * );
28
+ *
29
+ * if (result.success) {
30
+ * console.log('Mode:', result.distribution.mostLikelyPrice);
31
+ * console.log('Expected move:', result.distribution.expectedMove);
32
+ * }
33
+ * ```
34
+ */
35
+ function estimateImpliedProbabilityDistribution(symbol, underlyingPrice, callOptions) {
36
+ // Sort call options by strike price ascending
37
+ const sortedOptions = [...callOptions].sort((a, b) => a.strike - b.strike);
38
+ const n = sortedOptions.length;
39
+ if (n < 3) {
40
+ return { success: false, error: 'Not enough data points (need at least 3 call options)' };
41
+ }
42
+ // Get expiration from first option (assuming all same expiry)
43
+ const expiryDate = sortedOptions[0].expirationTimestamp;
44
+ // Estimate second derivative numerically (central difference)
45
+ // f(K) ≈ d²C/dK² where C is the call price
46
+ const strikeProbabilities = new Array(n);
47
+ // Initialize edge cases with zero probability
48
+ strikeProbabilities[0] = { strike: sortedOptions[0].strike, probability: 0 };
49
+ strikeProbabilities[n - 1] = { strike: sortedOptions[n - 1].strike, probability: 0 };
50
+ for (let i = 1; i < n - 1; i++) {
51
+ const kPrev = sortedOptions[i - 1].strike;
52
+ const kCurr = sortedOptions[i].strike;
53
+ const kNext = sortedOptions[i + 1].strike;
54
+ // Use mid prices for stability
55
+ const midPrev = (sortedOptions[i - 1].bid + sortedOptions[i - 1].ask) / 2;
56
+ const midCurr = (sortedOptions[i].bid + sortedOptions[i].ask) / 2;
57
+ const midNext = (sortedOptions[i + 1].bid + sortedOptions[i + 1].ask) / 2;
58
+ const cPrev = midPrev;
59
+ const cNext = midNext;
60
+ // Protect against division by zero if strikes are too close
61
+ const strikeDiff = kNext - kPrev;
62
+ if (Math.abs(strikeDiff) < 1e-9) {
63
+ strikeProbabilities[i] = { strike: kCurr, probability: 0 };
64
+ continue;
65
+ }
66
+ // Second derivative: d²C/dK² ≈ (C(K+) - 2*C(K) + C(K-)) / (ΔK)²
67
+ const d2 = (cNext - 2 * midCurr + cPrev) / Math.pow(strikeDiff, 2);
68
+ // f(K) = e^{rT} * d²C/dK², ignoring discount for simplicity
69
+ // Ensure non-negative probability
70
+ strikeProbabilities[i] = { strike: kCurr, probability: Math.max(d2, 0) };
71
+ }
72
+ // Normalize densities to sum to 1
73
+ let sum = 0;
74
+ for (const sp of strikeProbabilities) {
75
+ sum += sp.probability;
76
+ }
77
+ // Protect against division by zero if all probabilities are 0
78
+ if (sum < 1e-9) {
79
+ return { success: false, error: `Insufficient probability mass to normalize (sum=${sum})` };
80
+ }
81
+ for (let i = 0; i < strikeProbabilities.length; i++) {
82
+ strikeProbabilities[i].probability /= sum;
83
+ }
84
+ // Compute summary statistics
85
+ // Most likely price (mode)
86
+ let mostLikelyPrice = strikeProbabilities[0].strike;
87
+ let maxProb = 0;
88
+ for (const sp of strikeProbabilities) {
89
+ if (sp.probability > maxProb) {
90
+ maxProb = sp.probability;
91
+ mostLikelyPrice = sp.strike;
92
+ }
93
+ }
94
+ // Compute cumulative distribution for median
95
+ let cumulative = 0;
96
+ let medianPrice = strikeProbabilities[Math.floor(strikeProbabilities.length / 2)].strike;
97
+ for (const sp of strikeProbabilities) {
98
+ cumulative += sp.probability;
99
+ if (cumulative >= 0.5) {
100
+ medianPrice = sp.strike;
101
+ break;
102
+ }
103
+ }
104
+ // Expected value (mean)
105
+ let mean = 0;
106
+ for (const sp of strikeProbabilities) {
107
+ mean += sp.strike * sp.probability;
108
+ }
109
+ // Variance and expected move (standard deviation)
110
+ let variance = 0;
111
+ for (const sp of strikeProbabilities) {
112
+ const diff = sp.strike - mean;
113
+ variance += diff * diff * sp.probability;
114
+ }
115
+ const expectedMove = Math.sqrt(variance);
116
+ // Tail skew: rightTail / leftTail relative to mean
117
+ let leftTail = 0;
118
+ let rightTail = 0;
119
+ for (const sp of strikeProbabilities) {
120
+ if (sp.strike < mean) {
121
+ leftTail += sp.probability;
122
+ }
123
+ else {
124
+ rightTail += sp.probability;
125
+ }
126
+ }
127
+ const tailSkew = rightTail / Math.max(leftTail, 1e-9);
128
+ // Cumulative probabilities above and below spot price
129
+ let cumulativeBelowSpot = 0;
130
+ let cumulativeAboveSpot = 0;
131
+ for (const sp of strikeProbabilities) {
132
+ if (sp.strike < underlyingPrice) {
133
+ cumulativeBelowSpot += sp.probability;
134
+ }
135
+ else if (sp.strike > underlyingPrice) {
136
+ cumulativeAboveSpot += sp.probability;
137
+ }
138
+ }
139
+ return {
140
+ success: true,
141
+ distribution: {
142
+ symbol,
143
+ expiryDate,
144
+ calculationTimestamp: Date.now(),
145
+ underlyingPrice,
146
+ strikeProbabilities,
147
+ mostLikelyPrice,
148
+ medianPrice,
149
+ expectedValue: mean,
150
+ expectedMove,
151
+ tailSkew,
152
+ cumulativeProbabilityAboveSpot: cumulativeAboveSpot,
153
+ cumulativeProbabilityBelowSpot: cumulativeBelowSpot,
154
+ },
155
+ };
156
+ }
157
+ /**
158
+ * Estimate implied probability distributions for all expirations in an option chain
159
+ *
160
+ * @param symbol - Underlying ticker symbol
161
+ * @param underlyingPrice - Current spot/mark price of the underlying
162
+ * @param options - Array of all options (calls and puts, all expirations)
163
+ * @returns Array of ImpliedProbabilityDistribution for each expiration
164
+ *
165
+ * @example
166
+ * ```typescript
167
+ * const distributions = estimateImpliedProbabilityDistributions(
168
+ * 'QQQ',
169
+ * 500.00,
170
+ * chain.options
171
+ * );
172
+ *
173
+ * for (const dist of distributions) {
174
+ * console.log(`Expiry: ${new Date(dist.expiryDate).toISOString()}`);
175
+ * console.log(`Mode: ${dist.mostLikelyPrice}`);
176
+ * }
177
+ * ```
178
+ */
179
+ function estimateImpliedProbabilityDistributions(symbol, underlyingPrice, options) {
180
+ // Get unique expirations
181
+ const expirationsSet = new Set();
182
+ for (const option of options) {
183
+ expirationsSet.add(option.expirationTimestamp);
184
+ }
185
+ const expirations = Array.from(expirationsSet).sort((a, b) => a - b);
186
+ const distributions = [];
187
+ for (const expiry of expirations) {
188
+ // Filter to call options at this expiry with valid bid/ask
189
+ const callOptionsAtExpiry = options.filter((opt) => opt.expirationTimestamp === expiry &&
190
+ opt.optionType === 'call' &&
191
+ opt.bid > 0 &&
192
+ opt.ask > 0);
193
+ const result = estimateImpliedProbabilityDistribution(symbol, underlyingPrice, callOptionsAtExpiry);
194
+ if (result.success) {
195
+ distributions.push(result.distribution);
196
+ }
197
+ // Silently skip expirations that don't have enough data
198
+ }
199
+ return distributions;
200
+ }
201
+ /**
202
+ * Get the probability of the underlying finishing between two price levels
203
+ *
204
+ * @param distribution - Implied probability distribution
205
+ * @param lowerBound - Lower price bound
206
+ * @param upperBound - Upper price bound
207
+ * @returns Probability of finishing between the bounds
208
+ *
209
+ * @example
210
+ * ```typescript
211
+ * // Probability of QQQ finishing between 490 and 510
212
+ * const prob = getProbabilityInRange(distribution, 490, 510);
213
+ * console.log(`${(prob * 100).toFixed(1)}% chance of finishing in range`);
214
+ * ```
215
+ */
216
+ function getProbabilityInRange(distribution, lowerBound, upperBound) {
217
+ let probability = 0;
218
+ for (const sp of distribution.strikeProbabilities) {
219
+ if (sp.strike >= lowerBound && sp.strike <= upperBound) {
220
+ probability += sp.probability;
221
+ }
222
+ }
223
+ return probability;
224
+ }
225
+ /**
226
+ * Get the cumulative probability up to a given price level
227
+ *
228
+ * @param distribution - Implied probability distribution
229
+ * @param price - Price level
230
+ * @returns Cumulative probability of finishing at or below the price
231
+ *
232
+ * @example
233
+ * ```typescript
234
+ * // Probability of QQQ finishing at or below 495
235
+ * const prob = getCumulativeProbability(distribution, 495);
236
+ * console.log(`${(prob * 100).toFixed(1)}% chance of finishing <= 495`);
237
+ * ```
238
+ */
239
+ function getCumulativeProbability(distribution, price) {
240
+ let probability = 0;
241
+ for (const sp of distribution.strikeProbabilities) {
242
+ if (sp.strike <= price) {
243
+ probability += sp.probability;
244
+ }
245
+ }
246
+ return probability;
247
+ }
248
+ /**
249
+ * Get the quantile (inverse CDF) for a given probability
250
+ *
251
+ * @param distribution - Implied probability distribution
252
+ * @param probability - Probability value between 0 and 1
253
+ * @returns Strike price at the given probability quantile
254
+ *
255
+ * @example
256
+ * ```typescript
257
+ * // Find the 5th and 95th percentile strikes
258
+ * const p5 = getQuantile(distribution, 0.05);
259
+ * const p95 = getQuantile(distribution, 0.95);
260
+ * console.log(`90% confidence interval: [${p5}, ${p95}]`);
261
+ * ```
262
+ */
263
+ function getQuantile(distribution, probability) {
264
+ if (probability <= 0) {
265
+ return distribution.strikeProbabilities[0]?.strike ?? 0;
266
+ }
267
+ if (probability >= 1) {
268
+ return distribution.strikeProbabilities[distribution.strikeProbabilities.length - 1]?.strike ?? 0;
269
+ }
270
+ let cumulative = 0;
271
+ for (const sp of distribution.strikeProbabilities) {
272
+ cumulative += sp.probability;
273
+ if (cumulative >= probability) {
274
+ return sp.strike;
275
+ }
276
+ }
277
+ return distribution.strikeProbabilities[distribution.strikeProbabilities.length - 1]?.strike ?? 0;
278
+ }
package/dist/index.d.ts CHANGED
@@ -12,7 +12,11 @@ export { calculateGammaVannaCharmExposures, calculateSharesNeededToCover, } from
12
12
  export { cumulativeNormalDistribution, normalPDF, } from './utils/statistics';
13
13
  export { buildOCCSymbol, parseOCCSymbol, generateStrikesAroundSpot, generateOCCSymbolsForStrikes, generateOCCSymbolsAroundSpot, } from './utils/occ';
14
14
  export type { OCCSymbolParams, ParsedOCCSymbol, StrikeGenerationParams, } from './utils/occ';
15
+ export { estimateImpliedProbabilityDistribution, estimateImpliedProbabilityDistributions, getProbabilityInRange, getCumulativeProbability, getQuantile, } from './impliedpdf';
16
+ export type { StrikeProbability, ImpliedProbabilityDistribution, ImpliedPDFResult, } from './impliedpdf';
15
17
  export { FloeClient, Broker } from './client/FloeClient';
16
18
  export { TradierClient } from './client/brokers/TradierClient';
19
+ export { TastyTradeClient } from './client/brokers/TastyTradeClient';
20
+ export { TradeStationClient } from './client/brokers/TradeStationClient';
17
21
  export type { AggressorSide, IntradayTrade } from './client/brokers/TradierClient';
18
22
  export { genericAdapter, schwabAdapter, ibkrAdapter, tdaAdapter, brokerAdapters, getAdapter, createOptionChain, } from './adapters';
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
20
20
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
21
21
  };
22
22
  Object.defineProperty(exports, "__esModule", { value: true });
23
- exports.createOptionChain = exports.getAdapter = exports.brokerAdapters = exports.tdaAdapter = exports.ibkrAdapter = exports.schwabAdapter = exports.genericAdapter = exports.TradierClient = exports.Broker = exports.FloeClient = exports.generateOCCSymbolsAroundSpot = exports.generateOCCSymbolsForStrikes = exports.generateStrikesAroundSpot = exports.parseOCCSymbol = exports.buildOCCSymbol = exports.normalPDF = exports.cumulativeNormalDistribution = exports.calculateSharesNeededToCover = exports.calculateGammaVannaCharmExposures = exports.smoothTotalVarianceSmile = exports.getIVForStrike = exports.getIVSurfaces = exports.getTimeToExpirationInYears = exports.getMillisecondsToExpiration = exports.calculateImpliedVolatility = exports.calculateGreeks = exports.blackScholes = void 0;
23
+ exports.createOptionChain = exports.getAdapter = exports.brokerAdapters = exports.tdaAdapter = exports.ibkrAdapter = exports.schwabAdapter = exports.genericAdapter = exports.TradeStationClient = exports.TastyTradeClient = exports.TradierClient = exports.Broker = exports.FloeClient = exports.getQuantile = exports.getCumulativeProbability = exports.getProbabilityInRange = exports.estimateImpliedProbabilityDistributions = exports.estimateImpliedProbabilityDistribution = exports.generateOCCSymbolsAroundSpot = exports.generateOCCSymbolsForStrikes = exports.generateStrikesAroundSpot = exports.parseOCCSymbol = exports.buildOCCSymbol = exports.normalPDF = exports.cumulativeNormalDistribution = exports.calculateSharesNeededToCover = exports.calculateGammaVannaCharmExposures = exports.smoothTotalVarianceSmile = exports.getIVForStrike = exports.getIVSurfaces = exports.getTimeToExpirationInYears = exports.getMillisecondsToExpiration = exports.calculateImpliedVolatility = exports.calculateGreeks = exports.blackScholes = void 0;
24
24
  // Core types
25
25
  __exportStar(require("./types"), exports);
26
26
  // Black-Scholes pricing and Greeks
@@ -52,12 +52,23 @@ Object.defineProperty(exports, "parseOCCSymbol", { enumerable: true, get: functi
52
52
  Object.defineProperty(exports, "generateStrikesAroundSpot", { enumerable: true, get: function () { return occ_1.generateStrikesAroundSpot; } });
53
53
  Object.defineProperty(exports, "generateOCCSymbolsForStrikes", { enumerable: true, get: function () { return occ_1.generateOCCSymbolsForStrikes; } });
54
54
  Object.defineProperty(exports, "generateOCCSymbolsAroundSpot", { enumerable: true, get: function () { return occ_1.generateOCCSymbolsAroundSpot; } });
55
+ // Implied PDF (probability density function)
56
+ var impliedpdf_1 = require("./impliedpdf");
57
+ Object.defineProperty(exports, "estimateImpliedProbabilityDistribution", { enumerable: true, get: function () { return impliedpdf_1.estimateImpliedProbabilityDistribution; } });
58
+ Object.defineProperty(exports, "estimateImpliedProbabilityDistributions", { enumerable: true, get: function () { return impliedpdf_1.estimateImpliedProbabilityDistributions; } });
59
+ Object.defineProperty(exports, "getProbabilityInRange", { enumerable: true, get: function () { return impliedpdf_1.getProbabilityInRange; } });
60
+ Object.defineProperty(exports, "getCumulativeProbability", { enumerable: true, get: function () { return impliedpdf_1.getCumulativeProbability; } });
61
+ Object.defineProperty(exports, "getQuantile", { enumerable: true, get: function () { return impliedpdf_1.getQuantile; } });
55
62
  // Client
56
63
  var FloeClient_1 = require("./client/FloeClient");
57
64
  Object.defineProperty(exports, "FloeClient", { enumerable: true, get: function () { return FloeClient_1.FloeClient; } });
58
65
  Object.defineProperty(exports, "Broker", { enumerable: true, get: function () { return FloeClient_1.Broker; } });
59
66
  var TradierClient_1 = require("./client/brokers/TradierClient");
60
67
  Object.defineProperty(exports, "TradierClient", { enumerable: true, get: function () { return TradierClient_1.TradierClient; } });
68
+ var TastyTradeClient_1 = require("./client/brokers/TastyTradeClient");
69
+ Object.defineProperty(exports, "TastyTradeClient", { enumerable: true, get: function () { return TastyTradeClient_1.TastyTradeClient; } });
70
+ var TradeStationClient_1 = require("./client/brokers/TradeStationClient");
71
+ Object.defineProperty(exports, "TradeStationClient", { enumerable: true, get: function () { return TradeStationClient_1.TradeStationClient; } });
61
72
  // Broker adapters
62
73
  var adapters_1 = require("./adapters");
63
74
  Object.defineProperty(exports, "genericAdapter", { enumerable: true, get: function () { return adapters_1.genericAdapter; } });
@@ -20,7 +20,7 @@ import { OptionChain, IVSurface, VolatilityModel, SmoothingModel } from '../type
20
20
  */
21
21
  export declare function getIVSurfaces(volatilityModel: VolatilityModel, smoothingModel: SmoothingModel, chain: OptionChain): IVSurface[];
22
22
  /**
23
- * Get smoothed IV for a specific expiration, option type, and strike
23
+ * Helper function to get the smoothed IV for a specific expiration, option type, and strike combination
24
24
  *
25
25
  * @param ivSurfaces - Array of IV surfaces
26
26
  * @param expiration - Expiration timestamp in milliseconds
@@ -134,7 +134,7 @@ function getIVSurfaces(volatilityModel, smoothingModel, chain) {
134
134
  return ivSurfaces;
135
135
  }
136
136
  /**
137
- * Get smoothed IV for a specific expiration, option type, and strike
137
+ * Helper function to get the smoothed IV for a specific expiration, option type, and strike combination
138
138
  *
139
139
  * @param ivSurfaces - Array of IV surfaces
140
140
  * @param expiration - Expiration timestamp in milliseconds
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fullstackcraftllc/floe",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "Production-ready options analytics toolkit. Normalize broker data structures and calculate Black-Scholes, Greeks, and exposures with a clean, type-safe API. Built for trading platforms and fintech applications.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -32,7 +32,7 @@
32
32
  "license": "SEE LICENSE IN LICENSE.md",
33
33
  "repository": {
34
34
  "type": "git",
35
- "url": "https://github.com/FullStackCraft/floe.git"
35
+ "url": "git+https://github.com/FullStackCraft/floe.git"
36
36
  },
37
37
  "bugs": {
38
38
  "url": "https://github.com/FullStackCraft/floe/issues"
@@ -41,6 +41,7 @@
41
41
  "devDependencies": {
42
42
  "@types/jest": "^29.5.0",
43
43
  "@types/node": "^20.0.0",
44
+ "dotenv": "^17.2.3",
44
45
  "jest": "^29.5.0",
45
46
  "ts-jest": "^29.1.0",
46
47
  "typescript": "^5.9.3"