tradeblocks-mcp 3.0.1 → 3.0.2

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,295 @@
1
+ // src/utils/iv-solver-worker.ts
2
+ import { parentPort } from "node:worker_threads";
3
+
4
+ // src/utils/black-scholes.ts
5
+ var BACHELIER_DTE_THRESHOLD = 0.1;
6
+ function pdf(x) {
7
+ return Math.exp(-0.5 * x * x) / Math.sqrt(2 * Math.PI);
8
+ }
9
+ function cdf(x) {
10
+ if (x < -10) return 0;
11
+ if (x > 10) return 1;
12
+ const sign = x < 0 ? -1 : 1;
13
+ const absX = Math.abs(x);
14
+ const p = 0.2316419;
15
+ const b1 = 0.31938153;
16
+ const b2 = -0.356563782;
17
+ const b3 = 1.781477937;
18
+ const b4 = -1.821255978;
19
+ const b5 = 1.330274429;
20
+ const t = 1 / (1 + p * absX);
21
+ const t2 = t * t;
22
+ const t3 = t2 * t;
23
+ const t4 = t3 * t;
24
+ const t5 = t4 * t;
25
+ const poly = b1 * t + b2 * t2 + b3 * t3 + b4 * t4 + b5 * t5;
26
+ const result = 1 - pdf(absX) * poly;
27
+ return sign === 1 ? result : 1 - result;
28
+ }
29
+ function d1d2(S, K, T, r, q, sigma) {
30
+ const sqrtT = Math.sqrt(T);
31
+ const d1 = (Math.log(S / K) + (r - q + 0.5 * sigma * sigma) * T) / (sigma * sqrtT);
32
+ const d2 = d1 - sigma * sqrtT;
33
+ return { d1, d2 };
34
+ }
35
+ function bsPrice(type, S, K, T, r, q, sigma) {
36
+ if (T <= 0) {
37
+ return type === "call" ? Math.max(S - K, 0) : Math.max(K - S, 0);
38
+ }
39
+ if (sigma <= 0) {
40
+ const forward = S * Math.exp((r - q) * T);
41
+ if (type === "call") {
42
+ return Math.max(forward - K, 0) * Math.exp(-r * T);
43
+ } else {
44
+ return Math.max(K - forward, 0) * Math.exp(-r * T);
45
+ }
46
+ }
47
+ const { d1, d2 } = d1d2(S, K, T, r, q, sigma);
48
+ if (type === "call") {
49
+ return S * Math.exp(-q * T) * cdf(d1) - K * Math.exp(-r * T) * cdf(d2);
50
+ } else {
51
+ return K * Math.exp(-r * T) * cdf(-d2) - S * Math.exp(-q * T) * cdf(-d1);
52
+ }
53
+ }
54
+ function bsDelta(type, S, K, T, r, q, sigma) {
55
+ if (T <= 0 || sigma <= 0) {
56
+ if (type === "call") return S > K ? 1 : 0;
57
+ return S < K ? -1 : 0;
58
+ }
59
+ const { d1 } = d1d2(S, K, T, r, q, sigma);
60
+ const eqT = Math.exp(-q * T);
61
+ if (type === "call") {
62
+ return cdf(d1) * eqT;
63
+ } else {
64
+ return (cdf(d1) - 1) * eqT;
65
+ }
66
+ }
67
+ function bsGamma(S, K, T, r, q, sigma) {
68
+ if (T <= 0 || sigma <= 0) return 0;
69
+ const { d1 } = d1d2(S, K, T, r, q, sigma);
70
+ return pdf(d1) * Math.exp(-q * T) / (S * sigma * Math.sqrt(T));
71
+ }
72
+ function bsTheta(type, S, K, T, r, q, sigma) {
73
+ if (T <= 0 || sigma <= 0) return 0;
74
+ const { d1, d2 } = d1d2(S, K, T, r, q, sigma);
75
+ const sqrtT = Math.sqrt(T);
76
+ const eqT = Math.exp(-q * T);
77
+ const erT = Math.exp(-r * T);
78
+ const term1 = -(S * eqT * pdf(d1) * sigma) / (2 * sqrtT);
79
+ if (type === "call") {
80
+ const term2 = q * S * eqT * cdf(d1);
81
+ const term3 = -r * K * erT * cdf(d2);
82
+ return (term1 - term2 - term3) / 365;
83
+ } else {
84
+ const term2 = q * S * eqT * cdf(-d1);
85
+ const term3 = -r * K * erT * cdf(-d2);
86
+ return (term1 + term2 + term3) / 365;
87
+ }
88
+ }
89
+ function bsVega(S, K, T, r, q, sigma) {
90
+ if (T <= 0 || sigma <= 0) return 0;
91
+ const { d1 } = d1d2(S, K, T, r, q, sigma);
92
+ return S * Math.exp(-q * T) * pdf(d1) * Math.sqrt(T) / 100;
93
+ }
94
+ function solveIV(type, marketPrice, S, K, T, r, q, maxIter = 100, tolerance = 1e-6) {
95
+ if (marketPrice <= 0 || T <= 0) return null;
96
+ let sigma = 0.3;
97
+ let lo = 1e-3;
98
+ let hi = 5;
99
+ for (let i = 0; i < maxIter; i++) {
100
+ const price = bsPrice(type, S, K, T, r, q, sigma);
101
+ const diff = price - marketPrice;
102
+ if (Math.abs(diff) < tolerance) {
103
+ return sigma;
104
+ }
105
+ const { d1 } = d1d2(S, K, T, r, q, sigma);
106
+ const rawVega = S * Math.exp(-q * T) * pdf(d1) * Math.sqrt(T);
107
+ if (rawVega < 1e-10) {
108
+ const mid = (lo + hi) / 2;
109
+ if (diff > 0) {
110
+ hi = sigma;
111
+ } else {
112
+ lo = sigma;
113
+ }
114
+ sigma = mid;
115
+ } else {
116
+ const newSigma = sigma - diff / rawVega;
117
+ if (newSigma <= 0 || newSigma > 10) {
118
+ if (diff > 0) {
119
+ hi = sigma;
120
+ } else {
121
+ lo = sigma;
122
+ }
123
+ sigma = (lo + hi) / 2;
124
+ } else {
125
+ sigma = newSigma;
126
+ }
127
+ }
128
+ }
129
+ return null;
130
+ }
131
+ function bachelierPrice(type, S, K, T, r, q, sigma_n) {
132
+ if (T <= 0) return type === "call" ? Math.max(S - K, 0) : Math.max(K - S, 0);
133
+ if (sigma_n <= 0) {
134
+ const forward2 = S * Math.exp((r - q) * T);
135
+ return Math.exp(-r * T) * (type === "call" ? Math.max(forward2 - K, 0) : Math.max(K - forward2, 0));
136
+ }
137
+ const forward = S * Math.exp((r - q) * T);
138
+ const sqrtT = Math.sqrt(T);
139
+ const d = (forward - K) / (sigma_n * sqrtT);
140
+ const discount = Math.exp(-r * T);
141
+ if (type === "call") {
142
+ return discount * ((forward - K) * cdf(d) + sigma_n * sqrtT * pdf(d));
143
+ } else {
144
+ return discount * ((K - forward) * cdf(-d) + sigma_n * sqrtT * pdf(d));
145
+ }
146
+ }
147
+ function bachelierDelta(type, S, K, T, r, q, sigma_n) {
148
+ if (T <= 0 || sigma_n <= 0) {
149
+ if (type === "call") return S > K ? 1 : 0;
150
+ return S < K ? -1 : 0;
151
+ }
152
+ const forward = S * Math.exp((r - q) * T);
153
+ const d = (forward - K) / (sigma_n * Math.sqrt(T));
154
+ const discount = Math.exp(-r * T);
155
+ return type === "call" ? discount * cdf(d) : -discount * cdf(-d);
156
+ }
157
+ function bachelierGamma(S, K, T, r, q, sigma_n) {
158
+ if (T <= 0 || sigma_n <= 0) return 0;
159
+ const forward = S * Math.exp((r - q) * T);
160
+ const sqrtT = Math.sqrt(T);
161
+ const d = (forward - K) / (sigma_n * sqrtT);
162
+ return Math.exp(-r * T) * pdf(d) / (sigma_n * sqrtT);
163
+ }
164
+ function bachelierTheta(type, S, K, T, r, q, sigma_n) {
165
+ if (T <= 0 || sigma_n <= 0) return 0;
166
+ const forward = S * Math.exp((r - q) * T);
167
+ const sqrtT = Math.sqrt(T);
168
+ const d = (forward - K) / (sigma_n * sqrtT);
169
+ const discount = Math.exp(-r * T);
170
+ const price = bachelierPrice(type, S, K, T, r, q, sigma_n);
171
+ const annualTheta = -discount * sigma_n * pdf(d) / (2 * sqrtT) + r * price;
172
+ return annualTheta / 365;
173
+ }
174
+ function bachelierVega(S, K, T, r, q, sigma_n) {
175
+ if (T <= 0 || sigma_n <= 0) return 0;
176
+ const forward = S * Math.exp((r - q) * T);
177
+ const d = (forward - K) / (sigma_n * Math.sqrt(T));
178
+ return Math.exp(-r * T) * Math.sqrt(T) * pdf(d) / 100;
179
+ }
180
+ function solveNormalIV(type, marketPrice, S, K, T, r, q, maxIter = 100, tolerance = 1e-6) {
181
+ if (marketPrice <= 0 || T <= 0) return null;
182
+ let sigma_n = marketPrice / Math.sqrt(T / (2 * Math.PI));
183
+ sigma_n = Math.max(sigma_n, 1);
184
+ let lo = 0.01;
185
+ let hi = 5e4;
186
+ for (let i = 0; i < maxIter; i++) {
187
+ const price = bachelierPrice(type, S, K, T, r, q, sigma_n);
188
+ const diff = price - marketPrice;
189
+ if (Math.abs(diff) < tolerance) return sigma_n;
190
+ const forward = S * Math.exp((r - q) * T);
191
+ const d = (forward - K) / (sigma_n * Math.sqrt(T));
192
+ const rawVega = Math.exp(-r * T) * Math.sqrt(T) * pdf(d);
193
+ if (rawVega < 1e-10) {
194
+ if (diff > 0) {
195
+ hi = sigma_n;
196
+ } else {
197
+ lo = sigma_n;
198
+ }
199
+ sigma_n = (lo + hi) / 2;
200
+ } else {
201
+ const newSigma = sigma_n - diff / rawVega;
202
+ if (newSigma <= 0 || newSigma > 1e5) {
203
+ if (diff > 0) {
204
+ hi = sigma_n;
205
+ } else {
206
+ lo = sigma_n;
207
+ }
208
+ sigma_n = (lo + hi) / 2;
209
+ } else {
210
+ sigma_n = newSigma;
211
+ }
212
+ }
213
+ }
214
+ return null;
215
+ }
216
+ function computeLegGreeks(optionPrice, underlyingPrice, strike, dte, type, riskFreeRate, dividendYield) {
217
+ const T = dte / 365;
218
+ const bsType = type === "C" ? "call" : "put";
219
+ const nullResult = { delta: null, gamma: null, theta: null, vega: null, iv: null };
220
+ if (dte < BACHELIER_DTE_THRESHOLD) {
221
+ const iv2 = solveNormalIV(bsType, optionPrice, underlyingPrice, strike, T, riskFreeRate, dividendYield);
222
+ if (iv2 === null) return nullResult;
223
+ return {
224
+ delta: bachelierDelta(bsType, underlyingPrice, strike, T, riskFreeRate, dividendYield, iv2),
225
+ gamma: bachelierGamma(underlyingPrice, strike, T, riskFreeRate, dividendYield, iv2),
226
+ theta: bachelierTheta(bsType, underlyingPrice, strike, T, riskFreeRate, dividendYield, iv2),
227
+ vega: bachelierVega(underlyingPrice, strike, T, riskFreeRate, dividendYield, iv2),
228
+ iv: iv2,
229
+ model: "bachelier"
230
+ };
231
+ }
232
+ const iv = solveIV(bsType, optionPrice, underlyingPrice, strike, T, riskFreeRate, dividendYield);
233
+ if (iv === null) return nullResult;
234
+ return {
235
+ delta: bsDelta(bsType, underlyingPrice, strike, T, riskFreeRate, dividendYield, iv),
236
+ gamma: bsGamma(underlyingPrice, strike, T, riskFreeRate, dividendYield, iv),
237
+ theta: bsTheta(bsType, underlyingPrice, strike, T, riskFreeRate, dividendYield, iv),
238
+ vega: bsVega(underlyingPrice, strike, T, riskFreeRate, dividendYield, iv),
239
+ iv,
240
+ model: "bs"
241
+ };
242
+ }
243
+
244
+ // src/utils/iv-solver-worker.ts
245
+ function isFiniteNumber(value) {
246
+ return typeof value === "number" && Number.isFinite(value);
247
+ }
248
+ function solveIvBatch(req) {
249
+ const { id, count } = req;
250
+ const delta = new Float64Array(count);
251
+ const gamma = new Float64Array(count);
252
+ const theta = new Float64Array(count);
253
+ const vega = new Float64Array(count);
254
+ const iv = new Float64Array(count);
255
+ const ok = new Uint8Array(count);
256
+ for (let i = 0; i < count; i++) {
257
+ const result = computeLegGreeks(
258
+ req.optionPrice[i],
259
+ req.underlyingPrice[i],
260
+ req.strike[i],
261
+ req.dte[i],
262
+ req.type[i] === 0 ? "C" : "P",
263
+ req.riskFreeRate[i],
264
+ req.dividendYield[i]
265
+ );
266
+ if (isFiniteNumber(result.delta) && isFiniteNumber(result.gamma) && isFiniteNumber(result.theta) && isFiniteNumber(result.vega) && isFiniteNumber(result.iv)) {
267
+ delta[i] = result.delta;
268
+ gamma[i] = result.gamma;
269
+ theta[i] = result.theta;
270
+ vega[i] = result.vega;
271
+ iv[i] = result.iv;
272
+ ok[i] = 1;
273
+ } else {
274
+ ok[i] = 0;
275
+ }
276
+ }
277
+ return { id, count, delta, gamma, theta, vega, iv, ok };
278
+ }
279
+ if (parentPort) {
280
+ const port = parentPort;
281
+ port.on("message", (req) => {
282
+ const reply = solveIvBatch(req);
283
+ port.postMessage(reply, [
284
+ reply.delta.buffer,
285
+ reply.gamma.buffer,
286
+ reply.theta.buffer,
287
+ reply.vega.buffer,
288
+ reply.iv.buffer,
289
+ reply.ok.buffer
290
+ ]);
291
+ });
292
+ }
293
+ export {
294
+ solveIvBatch
295
+ };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  _resetProvider,
3
3
  getProvider
