@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,171 @@
1
+ "use strict";
2
+ /**
3
+ * Volatility surface smoothing algorithms
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.smoothTotalVarianceSmile = smoothTotalVarianceSmile;
7
+ /**
8
+ * Smooth total variance smile using cubic spline interpolation and convexity enforcement
9
+ *
10
+ * @param strikes - Sorted array of strike prices
11
+ * @param ivs - Array of IVs as percentages (e.g., 20 = 20%)
12
+ * @param T - Time to expiration in years
13
+ * @returns Smoothed IVs as percentages
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const smoothed = smoothTotalVarianceSmile([90, 95, 100, 105, 110], [22, 20, 18, 20, 22], 0.25);
18
+ * ```
19
+ */
20
+ function smoothTotalVarianceSmile(strikes, ivs, T) {
21
+ const n = strikes.length;
22
+ if (n <= 2) {
23
+ return ivs; // Not enough points to smooth meaningfully
24
+ }
25
+ // Convert IV% → decimal and total variance
26
+ const w = new Array(n);
27
+ for (let i = 0; i < n; i++) {
28
+ const vol = ivs[i] / 100.0; // percent → decimal
29
+ w[i] = vol * vol * T;
30
+ }
31
+ // Step 1: cubic spline interpolation on w(K)
32
+ const spline = new CubicSpline(strikes, w);
33
+ // Step 2: evaluate spline at existing strikes (already sorted)
34
+ const smoothedW = new Array(n);
35
+ for (let i = 0; i < n; i++) {
36
+ smoothedW[i] = spline.eval(strikes[i]);
37
+ }
38
+ // Step 3: enforce convexity of total variance (simple projection)
39
+ enforceConvexity(strikes, smoothedW);
40
+ // Step 4: convert total variance back to IV (percent)
41
+ const smoothedIV = new Array(n);
42
+ for (let i = 0; i < n; i++) {
43
+ if (smoothedW[i] <= 0) {
44
+ smoothedIV[i] = ivs[i]; // fallback
45
+ }
46
+ else {
47
+ smoothedIV[i] = Math.sqrt(smoothedW[i] / T) * 100.0;
48
+ }
49
+ }
50
+ return smoothedIV;
51
+ }
52
+ /**
53
+ * Cubic spline interpolation
54
+ */
55
+ class CubicSpline {
56
+ constructor(x, y) {
57
+ const n = x.length;
58
+ this.x = x;
59
+ this.a = [...y];
60
+ this.b = new Array(n).fill(0);
61
+ this.c = new Array(n).fill(0);
62
+ this.d = new Array(n).fill(0);
63
+ const h = new Array(n - 1);
64
+ for (let i = 0; i < n - 1; i++) {
65
+ h[i] = x[i + 1] - x[i];
66
+ }
67
+ const alpha = new Array(n - 1).fill(0);
68
+ for (let i = 1; i < n - 1; i++) {
69
+ alpha[i] = (3 * (this.a[i + 1] - this.a[i])) / h[i] - (3 * (this.a[i] - this.a[i - 1])) / h[i - 1];
70
+ }
71
+ const l = new Array(n).fill(0);
72
+ const mu = new Array(n).fill(0);
73
+ const z = new Array(n).fill(0);
74
+ l[0] = 1;
75
+ mu[0] = 0;
76
+ z[0] = 0;
77
+ for (let i = 1; i < n - 1; i++) {
78
+ l[i] = 2 * (x[i + 1] - x[i - 1]) - h[i - 1] * mu[i - 1];
79
+ mu[i] = h[i] / l[i];
80
+ z[i] = (alpha[i] - h[i - 1] * z[i - 1]) / l[i];
81
+ }
82
+ l[n - 1] = 1;
83
+ z[n - 1] = 0;
84
+ this.c[n - 1] = 0;
85
+ for (let j = n - 2; j >= 0; j--) {
86
+ this.c[j] = z[j] - mu[j] * this.c[j + 1];
87
+ this.b[j] = (this.a[j + 1] - this.a[j]) / h[j] - (h[j] * (this.c[j + 1] + 2 * this.c[j])) / 3;
88
+ this.d[j] = (this.c[j + 1] - this.c[j]) / (3 * h[j]);
89
+ }
90
+ }
91
+ eval(x) {
92
+ // Find interval
93
+ const n = this.x.length;
94
+ let i = this.findInterval(x, n);
95
+ if (i > 0 && i >= n - 1) {
96
+ i = n - 2;
97
+ }
98
+ const dx = x - this.x[i];
99
+ return this.a[i] + this.b[i] * dx + this.c[i] * dx * dx + this.d[i] * dx * dx * dx;
100
+ }
101
+ findInterval(x, n) {
102
+ // Binary search
103
+ let left = 0;
104
+ let right = n - 1;
105
+ while (left < right - 1) {
106
+ const mid = Math.floor((left + right) / 2);
107
+ if (this.x[mid] <= x) {
108
+ left = mid;
109
+ }
110
+ else {
111
+ right = mid;
112
+ }
113
+ }
114
+ return left;
115
+ }
116
+ }
117
+ /**
118
+ * Enforce convexity of total variance using convex hull approach
119
+ *
120
+ * @param x - Strike prices
121
+ * @param w - Total variance values (modified in place)
122
+ */
123
+ function enforceConvexity(x, w) {
124
+ const n = w.length;
125
+ if (n < 3) {
126
+ return;
127
+ }
128
+ // Build the lower convex hull of (x, w) points
129
+ // This guarantees convexity and runs in O(n)
130
+ const hull = [];
131
+ for (let i = 0; i < n; i++) {
132
+ const p = { x: x[i], w: w[i] };
133
+ // Remove points that would break convexity
134
+ while (hull.length >= 2) {
135
+ const h1 = hull[hull.length - 1];
136
+ const h2 = hull[hull.length - 2];
137
+ // Cross product to check if we make a left turn (convex)
138
+ // (h1 - h2) x (p - h2) should be >= 0 for convexity
139
+ const cross = (h1.x - h2.x) * (p.w - h2.w) - (h1.w - h2.w) * (p.x - h2.x);
140
+ if (cross >= 0) {
141
+ break; // convex, keep h1
142
+ }
143
+ hull.pop(); // remove h1, it breaks convexity
144
+ }
145
+ hull.push(p);
146
+ }
147
+ // Now interpolate the hull values back to original x positions
148
+ let hullIdx = 0;
149
+ for (let i = 0; i < n; i++) {
150
+ // Find the hull segment containing x[i]
151
+ while (hullIdx < hull.length - 1 && hull[hullIdx + 1].x < x[i]) {
152
+ hullIdx++;
153
+ }
154
+ if (hullIdx >= hull.length - 1) {
155
+ hullIdx = hull.length - 2;
156
+ }
157
+ if (hullIdx < 0) {
158
+ hullIdx = 0;
159
+ }
160
+ // Linear interpolation on the hull
161
+ const h1 = hull[hullIdx];
162
+ const h2 = hull[hullIdx + 1];
163
+ if (h2.x === h1.x) {
164
+ w[i] = h1.w;
165
+ }
166
+ else {
167
+ const t = (x[i] - h1.x) / (h2.x - h1.x);
168
+ w[i] = h1.w + t * (h2.w - h1.w);
169
+ }
170
+ }
171
+ }
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@fullstackcraftllc/floe",
3
+ "version": "0.0.1",
4
+ "description": "Production-ready options analytics toolkit. Normalize broker data structures and calculate Black-Scholes, Greeks, and GEX with a clean, type-safe API. Built for trading platforms and fintech applications.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "test": "jest",
10
+ "prepublishOnly": "npm run build",
11
+ "type-check": "tsc --noEmit"
12
+ },
13
+ "keywords": [
14
+ "options",
15
+ "black-scholes",
16
+ "greeks",
17
+ "gamma",
18
+ "delta",
19
+ "vanna",
20
+ "charm",
21
+ "dealer-exposure",
22
+ "gex",
23
+ "trading",
24
+ "finance",
25
+ "typescript"
26
+ ],
27
+ "author": {
28
+ "name": "Full Stack Craft LLC",
29
+ "email": "hi@fullstackcraft.com",
30
+ "url": "https://fullstackcraft.com"
31
+ },
32
+ "license": "SEE LICENSE IN LICENSE.md",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/FullStackCraft/floe.git"
36
+ },
37
+ "bugs": {
38
+ "url": "https://github.com/FullStackCraft/floe/issues"
39
+ },
40
+ "homepage": "https://github.com/FullStackCraft/floe#readme",
41
+ "devDependencies": {
42
+ "@types/jest": "^29.5.0",
43
+ "@types/node": "^20.0.0",
44
+ "jest": "^29.5.0",
45
+ "ts-jest": "^29.1.0",
46
+ "typescript": "^5.0.0"
47
+ },
48
+ "files": [
49
+ "dist",
50
+ "README.md",
51
+ "LICENSE.md",
52
+ "LICENSE-MIT",
53
+ "LICENSE-COMMERCIAL"
54
+ ]
55
+ }