@fullstackcraftllc/floe 0.0.1

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.
@@ -0,0 +1,266 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.blackScholes = blackScholes;
4
+ exports.calculateGreeks = calculateGreeks;
5
+ exports.calculateImpliedVolatility = calculateImpliedVolatility;
6
+ exports.getMillisecondsToExpiration = getMillisecondsToExpiration;
7
+ exports.getTimeToExpirationInYears = getTimeToExpirationInYears;
8
+ const types_1 = require("../types");
9
+ const statistics_1 = require("../utils/statistics");
10
+ /**
11
+ * Calculate option price using Black-Scholes model
12
+ *
13
+ * @param params - Black-Scholes parameters
14
+ * @returns Option price
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const price = blackScholes({
19
+ * spot: 100,
20
+ * strike: 105,
21
+ * timeToExpiry: 0.25,
22
+ * volatility: 0.20,
23
+ * riskFreeRate: 0.05,
24
+ * optionType: 'call'
25
+ * });
26
+ * ```
27
+ */
28
+ function blackScholes(params) {
29
+ const greeks = calculateGreeks(params);
30
+ return greeks.price;
31
+ }
32
+ /**
33
+ * Calculate complete option Greeks using Black-Scholes-Merton model
34
+ * Includes all first, second, and third-order Greeks
35
+ *
36
+ * @param params - Black-Scholes parameters
37
+ * @returns Complete Greeks including price
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * const greeks = calculateGreeks({
42
+ * spot: 100,
43
+ * strike: 105,
44
+ * timeToExpiry: 0.25,
45
+ * volatility: 0.20,
46
+ * riskFreeRate: 0.05,
47
+ * optionType: 'call'
48
+ * });
49
+ * ```
50
+ */
51
+ function calculateGreeks(params) {
52
+ const { spot: S, strike: K, timeToExpiry: t, volatility: vol, riskFreeRate: r, optionType, dividendYield: q = 0, } = params;
53
+ // Safety checks
54
+ if (t < 0) {
55
+ return createZeroGreeks();
56
+ }
57
+ if (vol <= 0 || S <= 0 || t <= 0) {
58
+ return createZeroGreeks();
59
+ }
60
+ // Calculate d1 and d2
61
+ const sqrtT = Math.sqrt(t);
62
+ const d1 = (Math.log(S / K) + (r - q + (vol * vol) / 2) * t) / (vol * sqrtT);
63
+ const d2 = d1 - vol * sqrtT;
64
+ // Calculate probability functions
65
+ const nd1 = (0, statistics_1.normalPDF)(d1);
66
+ const Nd1 = (0, statistics_1.cumulativeNormalDistribution)(d1);
67
+ const Nd2 = (0, statistics_1.cumulativeNormalDistribution)(d2);
68
+ const eqt = Math.exp(-q * t);
69
+ const ert = Math.exp(-r * t);
70
+ if (optionType === 'call') {
71
+ return calculateCallGreeks(S, K, r, q, t, vol, d1, d2, nd1, Nd1, Nd2, eqt, ert);
72
+ }
73
+ else {
74
+ return calculatePutGreeks(S, K, r, q, t, vol, d1, d2, nd1, Nd1, Nd2, eqt, ert);
75
+ }
76
+ }
77
+ /**
78
+ * Calculate all Greeks for a call option
79
+ * @internal
80
+ */
81
+ function calculateCallGreeks(S, K, r, q, t, vol, d1, d2, nd1, Nd1, Nd2, eqt, ert) {
82
+ const sqrtT = Math.sqrt(t);
83
+ // Price
84
+ const price = S * eqt * Nd1 - K * ert * Nd2;
85
+ // First-order Greeks
86
+ const delta = eqt * Nd1;
87
+ const gamma = (eqt * nd1) / (S * vol * sqrtT);
88
+ const theta = -(S * vol * eqt * nd1) / (2 * sqrtT) - r * K * ert * Nd2 + q * S * eqt * Nd1;
89
+ const vega = S * eqt * sqrtT * nd1;
90
+ const rho = K * t * ert * Nd2;
91
+ // Second-order Greeks
92
+ const vanna = -eqt * nd1 * (d2 / vol);
93
+ const charm = -q * eqt * Nd1 - (eqt * nd1 * (2 * (r - q) * t - d2 * vol * sqrtT)) / (2 * t * vol * sqrtT);
94
+ const volga = vega * ((d1 * d2) / (S * vol));
95
+ const speed = nd1 / (S * vol);
96
+ const zomma = (nd1 * d1) / (S * vol * vol);
97
+ // Third-order Greeks
98
+ const color = -(d1 * d2 * nd1) / (vol * vol);
99
+ const ultima = (d1 * d2 * d2 * nd1) / (vol * vol * vol);
100
+ return {
101
+ price: round(price, 2),
102
+ delta: round(delta, 5),
103
+ gamma: round(gamma, 5),
104
+ theta: round(theta / types_1.DAYS_PER_YEAR, 5), // Per day
105
+ vega: round(vega * 0.01, 5), // Per 1% change in volatility
106
+ rho: round(rho * 0.01, 5), // Per 1% change in interest rate
107
+ charm: round(charm / types_1.DAYS_PER_YEAR, 5), // Per day
108
+ vanna: round(vanna, 5),
109
+ volga: round(volga, 5),
110
+ speed: round(speed, 5),
111
+ zomma: round(zomma, 5),
112
+ color: round(color, 5),
113
+ ultima: round(ultima, 5),
114
+ };
115
+ }
116
+ /**
117
+ * Calculate all Greeks for a put option
118
+ * @internal
119
+ */
120
+ function calculatePutGreeks(S, K, r, q, t, vol, d1, d2, nd1, Nd1, Nd2, eqt, ert) {
121
+ const sqrtT = Math.sqrt(t);
122
+ // Price
123
+ const price = K * ert * (0, statistics_1.cumulativeNormalDistribution)(-d2) - S * eqt * (0, statistics_1.cumulativeNormalDistribution)(-d1);
124
+ // First-order Greeks
125
+ const delta = -eqt * (0, statistics_1.cumulativeNormalDistribution)(-d1);
126
+ const gamma = (eqt * nd1) / (S * vol * sqrtT); // Same as call
127
+ const theta = -(S * vol * eqt * nd1) / (2 * sqrtT) + r * K * ert * (0, statistics_1.cumulativeNormalDistribution)(-d2) - q * S * eqt * (0, statistics_1.cumulativeNormalDistribution)(-d1);
128
+ const vega = S * eqt * sqrtT * nd1; // Same as call
129
+ const rho = -K * t * ert * (0, statistics_1.cumulativeNormalDistribution)(-d2);
130
+ // Second-order Greeks (same as call for gamma, vega, vanna)
131
+ const vanna = -eqt * nd1 * (d2 / vol); // Same as call
132
+ const charm = -q * eqt * (0, statistics_1.cumulativeNormalDistribution)(-d1) - (eqt * nd1 * (2 * (r - q) * t - d2 * vol * sqrtT)) / (2 * t * vol * sqrtT);
133
+ const volga = vega * ((d1 * d2) / (S * vol)); // Same as call
134
+ const speed = (nd1 * d1 * d1) / vol;
135
+ const zomma = ((1 + d1 * d2) * nd1) / (vol * vol * sqrtT);
136
+ // Third-order Greeks
137
+ const color = ((1 - d1 * d2) * nd1) / S;
138
+ const ultima = (t * S * nd1 * d1 * d1) / vol;
139
+ return {
140
+ price: round(price, 2),
141
+ delta: round(delta, 5),
142
+ gamma: round(gamma, 5),
143
+ theta: round(theta / types_1.DAYS_PER_YEAR, 5), // Per day
144
+ vega: round(vega * 0.01, 5), // Per 1% change in volatility
145
+ rho: round(rho * 0.01, 5), // Per 1% change in interest rate
146
+ charm: round(charm / types_1.DAYS_PER_YEAR, 5), // Per day
147
+ vanna: round(vanna, 5),
148
+ volga: round(volga, 5),
149
+ speed: round(speed, 5),
150
+ zomma: round(zomma, 5),
151
+ color: round(color, 5),
152
+ ultima: round(ultima, 5),
153
+ };
154
+ }
155
+ /**
156
+ * Calculate implied volatility using bisection method
157
+ *
158
+ * @param price - Observed option price
159
+ * @param spot - Current spot price
160
+ * @param strike - Strike price
161
+ * @param riskFreeRate - Risk-free interest rate (as decimal)
162
+ * @param dividendYield - Dividend yield (as decimal)
163
+ * @param timeToExpiry - Time to expiration in years
164
+ * @param optionType - 'call' or 'put'
165
+ * @returns Implied volatility as a percentage (e.g., 20.0 for 20%)
166
+ *
167
+ * @example
168
+ * ```typescript
169
+ * const iv = calculateImpliedVolatility(5.50, 100, 105, 0.05, 0, 0.25, 'call');
170
+ * console.log(`IV: ${iv}%`);
171
+ * ```
172
+ */
173
+ function calculateImpliedVolatility(price, spot, strike, riskFreeRate, dividendYield, timeToExpiry, optionType) {
174
+ // Sanity checks
175
+ if (price <= 0 || spot <= 0 || strike <= 0 || timeToExpiry <= 0) {
176
+ return 0;
177
+ }
178
+ // Calculate intrinsic value
179
+ const intrinsic = optionType === 'call'
180
+ ? Math.max(0, spot * Math.exp(-dividendYield * timeToExpiry) - strike * Math.exp(-riskFreeRate * timeToExpiry))
181
+ : Math.max(0, strike * Math.exp(-riskFreeRate * timeToExpiry) - spot * Math.exp(-dividendYield * timeToExpiry));
182
+ // If price is at or below intrinsic value, return minimum IV
183
+ const extrinsic = price - intrinsic;
184
+ if (extrinsic <= 0.01) {
185
+ return 1.0; // 1% IV as floor
186
+ }
187
+ // Bisection search bounds (in decimal form)
188
+ let low = 0.0001;
189
+ let high = 5.0; // 500% volatility
190
+ let mid = 0;
191
+ // Bisection method
192
+ for (let i = 0; i < 100; i++) {
193
+ mid = 0.5 * (low + high);
194
+ const modelPrice = blackScholes({
195
+ spot,
196
+ strike,
197
+ timeToExpiry,
198
+ volatility: mid,
199
+ riskFreeRate,
200
+ dividendYield,
201
+ optionType,
202
+ });
203
+ const diff = modelPrice - price;
204
+ if (Math.abs(diff) < 1e-6) {
205
+ return mid * 100.0; // Return as percentage
206
+ }
207
+ if (diff > 0) {
208
+ // Model price too high → volatility too high
209
+ high = mid;
210
+ }
211
+ else {
212
+ // Model price too low → volatility too low
213
+ low = mid;
214
+ }
215
+ }
216
+ // Return midpoint as percentage
217
+ return 0.5 * (low + high) * 100.0;
218
+ }
219
+ /**
220
+ * Get milliseconds until expiration
221
+ *
222
+ * @param expirationTimestamp - Expiration timestamp in milliseconds
223
+ * @returns Milliseconds until expiration
224
+ */
225
+ function getMillisecondsToExpiration(expirationTimestamp) {
226
+ return expirationTimestamp - Date.now();
227
+ }
228
+ /**
229
+ * Get time to expiration in years
230
+ *
231
+ * @param expirationTimestamp - Expiration timestamp in milliseconds
232
+ * @returns Time to expiration in years
233
+ */
234
+ function getTimeToExpirationInYears(expirationTimestamp) {
235
+ const milliseconds = getMillisecondsToExpiration(expirationTimestamp);
236
+ return milliseconds / types_1.MILLISECONDS_PER_YEAR;
237
+ }
238
+ /**
239
+ * Helper: Round number to specified decimal places
240
+ * @internal
241
+ */
242
+ function round(value, decimals) {
243
+ const factor = Math.pow(10, decimals);
244
+ return Math.round(value * factor) / factor;
245
+ }
246
+ /**
247
+ * Helper: Create zero Greeks object
248
+ * @internal
249
+ */
250
+ function createZeroGreeks() {
251
+ return {
252
+ price: 0,
253
+ delta: 0,
254
+ gamma: 0,
255
+ theta: 0,
256
+ vega: 0,
257
+ rho: 0,
258
+ charm: 0,
259
+ vanna: 0,
260
+ volga: 0,
261
+ speed: 0,
262
+ zomma: 0,
263
+ color: 0,
264
+ ultima: 0,
265
+ };
266
+ }
@@ -0,0 +1,35 @@
1
+ import { OptionChain, ExposurePerExpiry, IVSurface } from '../types';
2
+ /**
3
+ * Calculate Gamma, Vanna, and Charm exposures for an option chain
4
+ *
5
+ * @param chain - Option chain with market context (spot, rates, options)
6
+ * @param ivSurfaces - IV surfaces for all expirations
7
+ * @returns Array of exposure metrics per expiration
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * const exposures = calculateGammaVannaCharmExposures(chain, ivSurfaces);
12
+ * ```
13
+ */
14
+ export declare function calculateGammaVannaCharmExposures(chain: OptionChain, ivSurfaces: IVSurface[]): ExposurePerExpiry[];
15
+ /**
16
+ * Calculate shares needed to cover net exposure
17
+ *
18
+ * @param sharesOutstanding - Total shares outstanding
19
+ * @param totalNetExposure - Total net exposure (gamma + vanna + charm)
20
+ * @param underlyingMark - Current spot price
21
+ * @returns Action to cover, shares to cover, implied move %, and resulting price
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * const coverage = calculateSharesNeededToCover(1000000000, -5000000, 450.50);
26
+ * console.log(`Action: ${coverage.actionToCover}`);
27
+ * console.log(`Shares: ${coverage.sharesToCover}`);
28
+ * ```
29
+ */
30
+ export declare function calculateSharesNeededToCover(sharesOutstanding: number, totalNetExposure: number, underlyingMark: number): {
31
+ actionToCover: string;
32
+ sharesToCover: number;
33
+ impliedMoveToCover: number;
34
+ resultingSpotToCover: number;
35
+ };
@@ -0,0 +1,212 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.calculateGammaVannaCharmExposures = calculateGammaVannaCharmExposures;
4
+ exports.calculateSharesNeededToCover = calculateSharesNeededToCover;
5
+ const types_1 = require("../types");
6
+ const blackscholes_1 = require("../blackscholes");
7
+ const volatility_1 = require("../volatility");
8
+ /**
9
+ * Calculate Gamma, Vanna, and Charm exposures for an option chain
10
+ *
11
+ * @param chain - Option chain with market context (spot, rates, options)
12
+ * @param ivSurfaces - IV surfaces for all expirations
13
+ * @returns Array of exposure metrics per expiration
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const exposures = calculateGammaVannaCharmExposures(chain, ivSurfaces);
18
+ * ```
19
+ */
20
+ function calculateGammaVannaCharmExposures(chain, ivSurfaces) {
21
+ const { spot, riskFreeRate, dividendYield, options } = chain;
22
+ const exposureRows = [];
23
+ // Get unique expirations from options
24
+ const expirationsSet = new Set();
25
+ for (const option of options) {
26
+ expirationsSet.add(option.expirationTimestamp);
27
+ }
28
+ const expirations = Array.from(expirationsSet).sort((a, b) => a - b);
29
+ // Loop through all expirations
30
+ for (const expiration of expirations) {
31
+ // Skip any expiration that is in the past
32
+ if (expiration < Date.now()) {
33
+ continue;
34
+ }
35
+ // Reset totals for this expiration
36
+ let totalGammaExposure = 0.0;
37
+ let totalVannaExposure = 0.0;
38
+ let totalCharmExposure = 0.0;
39
+ let strikeOfMaxGamma = 0.0;
40
+ let strikeOfMinGamma = 0.0;
41
+ let strikeOfMaxVanna = 0.0;
42
+ let strikeOfMinVanna = 0.0;
43
+ let strikeOfMaxCharm = 0.0;
44
+ let strikeOfMinCharm = 0.0;
45
+ let strikeOfMaxNet = 0.0;
46
+ let strikeOfMinNet = 0.0;
47
+ const strikeExposures = [];
48
+ // Process all call options first
49
+ for (const callOption of options) {
50
+ // Check if this option is at the expiration we are looking at
51
+ if (callOption.expirationTimestamp !== expiration || callOption.optionType === 'put') {
52
+ continue;
53
+ }
54
+ // Get the corresponding put option
55
+ const putOption = options.find((opt) => opt.expirationTimestamp === expiration &&
56
+ opt.optionType === 'put' &&
57
+ opt.strike === callOption.strike);
58
+ if (!putOption) {
59
+ continue; // Skip if no matching put
60
+ }
61
+ // Get IV for this strike and expiry from the surface
62
+ const callIVAtStrike = (0, volatility_1.getIVForStrike)(ivSurfaces, expiration, 'call', callOption.strike);
63
+ const putIVAtStrike = (0, volatility_1.getIVForStrike)(ivSurfaces, expiration, 'put', putOption.strike);
64
+ // Get time to expiration in years
65
+ const timeToExpirationInYears = (0, blackscholes_1.getTimeToExpirationInYears)(expiration);
66
+ // Calculate Greeks for both call and put
67
+ // Rates are already decimals in OptionChain, IV from surface is percentage
68
+ const callGreeks = (0, blackscholes_1.calculateGreeks)({
69
+ spot,
70
+ strike: callOption.strike,
71
+ timeToExpiry: timeToExpirationInYears,
72
+ volatility: callIVAtStrike / 100.0, // Convert from percentage to decimal
73
+ riskFreeRate,
74
+ dividendYield,
75
+ optionType: 'call',
76
+ });
77
+ const putGreeks = (0, blackscholes_1.calculateGreeks)({
78
+ spot,
79
+ strike: putOption.strike,
80
+ timeToExpiry: timeToExpirationInYears,
81
+ volatility: putIVAtStrike / 100.0,
82
+ riskFreeRate,
83
+ dividendYield,
84
+ optionType: 'put',
85
+ });
86
+ // Calculate exposures from dealer perspective
87
+ // Dealer is short calls (negative gamma) and long puts (positive gamma)
88
+ // Multiply by 100 for contract size, multiply by spot for dollar exposure
89
+ // Multiply by 0.01 for 1% move sensitivity
90
+ // Gamma: second order with respect to price twice
91
+ const gammaExposureForStrike = -callOption.openInterest * callGreeks.gamma * (spot * 100.0) * spot * 0.01 +
92
+ putOption.openInterest * putGreeks.gamma * (spot * 100.0) * spot * 0.01;
93
+ // Vanna: second order with respect to price and volatility
94
+ const vannaExposureForStrike = -callOption.openInterest * callGreeks.vanna * (spot * 100.0) * callIVAtStrike * 0.01 +
95
+ putOption.openInterest * putGreeks.vanna * (spot * 100.0) * putIVAtStrike * 0.01;
96
+ // Charm: second order with respect to price and time
97
+ // Already normalized per day in calculateGreeks
98
+ const charmExposureForStrike = -callOption.openInterest * callGreeks.charm * (spot * 100.0) * types_1.DAYS_PER_YEAR * timeToExpirationInYears +
99
+ putOption.openInterest * putGreeks.charm * (spot * 100.0) * types_1.DAYS_PER_YEAR * timeToExpirationInYears;
100
+ // NaN checks
101
+ const gammaExposure = isNaN(gammaExposureForStrike) ? 0.0 : gammaExposureForStrike;
102
+ const vannaExposure = isNaN(vannaExposureForStrike) ? 0.0 : vannaExposureForStrike;
103
+ const charmExposure = isNaN(charmExposureForStrike) ? 0.0 : charmExposureForStrike;
104
+ // Add to totals
105
+ totalGammaExposure += gammaExposure;
106
+ totalVannaExposure += vannaExposure;
107
+ totalCharmExposure += charmExposure;
108
+ // Add to strike exposures
109
+ strikeExposures.push({
110
+ strikePrice: callOption.strike,
111
+ gammaExposure,
112
+ vannaExposure,
113
+ charmExposure,
114
+ netExposure: gammaExposure + vannaExposure + charmExposure,
115
+ });
116
+ }
117
+ if (strikeExposures.length === 0) {
118
+ continue; // No options for this expiration
119
+ }
120
+ // Sort by gamma exposure and find extremes
121
+ strikeExposures.sort((a, b) => b.gammaExposure - a.gammaExposure);
122
+ strikeOfMaxGamma = strikeExposures[0].strikePrice;
123
+ strikeOfMinGamma = strikeExposures[strikeExposures.length - 1].strikePrice;
124
+ // Sort by vanna exposure and find extremes
125
+ strikeExposures.sort((a, b) => b.vannaExposure - a.vannaExposure);
126
+ strikeOfMaxVanna = strikeExposures[0].strikePrice;
127
+ strikeOfMinVanna = strikeExposures[strikeExposures.length - 1].strikePrice;
128
+ // Sort by charm exposure and find extremes
129
+ strikeExposures.sort((a, b) => b.charmExposure - a.charmExposure);
130
+ strikeOfMaxCharm = strikeExposures[0].strikePrice;
131
+ strikeOfMinCharm = strikeExposures[strikeExposures.length - 1].strikePrice;
132
+ // Sort by net exposure and find extremes
133
+ strikeExposures.sort((a, b) => b.netExposure - a.netExposure);
134
+ strikeOfMaxNet = strikeExposures[0].strikePrice;
135
+ strikeOfMinNet = strikeExposures[strikeExposures.length - 1].strikePrice;
136
+ const totalNetExposure = totalGammaExposure + totalVannaExposure + totalCharmExposure;
137
+ // Add exposure row
138
+ exposureRows.push({
139
+ spotPrice: spot,
140
+ expiration,
141
+ totalGammaExposure,
142
+ totalVannaExposure,
143
+ totalCharmExposure,
144
+ totalNetExposure,
145
+ strikeOfMaxGamma,
146
+ strikeOfMinGamma,
147
+ strikeOfMaxVanna,
148
+ strikeOfMinVanna,
149
+ strikeOfMaxCharm,
150
+ strikeOfMinCharm,
151
+ strikeOfMaxNet,
152
+ strikeOfMinNet,
153
+ strikeExposures
154
+ });
155
+ }
156
+ return exposureRows;
157
+ }
158
+ /**
159
+ * Calculate shares needed to cover net exposure
160
+ *
161
+ * @param sharesOutstanding - Total shares outstanding
162
+ * @param totalNetExposure - Total net exposure (gamma + vanna + charm)
163
+ * @param underlyingMark - Current spot price
164
+ * @returns Action to cover, shares to cover, implied move %, and resulting price
165
+ *
166
+ * @example
167
+ * ```typescript
168
+ * const coverage = calculateSharesNeededToCover(1000000000, -5000000, 450.50);
169
+ * console.log(`Action: ${coverage.actionToCover}`);
170
+ * console.log(`Shares: ${coverage.sharesToCover}`);
171
+ * ```
172
+ */
173
+ function calculateSharesNeededToCover(sharesOutstanding, totalNetExposure, underlyingMark) {
174
+ let actionToCover = 'BUY';
175
+ if (totalNetExposure > 0) {
176
+ actionToCover = 'SELL';
177
+ }
178
+ // Protect from inf or nan
179
+ if (sharesOutstanding === 0 ||
180
+ isNaN(sharesOutstanding) ||
181
+ !isFinite(sharesOutstanding)) {
182
+ return {
183
+ actionToCover: '',
184
+ sharesToCover: 0,
185
+ impliedMoveToCover: 0,
186
+ resultingSpotToCover: underlyingMark,
187
+ };
188
+ }
189
+ // Protect against division by zero for underlyingMark
190
+ if (underlyingMark === 0 ||
191
+ isNaN(underlyingMark) ||
192
+ !isFinite(underlyingMark)) {
193
+ return {
194
+ actionToCover: '',
195
+ sharesToCover: 0,
196
+ impliedMoveToCover: 0,
197
+ resultingSpotToCover: underlyingMark,
198
+ };
199
+ }
200
+ // Since this is the action the dealer makes, we negate it to get the implied move
201
+ // i.e. negative exposure means the dealer has to buy to cover, which implies upward pressure
202
+ // likewise positive exposure means the dealer has to sell to cover, which implies downward pressure
203
+ const sharesNeededToCoverFloat = -totalNetExposure / underlyingMark;
204
+ const impliedChange = (sharesNeededToCoverFloat / sharesOutstanding) * 100.0;
205
+ const resultingPrice = underlyingMark * (1 + impliedChange / 100);
206
+ return {
207
+ actionToCover,
208
+ sharesToCover: Math.abs(sharesNeededToCoverFloat),
209
+ impliedMoveToCover: impliedChange,
210
+ resultingSpotToCover: resultingPrice,
211
+ };
212
+ }
@@ -0,0 +1,29 @@
1
+ import { BlackScholesParams, Greeks } from '../types';
2
+ /**
3
+ * Calculate all Greeks for an option
4
+ *
5
+ * @param params - Black-Scholes parameters
6
+ * @returns All Greeks (delta, gamma, theta, vega, rho)
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const greeks = calculateGreeks({
11
+ * spot: 100,
12
+ * strike: 105,
13
+ * timeToExpiry: 0.25,
14
+ * volatility: 0.20,
15
+ * riskFreeRate: 0.05,
16
+ * optionType: 'call'
17
+ * });
18
+ * console.log('Delta:', greeks.delta);
19
+ * ```
20
+ */
21
+ export declare function calculateGreeks(params: BlackScholesParams): Greeks;
22
+ /**
23
+ * Calculate delta only (optimized)
24
+ */
25
+ export declare function calculateDelta(params: BlackScholesParams): number;
26
+ /**
27
+ * Calculate gamma only (optimized)
28
+ */
29
+ export declare function calculateGamma(params: BlackScholesParams): number;
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.calculateGreeks = calculateGreeks;
4
+ exports.calculateDelta = calculateDelta;
5
+ exports.calculateGamma = calculateGamma;
6
+ const statistics_1 = require("../utils/statistics");
7
+ /**
8
+ * Calculate all Greeks for an option
9
+ *
10
+ * @param params - Black-Scholes parameters
11
+ * @returns All Greeks (delta, gamma, theta, vega, rho)
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * const greeks = calculateGreeks({
16
+ * spot: 100,
17
+ * strike: 105,
18
+ * timeToExpiry: 0.25,
19
+ * volatility: 0.20,
20
+ * riskFreeRate: 0.05,
21
+ * optionType: 'call'
22
+ * });
23
+ * console.log('Delta:', greeks.delta);
24
+ * ```
25
+ */
26
+ function calculateGreeks(params) {
27
+ const { spot, strike, timeToExpiry, volatility, riskFreeRate, optionType, dividendYield = 0, } = params;
28
+ // Handle edge case
29
+ if (timeToExpiry <= 0) {
30
+ return {
31
+ delta: 0,
32
+ gamma: 0,
33
+ theta: 0,
34
+ vega: 0,
35
+ rho: 0,
36
+ };
37
+ }
38
+ const sqrtT = Math.sqrt(timeToExpiry);
39
+ const d1 = (Math.log(spot / strike) +
40
+ (riskFreeRate - dividendYield + (volatility ** 2) / 2) * timeToExpiry) /
41
+ (volatility * sqrtT);
42
+ const d2 = d1 - volatility * sqrtT;
43
+ const Nd1 = (0, statistics_1.cumulativeNormalDistribution)(d1);
44
+ const Nd2 = (0, statistics_1.cumulativeNormalDistribution)(d2);
45
+ const nd1 = (0, statistics_1.normalPDF)(d1);
46
+ // Delta
47
+ const delta = optionType === 'call'
48
+ ? Math.exp(-dividendYield * timeToExpiry) * Nd1
49
+ : -Math.exp(-dividendYield * timeToExpiry) * (0, statistics_1.cumulativeNormalDistribution)(-d1);
50
+ // Gamma (same for calls and puts)
51
+ const gamma = (Math.exp(-dividendYield * timeToExpiry) * nd1) / (spot * volatility * sqrtT);
52
+ // Theta (per day, so divide by 365)
53
+ const theta = optionType === 'call'
54
+ ? (-(spot * nd1 * volatility * Math.exp(-dividendYield * timeToExpiry)) /
55
+ (2 * sqrtT) -
56
+ riskFreeRate * strike * Math.exp(-riskFreeRate * timeToExpiry) * Nd2 +
57
+ dividendYield * spot * Math.exp(-dividendYield * timeToExpiry) * Nd1) /
58
+ 365
59
+ : (-(spot * nd1 * volatility * Math.exp(-dividendYield * timeToExpiry)) /
60
+ (2 * sqrtT) +
61
+ riskFreeRate * strike * Math.exp(-riskFreeRate * timeToExpiry) * (0, statistics_1.cumulativeNormalDistribution)(-d2) -
62
+ dividendYield * spot * Math.exp(-dividendYield * timeToExpiry) * (0, statistics_1.cumulativeNormalDistribution)(-d1)) /
63
+ 365;
64
+ // Vega (per 1% change in volatility, so divide by 100)
65
+ const vega = (spot * Math.exp(-dividendYield * timeToExpiry) * nd1 * sqrtT) / 100;
66
+ // Rho (per 1% change in interest rate, so divide by 100)
67
+ const rho = optionType === 'call'
68
+ ? (strike * timeToExpiry * Math.exp(-riskFreeRate * timeToExpiry) * Nd2) / 100
69
+ : (-strike * timeToExpiry * Math.exp(-riskFreeRate * timeToExpiry) * (0, statistics_1.cumulativeNormalDistribution)(-d2)) /
70
+ 100;
71
+ return {
72
+ delta,
73
+ gamma,
74
+ theta,
75
+ vega,
76
+ rho,
77
+ };
78
+ }
79
+ /**
80
+ * Calculate delta only (optimized)
81
+ */
82
+ function calculateDelta(params) {
83
+ const { spot, strike, timeToExpiry, volatility, riskFreeRate, optionType, dividendYield = 0 } = params;
84
+ if (timeToExpiry <= 0)
85
+ return 0;
86
+ const sqrtT = Math.sqrt(timeToExpiry);
87
+ const d1 = (Math.log(spot / strike) +
88
+ (riskFreeRate - dividendYield + (volatility ** 2) / 2) * timeToExpiry) /
89
+ (volatility * sqrtT);
90
+ return optionType === 'call'
91
+ ? Math.exp(-dividendYield * timeToExpiry) * (0, statistics_1.cumulativeNormalDistribution)(d1)
92
+ : -Math.exp(-dividendYield * timeToExpiry) * (0, statistics_1.cumulativeNormalDistribution)(-d1);
93
+ }
94
+ /**
95
+ * Calculate gamma only (optimized)
96
+ */
97
+ function calculateGamma(params) {
98
+ const { spot, strike, timeToExpiry, volatility, riskFreeRate, dividendYield = 0 } = params;
99
+ if (timeToExpiry <= 0)
100
+ return 0;
101
+ const sqrtT = Math.sqrt(timeToExpiry);
102
+ const d1 = (Math.log(spot / strike) +
103
+ (riskFreeRate - dividendYield + (volatility ** 2) / 2) * timeToExpiry) /
104
+ (volatility * sqrtT);
105
+ const nd1 = (0, statistics_1.normalPDF)(d1);
106
+ return (Math.exp(-dividendYield * timeToExpiry) * nd1) / (spot * volatility * sqrtT);
107
+ }
File without changes
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @fullstackcraftllc/floe - Options Analytics Library
3
+ *
4
+ * A comprehensive TypeScript library for options pricing, Greeks calculation,
5
+ * and dealer exposure analysis across multiple brokers.
6
+ */
7
+ export * from './types';
8
+ export { blackScholes, calculateGreeks, calculateImpliedVolatility, getMillisecondsToExpiration, getTimeToExpirationInYears, } from './blackscholes';
9
+ export { getIVSurfaces, getIVForStrike, } from './volatility';
10
+ export { smoothTotalVarianceSmile, } from './volatility/smoothing';
11
+ export { calculateGammaVannaCharmExposures, calculateSharesNeededToCover, } from './exposure';
12
+ export { cumulativeNormalDistribution, normalPDF, } from './utils/statistics';
13
+ export { genericAdapter, schwabAdapter, ibkrAdapter, tdaAdapter, brokerAdapters, getAdapter, createOptionChain, } from './adapters';