4
- } from "./chunk-CCITWAAI.js";
4
+ } from "./chunk-XXYOUIZY.js";
5
5
  import "./chunk-QTTR7AAW.js";
6
6
  import "./chunk-PRAYH3RT.js";
7
7
  import "./chunk-W2PP3LEH.js";
@@ -13,4 +13,4 @@ export {
13
13
  _resetProvider,
14
14
  getProvider
15
15
  };
16
- //# sourceMappingURL=market-provider-GGLA7ACC.js.map
16
+ //# sourceMappingURL=market-provider-VDRJUEF2.js.map
@@ -83,6 +83,7 @@ import {
83
83
  } from "./chunk-4BLCXNQ6.js";
84
84
  import {
85
85
  BACHELIER_DTE_THRESHOLD,
86
+ IvSolverPool,
86
87
  MASSIVE_BASE_URL,
87
88
  MASSIVE_MAX_LIMIT,
88
89
  MASSIVE_MAX_PAGES,
@@ -100,6 +101,7 @@ import {
100
101
  ThetaMddsClient,
101
102
  _resetProvider,
102
103
  applyQuoteGreeks,
104
+ applyQuoteGreeksParallel,
103
105
  bachelierDelta,
104
106
  bachelierGamma,
105
107
  bachelierPrice,
@@ -118,9 +120,11 @@ import {
118
120
  computeStrategyPnlPath,
119
121
  computeThetaQuoteMidGreekRow,
120
122
  decodeThetaResponseData,
123
+ destroySharedIvSolverPool,
121
124
  findNearestTimestamp,
122
125
  fromMassiveTicker,
123
126
  getProvider,
127
+ getSharedIvSolverPool,
124
128
  hasQuoteGreeks,
125
129
  indexHistoryEod,
126
130
  indexHistoryOhlc,
@@ -152,7 +156,7 @@ import {
152
156
  stockHistoryOhlc,
153
157
  thetaTimestampToEtMinute,
154
158
  toMassiveTicker
155
- } from "./chunk-CCITWAAI.js";
159
+ } from "./chunk-XXYOUIZY.js";
156
160
  import {
157
161
  PortfolioStatsCalculator,
158
162
  calculateCorrelationMatrix,
@@ -8663,7 +8667,7 @@ var MarketIngestor = class {
8663
8667
  underlyingPriceByTime.set(time, bar.open);
8664
8668
  }
8665
8669
  }
8666
- const stats = applyQuoteGreeks({
8670
+ const stats = await applyQuoteGreeksParallel({
8667
8671
  rows,
8668
8672
  getDate: (row) => row.timestamp.slice(0, 10),
8669
8673
  getTime: (row) => row.timestamp.slice(11, 16),
@@ -9654,6 +9658,7 @@ export {
9654
9658
  ENRICHED_FIELD_TYPES,
9655
9659
  EnrichedStore,
9656
9660
  EnrichmentWatermarksSchema,
9661
+ IvSolverPool,
9657
9662
  LEVERAGED_ETFS,
9658
9663
  MASSIVE_BASE_URL,
9659
9664
  MASSIVE_MAX_LIMIT,
@@ -9695,6 +9700,7 @@ export {
9695
9700
  analyzeStructureFitSchema,
9696
9701
  appendBackfillManifestLineDurable,
9697
9702
  applyQuoteGreeks,
9703
+ applyQuoteGreeksParallel,
9698
9704
  assessPrecision,
9699
9705
  bachelierDelta,
9700
9706
  bachelierGamma,
@@ -9770,6 +9776,7 @@ export {
9770
9776
  deleteProfileSchema,
9771
9777
  deleteSyncMetadataJson,
9772
9778
  describeReadParquetColumns,
9779
+ destroySharedIvSolverPool,
9773
9780
  detectCsvType,
9774
9781
  discoverCsvFiles,
9775
9782
  downgradeToReadOnly,
@@ -9806,6 +9813,7 @@ export {
9806
9813
  getProvider,
9807
9814
  getReadOnlyConnection,
9808
9815
  getResolvedProviderCapabilities,
9816
+ getSharedIvSolverPool,
9809
9817
  getStrategyProfileSchema,
9810
9818
  getSyncMetadataJson,
9811
9819
  groupBackfillTickersByGreekBand,