@fullstackcraftllc/floe 0.0.13 → 0.0.14

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 CHANGED
@@ -37,13 +37,13 @@ The same library that is used in [Full Stack Craft's](https://fullstackcraft.com
37
37
 
38
38
  Due to the overwhelming variety of how broker APIs structure their data (and how they make it available), there is a wide variety of how much support we can provide out-of-the-box for different brokers, summarized in this table:
39
39
 
40
- | Broker | Black-Scholes | Greeks | Open Interest Based Exposures | Options-Book Based Exposures | Implied PDF Calculations |
41
- |-----------------------|--------------|--------|-------------------------------|------------------------------|-------------------------|
42
- | Tradier (via WebSocket) | ✅ | ✅ | ✅ | ✅ | ✅ |
43
- | Tastytrade (via WebSocket - DXLink Streamer) | ✅ | ✅ | ✅ | ✅ | ✅ |
44
- | TradeStation (via HTTP Streaming) | ✅ | ✅ | ✅ | ✅ | ✅ |
45
- | Schwab (via WebSocket) | ✅ | ✅ | ✅ | ✅ | ✅ |
46
- | Interactive Brokers (via WebSocket) | Coming Soon | Coming Soon | Coming Soon | Coming Soon | Coming Soon |
40
+ | Broker | Black-Scholes | Greeks | Open Interest Based Exposures | Options-Book Based Exposures | Implied PDF Calculations | SPX / NDX 0DTE Data |
41
+ |-----------------------|--------------|--------|-------------------------------|------------------------------|-------------------------|----------------------|
42
+ | Tradier (via WebSocket) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
43
+ | Tastytrade (via WebSocket - DXLink Streamer) | ✅ | ✅ | ✅ | ✅ | ✅ | Not yet tested |
44
+ | TradeStation (via HTTP Streaming) | ✅ | ✅ | ✅ | ✅ | ✅ | Not yet tested |
45
+ | Schwab (via WebSocket) | ✅ | ✅ | ✅ | ✅ | ✅ | Not yet tested |
46
+ | Interactive Brokers (via WebSocket) | Coming Soon | Coming Soon | Coming Soon | Coming Soon | Coming Soon | Coming Soon |
47
47
 
48
48
  Ideally all aspects of `floe` will be available for all brokers, but this will take time to determine as we work through the various data structures and formats that each broker provides.
49
49
 
@@ -82,17 +82,18 @@ class TradierClient extends BaseBrokerClient_1.BaseBrokerClient {
82
82
  * @param symbols - Array of ticker symbols and/or OCC option symbols
83
83
  */
84
84
  subscribe(symbols) {
85
+ // Add to tracked symbols first
86
+ symbols.forEach(s => this.subscribedSymbols.add(s));
85
87
  if (!this.connected || !this.ws || !this.streamSession) {
86
- // Queue symbols for subscription when connected
87
- symbols.forEach(s => this.subscribedSymbols.add(s));
88
+ // Symbols queued for subscription when connected
88
89
  return;
89
90
  }
90
- // Add to tracked symbols
91
- symbols.forEach(s => this.subscribedSymbols.add(s));
92
- // Send subscription message
91
+ // Send subscription message with ALL subscribed symbols
92
+ // Tradier replaces the entire subscription list on each payload,
93
+ // so we must send the complete list every time
93
94
  const payload = {
94
95
  sessionid: this.streamSession.sessionid,
95
- symbols: symbols,
96
+ symbols: Array.from(this.subscribedSymbols), // send ALL symbols!
96
97
  };
97
98
  this.ws.send(JSON.stringify(payload));
98
99
  }
@@ -0,0 +1,173 @@
1
+ import { ImpliedProbabilityDistribution, getProbabilityInRange, getCumulativeProbability, getQuantile } from './index';
2
+ import { ExposurePerExpiry, NormalizedOption } from '../types';
3
+ /**
4
+ * Configuration for exposure-based PDF adjustments
5
+ */
6
+ export interface ExposureAdjustmentConfig {
7
+ /** Gamma adjustment settings */
8
+ gamma: {
9
+ /** Enable gamma-based kurtosis adjustment */
10
+ enabled: boolean;
11
+ /** Strength of attractor effect at +GEX strikes (0-1) */
12
+ attractorStrength: number;
13
+ /** Strength of repellent effect at -GEX strikes (0-1) */
14
+ repellentStrength: number;
15
+ /** Minimum absolute GEX to consider significant (in dollars) */
16
+ threshold: number;
17
+ /** Decay rate for influence distance (higher = more localized) */
18
+ decayRate: number;
19
+ };
20
+ /** Vanna adjustment settings */
21
+ vanna: {
22
+ /** Enable vanna-based tail adjustment */
23
+ enabled: boolean;
24
+ /** Spot-vol beta: IV change per 1% spot move (typically -2 to -4 for indices) */
25
+ spotVolBeta: number;
26
+ /** Maximum tail fattening multiplier */
27
+ maxTailMultiplier: number;
28
+ /** Number of feedback iterations to simulate */
29
+ feedbackIterations: number;
30
+ };
31
+ /** Charm adjustment settings */
32
+ charm: {
33
+ /** Enable charm-based mean shift */
34
+ enabled: boolean;
35
+ /** Time horizon multiplier ('intraday' = 0.25, 'daily' = 1.0, 'weekly' = 5.0) */
36
+ timeHorizon: 'intraday' | 'daily' | 'weekly';
37
+ /** Scaling factor for mean shift */
38
+ shiftScale: number;
39
+ };
40
+ }
41
+ /**
42
+ * Result of exposure-adjusted PDF calculation
43
+ */
44
+ export interface AdjustedPDFResult {
45
+ /** Original market-implied distribution */
46
+ baseline: ImpliedProbabilityDistribution;
47
+ /** Exposure-adjusted distribution */
48
+ adjusted: ImpliedProbabilityDistribution;
49
+ /** Gamma modifier applied at each strike (multiplicative) */
50
+ gammaModifiers: number[];
51
+ /** Vanna modifier applied at each strike (multiplicative) */
52
+ vannaModifiers: number[];
53
+ /** Charm-induced mean shift (in price units) */
54
+ charmShift: number;
55
+ /** Comparison metrics between baseline and adjusted */
56
+ comparison: PDFComparison;
57
+ }
58
+ /**
59
+ * Comparison metrics between baseline and adjusted PDFs
60
+ */
61
+ export interface PDFComparison {
62
+ /** Shift in expected value */
63
+ meanShift: number;
64
+ /** Shift as percentage of spot */
65
+ meanShiftPercent: number;
66
+ /** Change in standard deviation */
67
+ stdDevChange: number;
68
+ /** Change in tail skew ratio */
69
+ tailSkewChange: number;
70
+ /** 5th percentile: baseline vs adjusted */
71
+ leftTail: {
72
+ baseline: number;
73
+ adjusted: number;
74
+ ratio: number;
75
+ };
76
+ /** 95th percentile: baseline vs adjusted */
77
+ rightTail: {
78
+ baseline: number;
79
+ adjusted: number;
80
+ ratio: number;
81
+ };
82
+ /** Dominant adjustment factor */
83
+ dominantFactor: 'gamma' | 'vanna' | 'charm' | 'none';
84
+ }
85
+ /**
86
+ * Default configuration tuned for SPX-like indices
87
+ */
88
+ export declare const DEFAULT_ADJUSTMENT_CONFIG: ExposureAdjustmentConfig;
89
+ /**
90
+ * Configuration for low volatility / grinding markets
91
+ */
92
+ export declare const LOW_VOL_CONFIG: ExposureAdjustmentConfig;
93
+ /**
94
+ * Configuration for high volatility / crisis markets
95
+ */
96
+ export declare const CRISIS_CONFIG: ExposureAdjustmentConfig;
97
+ /**
98
+ * Configuration for OPEX week
99
+ */
100
+ export declare const OPEX_CONFIG: ExposureAdjustmentConfig;
101
+ /**
102
+ * Estimate an exposure-adjusted implied probability distribution.
103
+ *
104
+ * This function takes the standard market-implied PDF (Breeden-Litzenberger)
105
+ * and adjusts it based on dealer Greek exposures to produce a "mechanically-informed"
106
+ * probability distribution that accounts for:
107
+ *
108
+ * - **Gamma**: Creates "sticky" zones (+GEX) where price pins, and "slippery" zones
109
+ * (-GEX) where price accelerates through
110
+ * - **Vanna**: Fattens tails based on the IV-spot feedback loop (selloffs spike IV,
111
+ * which forces more selling via negative vanna)
112
+ * - **Charm**: Shifts the mean based on predictable delta decay over time
113
+ *
114
+ * @param symbol - Underlying ticker symbol
115
+ * @param underlyingPrice - Current spot price
116
+ * @param callOptions - Call options for a single expiry
117
+ * @param exposures - Exposure metrics from calculateGammaVannaCharmExposures()
118
+ * @param config - Adjustment configuration (uses defaults if not provided)
119
+ * @returns Baseline and adjusted PDFs with comparison metrics
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * // Get exposures first
124
+ * const allExposures = calculateGammaVannaCharmExposures(chain, ivSurfaces);
125
+ * const expiryExposures = allExposures.find(e => e.expiration === targetExpiry);
126
+ *
127
+ * // Calculate adjusted PDF
128
+ * const result = estimateExposureAdjustedPDF(
129
+ * 'SPX',
130
+ * 4520,
131
+ * callOptionsForExpiry,
132
+ * expiryExposures
133
+ * );
134
+ *
135
+ * // Compare probabilities
136
+ * const target = 4400;
137
+ * const baselineProb = getCumulativeProbability(result.baseline, target);
138
+ * const adjustedProb = getCumulativeProbability(result.adjusted, target);
139
+ * console.log(`Market says ${baselineProb}% chance of ${target}`);
140
+ * console.log(`Flow-adjusted: ${adjustedProb}% chance`);
141
+ * ```
142
+ */
143
+ export declare function estimateExposureAdjustedPDF(symbol: string, underlyingPrice: number, callOptions: NormalizedOption[], exposures: ExposurePerExpiry, config?: Partial<ExposureAdjustmentConfig>): AdjustedPDFResult | {
144
+ success: false;
145
+ error: string;
146
+ };
147
+ /**
148
+ * Get the "edge" - the difference between market-implied and flow-adjusted
149
+ * probability of reaching a price level.
150
+ *
151
+ * Positive edge means the market is underpricing the probability of reaching that level.
152
+ * Negative edge means the market is overpricing it.
153
+ *
154
+ * @example
155
+ * ```typescript
156
+ * const result = estimateExposureAdjustedPDF(...);
157
+ * const edge = getEdgeAtPrice(result, 4400);
158
+ * console.log(`Edge at 4400: ${(edge * 100).toFixed(2)}%`);
159
+ * // Output: "Edge at 4400: 2.35%"
160
+ * // Meaning: flow mechanics suggest 2.35% higher probability than market prices
161
+ * ```
162
+ */
163
+ export declare function getEdgeAtPrice(result: AdjustedPDFResult, price: number): number;
164
+ /**
165
+ * Get price levels where the adjustment is most significant
166
+ */
167
+ export declare function getSignificantAdjustmentLevels(result: AdjustedPDFResult, threshold?: number): Array<{
168
+ strike: number;
169
+ baselineProb: number;
170
+ adjustedProb: number;
171
+ edge: number;
172
+ }>;
173
+ export { getProbabilityInRange, getCumulativeProbability, getQuantile };