@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 +7 -7
- package/dist/client/brokers/TradierClient.js +7 -6
- package/dist/impliedpdf/adjusted.d.ts +173 -0
- package/dist/impliedpdf/adjusted.js +500 -0
- package/dist/impliedpdf/index.d.ts +1 -0
- package/dist/impliedpdf/index.js +10 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +27 -1
- package/dist/pressure/grid.d.ts +14 -0
- package/dist/pressure/grid.js +220 -0
- package/dist/pressure/index.d.ts +5 -0
- package/dist/pressure/index.js +22 -0
- package/dist/pressure/ivpath.d.ts +31 -0
- package/dist/pressure/ivpath.js +304 -0
- package/dist/pressure/normalize.d.ts +6 -0
- package/dist/pressure/normalize.js +76 -0
- package/dist/pressure/regime.d.ts +7 -0
- package/dist/pressure/regime.js +99 -0
- package/dist/pressure/types.d.ts +182 -0
- package/dist/pressure/types.js +2 -0
- package/dist/utils/indexOptions.js +2 -1
- package/package.json +1 -1
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
|
-
//
|
|
87
|
-
symbols.forEach(s => this.subscribedSymbols.add(s));
|
|
88
|
+
// Symbols queued for subscription when connected
|
|
88
89
|
return;
|
|
89
90
|
}
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
//
|
|
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 };
|