tradeblocks-mcp 3.0.2 → 3.3.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.
Files changed (218) hide show
  1. package/README.md +85 -80
  2. package/dist/{chunk-LDKTV7GW.js → chunk-27S67XW3.js} +24 -52
  3. package/dist/chunk-27S67XW3.js.map +1 -0
  4. package/dist/{chunk-FGZH632F.js → chunk-2E63THNI.js} +13 -11
  5. package/dist/chunk-2E63THNI.js.map +1 -0
  6. package/dist/{chunk-QTTR7AAW.js → chunk-2I3S2ZLT.js} +325 -84
  7. package/dist/chunk-2I3S2ZLT.js.map +1 -0
  8. package/dist/{chunk-4BLCXNQ6.js → chunk-4HZLVUOZ.js} +179 -183
  9. package/dist/chunk-4HZLVUOZ.js.map +1 -0
  10. package/dist/{chunk-XXYOUIZY.js → chunk-NWNSKALN.js} +63 -80
  11. package/dist/chunk-NWNSKALN.js.map +1 -0
  12. package/dist/{chunk-PRAYH3RT.js → chunk-WNTYA7ER.js} +29 -12
  13. package/dist/chunk-WNTYA7ER.js.map +1 -0
  14. package/dist/{chunk-BKQ4PM4Y.js → chunk-YZA4RS76.js} +24 -18
  15. package/dist/chunk-YZA4RS76.js.map +1 -0
  16. package/dist/{chunk-W2PP3LEH.js → chunk-ZTJXC3LS.js} +17 -8
  17. package/dist/chunk-ZTJXC3LS.js.map +1 -0
  18. package/dist/daily-log-processor-MZW2XBZY.js +9 -0
  19. package/dist/{daily-logs-store-D3QC2XPV.js → daily-logs-store-3C3OTGPK.js} +2 -2
  20. package/dist/iv-solver-worker.js +9 -1
  21. package/dist/market-provider-6U33TQUT.js +16 -0
  22. package/dist/{proto-3HZTCWK4.js → proto-V23GIZG2.js} +2 -2
  23. package/dist/{sync-PO4IPCYV.js → sync-3UBC37VW.js} +7 -7
  24. package/dist/test-exports.js +876 -483
  25. package/dist/test-exports.js.map +1 -1
  26. package/dist/trade-processor-DKDCWGKD.js +9 -0
  27. package/dist/{trades-store-LOL3FQSF.js → trades-store-R3NL25T2.js} +2 -2
  28. package/package.json +2 -6
  29. package/server/{chunk-CSDVJPBB.js → chunk-536NSFED.js} +29 -12
  30. package/server/chunk-536NSFED.js.map +1 -0
  31. package/server/{chunk-WA5AAPCH.js → chunk-A3UKD64A.js} +17 -8
  32. package/server/chunk-A3UKD64A.js.map +1 -0
  33. package/server/{chunk-PNKG7RY7.js → chunk-OMUDNJBJ.js} +63 -80
  34. package/server/chunk-OMUDNJBJ.js.map +1 -0
  35. package/server/{chunk-72GKJE2U.js → chunk-RJDJHZ5Y.js} +934 -335
  36. package/server/chunk-RJDJHZ5Y.js.map +1 -0
  37. package/server/{chunk-NZO6PT64.js → chunk-RM4B2VKS.js} +167 -177
  38. package/server/chunk-RM4B2VKS.js.map +1 -0
  39. package/server/{chunk-5EBXHT6C.js → chunk-SY6GDNVI.js} +24 -18
  40. package/server/chunk-SY6GDNVI.js.map +1 -0
  41. package/server/{chunk-FBNDMCT5.js → chunk-T66KH2XH.js} +13 -11
  42. package/server/chunk-T66KH2XH.js.map +1 -0
  43. package/server/{chunk-NRFXAJF7.js → chunk-W5E7FHC4.js} +24 -52
  44. package/server/chunk-W5E7FHC4.js.map +1 -0
  45. package/server/{config-6IZXEFEX.js → config-DK7KOMNL.js} +1 -1
  46. package/server/config-DK7KOMNL.js.map +1 -0
  47. package/server/daily-log-processor-B2VPU2FQ.js +10 -0
  48. package/server/{daily-logs-store-NU7M4L5C.js → daily-logs-store-YFNXTB7J.js} +2 -2
  49. package/server/http-server.js +2 -5
  50. package/server/index.js +2497 -2029
  51. package/server/index.js.map +1 -1
  52. package/server/iv-solver-worker.js +9 -1
  53. package/server/market-provider-L56RFHAC.js +17 -0
  54. package/server/{proto-DWRZJO4E.js → proto-YZ4TLX2N.js} +2 -2
  55. package/server/{sync-QFI5L7S7.js → sync-CENKDN53.js} +7 -7
  56. package/server/trade-processor-3PI4LHZI.js +10 -0
  57. package/server/{trades-store-VY26MWER.js → trades-store-RTTEYMXH.js} +2 -2
  58. package/src/auth/clients-store.ts +4 -4
  59. package/src/auth/code-store.ts +1 -1
  60. package/src/auth/config.ts +11 -12
  61. package/src/auth/login-page.ts +8 -10
  62. package/src/auth/provider.ts +35 -30
  63. package/src/auth/token.ts +17 -15
  64. package/src/db/backtest-schemas.ts +38 -8
  65. package/src/db/connection.ts +107 -40
  66. package/src/db/data-root.ts +22 -0
  67. package/src/db/index.ts +37 -5
  68. package/src/db/json-adapters.ts +22 -31
  69. package/src/db/json-migration.ts +11 -15
  70. package/src/db/json-store.ts +5 -3
  71. package/src/db/market-datasets.ts +48 -15
  72. package/src/db/market-schemas.ts +11 -5
  73. package/src/db/market-views.ts +119 -32
  74. package/src/db/parquet-writer.ts +7 -7
  75. package/src/db/profile-schemas.ts +39 -22
  76. package/src/db/schemas.ts +2 -2
  77. package/src/http-server.ts +7 -12
  78. package/src/index.ts +8 -9
  79. package/src/market/ingestor/index.ts +1 -4
  80. package/src/market/ingestor/market-ingestor.ts +140 -67
  81. package/src/market/ingestor/types.ts +1 -3
  82. package/src/market/stores/chain-sql.ts +2 -8
  83. package/src/market/stores/chain-store.ts +1 -4
  84. package/src/market/stores/duckdb-chain-store.ts +3 -14
  85. package/src/market/stores/duckdb-enriched-store.ts +3 -13
  86. package/src/market/stores/duckdb-quote-store.ts +10 -27
  87. package/src/market/stores/duckdb-spot-store.ts +4 -20
  88. package/src/market/stores/enriched-sql.ts +3 -9
  89. package/src/market/stores/enriched-store.ts +2 -2
  90. package/src/market/stores/parquet-chain-store.ts +5 -22
  91. package/src/market/stores/parquet-enriched-store.ts +4 -16
  92. package/src/market/stores/parquet-oi-daily-store.ts +3 -14
  93. package/src/market/stores/parquet-quote-store.ts +9 -29
  94. package/src/market/stores/parquet-spot-store.ts +14 -33
  95. package/src/market/stores/quote-store.ts +2 -10
  96. package/src/market/stores/spot-sql.ts +3 -15
  97. package/src/market/stores/spot-store.ts +1 -1
  98. package/src/market/tickers/defaults.json +6 -6
  99. package/src/market/tickers/loader.ts +2 -7
  100. package/src/market/tickers/registry.ts +5 -15
  101. package/src/market/tickers/schemas.ts +2 -6
  102. package/src/models/strategy-profile.ts +39 -39
  103. package/src/sync/block-sync.ts +44 -65
  104. package/src/sync/index.ts +1 -4
  105. package/src/sync/metadata.ts +14 -20
  106. package/src/test-exports.ts +139 -123
  107. package/src/tools/analysis.ts +180 -159
  108. package/src/tools/batch-exit-analysis.ts +100 -59
  109. package/src/tools/blocks/analysis.ts +116 -101
  110. package/src/tools/blocks/comparison.ts +281 -364
  111. package/src/tools/blocks/core.ts +208 -253
  112. package/src/tools/blocks/health.ts +571 -563
  113. package/src/tools/blocks/index.ts +2 -0
  114. package/src/tools/blocks/paired-comparison.ts +425 -0
  115. package/src/tools/blocks/similarity.ts +316 -283
  116. package/src/tools/edge-decay.ts +124 -197
  117. package/src/tools/exit-analysis.ts +130 -77
  118. package/src/tools/greeks-attribution.ts +84 -35
  119. package/src/tools/guides.ts +4 -6
  120. package/src/tools/imports.ts +11 -14
  121. package/src/tools/market-data.ts +1067 -757
  122. package/src/tools/market-enrichment.ts +3 -3
  123. package/src/tools/market-fetch.ts +148 -67
  124. package/src/tools/market-imports.ts +12 -12
  125. package/src/tools/middleware/sync-middleware.ts +5 -6
  126. package/src/tools/performance.ts +185 -302
  127. package/src/tools/profile-analysis.ts +52 -66
  128. package/src/tools/profiles.ts +106 -69
  129. package/src/tools/regime-advisor.ts +20 -45
  130. package/src/tools/replay.ts +81 -77
  131. package/src/tools/reports/discrepancies.ts +298 -328
  132. package/src/tools/reports/fields.ts +7 -25
  133. package/src/tools/reports/helpers.ts +18 -49
  134. package/src/tools/reports/predictive.ts +27 -70
  135. package/src/tools/reports/slippage-trends.ts +315 -345
  136. package/src/tools/reports/slippage.ts +1 -4
  137. package/src/tools/reports/strategy-matches.ts +399 -441
  138. package/src/tools/schema.ts +43 -40
  139. package/src/tools/shared/filters.ts +3 -9
  140. package/src/tools/snapshot.ts +9 -30
  141. package/src/tools/sql.ts +15 -14
  142. package/src/tools/tickers.ts +1 -4
  143. package/src/utils/batch-exit-analysis.ts +31 -42
  144. package/src/utils/black-scholes.ts +39 -29
  145. package/src/utils/block-loader.ts +69 -83
  146. package/src/utils/calibration-probe.ts +3 -4
  147. package/src/utils/chain-loader.ts +3 -3
  148. package/src/utils/csv-discovery.ts +16 -22
  149. package/src/utils/data-quality.ts +24 -36
  150. package/src/utils/exit-triggers.ts +91 -96
  151. package/src/utils/field-timing.ts +94 -79
  152. package/src/utils/filter-predicates.ts +13 -9
  153. package/src/utils/flatfile-importer.ts +94 -64
  154. package/src/utils/greeks-decomposition.ts +152 -100
  155. package/src/utils/iv-solver-pool.ts +55 -25
  156. package/src/utils/iv-solver-worker.ts +5 -5
  157. package/src/utils/market-enricher.ts +528 -497
  158. package/src/utils/market-importer.ts +31 -12
  159. package/src/utils/market-provider.ts +21 -23
  160. package/src/utils/massive-tier.ts +5 -7
  161. package/src/utils/migrate-option-data-helpers.ts +2 -8
  162. package/src/utils/option-quote-greeks.ts +25 -31
  163. package/src/utils/option-time.ts +4 -8
  164. package/src/utils/output-formatter.ts +1 -4
  165. package/src/utils/provider-capabilities.ts +1 -4
  166. package/src/utils/providers/massive.ts +59 -93
  167. package/src/utils/providers/thetadata/backfill.ts +14 -23
  168. package/src/utils/providers/thetadata/client.ts +12 -8
  169. package/src/utils/providers/thetadata/decode.ts +2 -20
  170. package/src/utils/providers/thetadata/endpoints.ts +32 -40
  171. package/src/utils/providers/thetadata/join.ts +11 -10
  172. package/src/utils/providers/thetadata/proto.ts +12 -10
  173. package/src/utils/providers/thetadata/quote-mid-greeks.ts +5 -5
  174. package/src/utils/providers/thetadata.ts +11 -10
  175. package/src/utils/quote-enricher.ts +4 -4
  176. package/src/utils/quote-parquet-projection.ts +3 -11
  177. package/src/utils/sample-date-selector.ts +3 -5
  178. package/src/utils/schema-metadata.ts +102 -70
  179. package/src/utils/ticker.ts +5 -9
  180. package/src/utils/trade-replay.ts +77 -68
  181. package/dist/chunk-4BLCXNQ6.js.map +0 -1
  182. package/dist/chunk-BKQ4PM4Y.js.map +0 -1
  183. package/dist/chunk-FGZH632F.js.map +0 -1
  184. package/dist/chunk-LDKTV7GW.js.map +0 -1
  185. package/dist/chunk-PRAYH3RT.js.map +0 -1
  186. package/dist/chunk-QTTR7AAW.js.map +0 -1
  187. package/dist/chunk-W2PP3LEH.js.map +0 -1
  188. package/dist/chunk-XXYOUIZY.js.map +0 -1
  189. package/dist/daily-log-processor-6MWJ23JK.js +0 -9
  190. package/dist/market-provider-VDRJUEF2.js +0 -16
  191. package/dist/trade-processor-NHU4VWRX.js +0 -9
  192. package/manifest.json +0 -141
  193. package/server/chunk-5EBXHT6C.js.map +0 -1
  194. package/server/chunk-72GKJE2U.js.map +0 -1
  195. package/server/chunk-CSDVJPBB.js.map +0 -1
  196. package/server/chunk-FBNDMCT5.js.map +0 -1
  197. package/server/chunk-NRFXAJF7.js.map +0 -1
  198. package/server/chunk-NZO6PT64.js.map +0 -1
  199. package/server/chunk-PNKG7RY7.js.map +0 -1
  200. package/server/chunk-WA5AAPCH.js.map +0 -1
  201. package/server/config-6IZXEFEX.js.map +0 -1
  202. package/server/daily-log-processor-Y3PVSVBM.js +0 -10
  203. package/server/market-provider-VOYYVYWT.js +0 -17
  204. package/server/trade-processor-JWVS37KM.js +0 -10
  205. /package/dist/{daily-log-processor-6MWJ23JK.js.map → daily-log-processor-MZW2XBZY.js.map} +0 -0
  206. /package/dist/{daily-logs-store-D3QC2XPV.js.map → daily-logs-store-3C3OTGPK.js.map} +0 -0
  207. /package/dist/{market-provider-VDRJUEF2.js.map → market-provider-6U33TQUT.js.map} +0 -0
  208. /package/dist/{proto-3HZTCWK4.js.map → proto-V23GIZG2.js.map} +0 -0
  209. /package/dist/{sync-PO4IPCYV.js.map → sync-3UBC37VW.js.map} +0 -0
  210. /package/dist/{trade-processor-NHU4VWRX.js.map → trade-processor-DKDCWGKD.js.map} +0 -0
  211. /package/dist/{trades-store-LOL3FQSF.js.map → trades-store-R3NL25T2.js.map} +0 -0
  212. /package/server/{daily-log-processor-Y3PVSVBM.js.map → daily-log-processor-B2VPU2FQ.js.map} +0 -0
  213. /package/server/{daily-logs-store-NU7M4L5C.js.map → daily-logs-store-YFNXTB7J.js.map} +0 -0
  214. /package/server/{market-provider-VOYYVYWT.js.map → market-provider-L56RFHAC.js.map} +0 -0
  215. /package/server/{proto-DWRZJO4E.js.map → proto-YZ4TLX2N.js.map} +0 -0
  216. /package/server/{sync-QFI5L7S7.js.map → sync-CENKDN53.js.map} +0 -0
  217. /package/server/{trade-processor-JWVS37KM.js.map → trade-processor-3PI4LHZI.js.map} +0 -0
  218. /package/server/{trades-store-VY26MWER.js.map → trades-store-RTTEYMXH.js.map} +0 -0
@@ -95,9 +95,15 @@ export function validateColumnMapping(
95
95
 
96
96
  /** Parse CSV content into rows with header mapping. Strips UTF-8 BOM. */
97
97
  function parseCSV(content: string): { headers: string[]; rows: Record<string, string>[] } {
98
- const lines = content.replace(/^\uFEFF/, "").trim().split("\n");
98
+ const lines = content
99
+ .replace(/^\uFEFF/, "")
100
+ .trim()
101
+ .split("\n");
99
102
  if (lines.length < 2) return { headers: [], rows: [] };
100
- const headers = lines[0].trim().split(",").map((h) => h.trim());
103
+ const headers = lines[0]
104
+ .trim()
105
+ .split(",")
106
+ .map((h) => h.trim());
101
107
  const rows: Record<string, string>[] = [];
102
108
  for (let i = 1; i < lines.length; i++) {
103
109
  const line = lines[i].trim();
@@ -123,7 +129,9 @@ function parseFlexibleDate(value: string): string | null {
123
129
  if (!isNaN(numeric) && numeric > 1e8) {
124
130
  return new Date(numeric * 1000).toLocaleDateString("en-CA", {
125
131
  timeZone: "America/New_York",
126
- year: "numeric", month: "2-digit", day: "2-digit",
132
+ year: "numeric",
133
+ month: "2-digit",
134
+ day: "2-digit",
127
135
  });
128
136
  }
129
137
  if (/^\d{4}-\d{2}-\d{2}$/.test(value)) return value;
@@ -143,7 +151,9 @@ function parseFlexibleTime(value: string): string | null {
143
151
  const d = new Date(numeric * 1000);
144
152
  return d.toLocaleTimeString("en-US", {
145
153
  timeZone: "America/New_York",
146
- hour: "2-digit", minute: "2-digit", hour12: false,
154
+ hour: "2-digit",
155
+ minute: "2-digit",
156
+ hour12: false,
147
157
  });
148
158
  }
149
159
  if (/^\d{2}:\d{2}$/.test(value)) return value;
@@ -171,11 +181,17 @@ function applyColumnMapping(
171
181
  const rawValue = row[sourceCol] ?? "";
172
182
  if (schemaCol === "date") {
173
183
  const parsed = parseFlexibleDate(rawValue);
174
- if (parsed === null) { hasNullDate = true; break; }
184
+ if (parsed === null) {
185
+ hasNullDate = true;
186
+ break;
187
+ }
175
188
  mapped[schemaCol] = parsed;
176
189
  } else if (schemaCol === "time") {
177
190
  const parsed = parseFlexibleTime(rawValue);
178
- if (parsed === null) { hasNullDate = true; break; }
191
+ if (parsed === null) {
192
+ hasNullDate = true;
193
+ break;
194
+ }
179
195
  mapped[schemaCol] = parsed;
180
196
  } else {
181
197
  if (rawValue === "" || rawValue === "NaN" || rawValue === "NA") {
@@ -190,7 +206,9 @@ function applyColumnMapping(
190
206
  if (!("date" in mapped)) continue;
191
207
  // Auto-extract time from a Unix-timestamp date column when `time` is not mapped.
192
208
  if (!("time" in mapped)) {
193
- const dateSourceCol = Object.entries(columnMapping).find(([, schema]) => schema === "date")?.[0];
209
+ const dateSourceCol = Object.entries(columnMapping).find(
210
+ ([, schema]) => schema === "date",
211
+ )?.[0];
194
212
  if (dateSourceCol) {
195
213
  const rawDateValue = row[dateSourceCol] ?? "";
196
214
  const numericDate = Number(rawDateValue);
@@ -211,10 +229,7 @@ function applyColumnMapping(
211
229
  * Non-numeric values fall back to `0` so the spot store always receives well-
212
230
  * typed numbers — invalid rows are filtered upstream.
213
231
  */
214
- function coerceMappedRowToBar(
215
- row: Record<string, unknown>,
216
- ticker: string,
217
- ): BarRow | null {
232
+ function coerceMappedRowToBar(row: Record<string, unknown>, ticker: string): BarRow | null {
218
233
  const date = typeof row.date === "string" ? row.date : null;
219
234
  if (!date) return null;
220
235
  const time = typeof row.time === "string" ? row.time : "09:30";
@@ -408,7 +423,11 @@ export async function importFromDatabase(
408
423
  });
409
424
  bars = parseDatabaseRowsToBars(rawRows, normalizedTicker, columnMapping);
410
425
  } finally {
411
- try { await conn.run(`DETACH ${EXT_ALIAS}`); } catch { /* best-effort */ }
426
+ try {
427
+ await conn.run(`DETACH ${EXT_ALIAS}`);
428
+ } catch {
429
+ /* best-effort */
430
+ }
412
431
  }
413
432
 
414
433
  if (bars.length === 0) {
@@ -18,16 +18,16 @@ import { ThetaDataProvider } from "./providers/thetadata.ts";
18
18
 
19
19
  /** Normalized OHLCV bar — shared output type for all providers. */
20
20
  export interface BarRow {
21
- date: string; // "YYYY-MM-DD" Eastern Time
21
+ date: string; // "YYYY-MM-DD" Eastern Time
22
22
  open: number;
23
23
  high: number;
24
24
  low: number;
25
25
  close: number;
26
26
  volume: number;
27
- ticker: string; // Plain storage format (no prefix)
28
- time?: string; // "HH:MM" ET — only set for intraday (minute/hour) bars
29
- bid?: number; // Best bid — only set when provider supplies quote data
30
- ask?: number; // Best ask — only set when provider supplies quote data
27
+ ticker: string; // Plain storage format (no prefix)
28
+ time?: string; // "HH:MM" ET — only set for intraday (minute/hour) bars
29
+ bid?: number; // Best bid — only set when provider supplies quote data
30
+ ask?: number; // Best ask — only set when provider supplies quote data
31
31
  }
32
32
 
33
33
  /** Asset classes supported by market data providers. */
@@ -56,7 +56,7 @@ export interface OptionContract {
56
56
  underlying_price: number;
57
57
  contract_type: "call" | "put";
58
58
  strike: number;
59
- expiration: string; // "YYYY-MM-DD"
59
+ expiration: string; // "YYYY-MM-DD"
60
60
  exercise_style: string;
61
61
  delta: number | null;
62
62
  gamma: number | null;
@@ -93,19 +93,19 @@ export interface FetchSnapshotResult {
93
93
  /** Options for fetching historical option contract metadata (reference endpoint). */
94
94
  export interface FetchContractListOptions {
95
95
  underlying: string;
96
- as_of: string; // "YYYY-MM-DD" -- historical date
97
- expired?: boolean; // default true for historical contract lookup
98
- expiration_date_gte?: string; // Only contracts expiring on or after this date
99
- expiration_date_lte?: string; // Only contracts expiring on or before this date
96
+ as_of: string; // "YYYY-MM-DD" -- historical date
97
+ expired?: boolean; // default true for historical contract lookup
98
+ expiration_date_gte?: string; // Only contracts expiring on or after this date
99
+ expiration_date_lte?: string; // Only contracts expiring on or before this date
100
100
  }
101
101
 
102
102
  /** Single contract reference record (no greeks/pricing -- metadata only). */
103
103
  export interface ContractReference {
104
- ticker: string; // OCC ticker without O: prefix
104
+ ticker: string; // OCC ticker without O: prefix
105
105
  contract_type: "call" | "put";
106
106
  strike: number;
107
- expiration: string; // "YYYY-MM-DD"
108
- exercise_style: string; // "american" | "european"
107
+ expiration: string; // "YYYY-MM-DD"
108
+ exercise_style: string; // "american" | "european"
109
109
  }
110
110
 
111
111
  /** Result from contract list reference endpoint. */
@@ -147,7 +147,7 @@ export interface DataAvailability {
147
147
 
148
148
  /** Declares what data endpoints a provider supports. Used by the pipeline to build fetch plans. */
149
149
  export interface ProviderCapabilities {
150
- tradeBars: boolean; // minute OHLC from trade aggregates
150
+ tradeBars: boolean; // minute OHLC from trade aggregates
151
151
  /**
152
152
  * Strictly: "true NBBO bid/ask is available via this provider's dedicated
153
153
  * quotes endpoint". Use this when you specifically need real bid/ask spreads.
@@ -160,12 +160,12 @@ export interface ProviderCapabilities {
160
160
  * 'synth_close') for per-row provenance.
161
161
  */
162
162
  quotes: boolean;
163
- greeks: boolean; // provider-computed greeks on contracts
164
- flatFiles: boolean; // bulk S3/file download of historical data
165
- bulkByRoot: boolean; // provider has an every-contract path for an underlying/root
166
- perTicker: boolean; // one call per OCC ticker (Massive/Polygon pattern)
167
- minuteBars: boolean; // minute-level resolution available
168
- dailyBars: boolean; // daily-level resolution available
163
+ greeks: boolean; // provider-computed greeks on contracts
164
+ flatFiles: boolean; // bulk S3/file download of historical data
165
+ bulkByRoot: boolean; // provider has an every-contract path for an underlying/root
166
+ perTicker: boolean; // one call per OCC ticker (Massive/Polygon pattern)
167
+ minuteBars: boolean; // minute-level resolution available
168
+ dailyBars: boolean; // daily-level resolution available
169
169
  /** Earliest available data per asset class. Used by download tools and data pipelines to avoid requesting data that doesn't exist. */
170
170
  dataAvailability?: {
171
171
  option?: DataAvailability;
@@ -342,9 +342,7 @@ export function getProvider(): MarketDataProvider {
342
342
  _cached = new ThetaDataProvider();
343
343
  break;
344
344
  default:
345
- throw new Error(
346
- `Unknown MARKET_DATA_PROVIDER: "${name}". Supported: massive, thetadata`
347
- );
345
+ throw new Error(`Unknown MARKET_DATA_PROVIDER: "${name}". Supported: massive, thetadata`);
348
346
  }
349
347
  return _cached!;
350
348
  }
@@ -1,11 +1,9 @@
1
- export type MassiveDataTier = 'ohlc' | 'trades' | 'quotes';
1
+ export type MassiveDataTier = "ohlc" | "trades" | "quotes";
2
2
 
3
- export function resolveMassiveDataTier(
4
- env: NodeJS.ProcessEnv = process.env,
5
- ): MassiveDataTier {
6
- const tier = (env.MASSIVE_DATA_TIER ?? '').toLowerCase();
7
- if (tier === 'quotes' || tier === 'trades' || tier === 'ohlc') {
3
+ export function resolveMassiveDataTier(env: NodeJS.ProcessEnv = process.env): MassiveDataTier {
4
+ const tier = (env.MASSIVE_DATA_TIER ?? "").toLowerCase();
5
+ if (tier === "quotes" || tier === "trades" || tier === "ohlc") {
8
6
  return tier;
9
7
  }
10
- return 'ohlc';
8
+ return "ohlc";
11
9
  }
@@ -46,10 +46,7 @@ export function groupTickersByUnderlying(
46
46
  * a row-level column. sourceGlob is interpolated raw; caller must pass a
47
47
  * trusted, migrator-composed path.
48
48
  */
49
- export function buildOptionChainSelectQuery(
50
- sourceGlob: string,
51
- underlying: string,
52
- ): string {
49
+ export function buildOptionChainSelectQuery(sourceGlob: string, underlying: string): string {
53
50
  return `SELECT * EXCLUDE (underlying)
54
51
  FROM read_parquet('${sourceGlob}')
55
52
  WHERE underlying = '${underlying}'`;
@@ -59,10 +56,7 @@ export function buildOptionChainSelectQuery(
59
56
  * Build the SELECT for option_quote_minutes rewrite. NO EXCLUDE — the body
60
57
  * has no `underlying` column. Filters by root via regexp_extract.
61
58
  */
62
- export function buildOptionQuoteSelectQuery(
63
- sourceGlob: string,
64
- roots: string[],
65
- ): string {
59
+ export function buildOptionQuoteSelectQuery(sourceGlob: string, roots: string[]): string {
66
60
  if (roots.length === 0) {
67
61
  throw new Error("buildOptionQuoteSelectQuery: roots must not be empty");
68
62
  }
@@ -2,11 +2,7 @@ import { getSofrRateByKey } from "@tradeblocks/lib";
2
2
  import type { ContractRow } from "./chain-loader.ts";
3
3
  import { computeLegGreeks } from "./black-scholes.ts";
4
4
  import { computeFractionalDte } from "./option-time.ts";
5
- import {
6
- getSharedIvSolverPool,
7
- type IvSolveColumns,
8
- type IvSolverPool,
9
- } from "./iv-solver-pool.ts";
5
+ import { getSharedIvSolverPool, type IvSolveColumns, type IvSolverPool } from "./iv-solver-pool.ts";
10
6
 
11
7
  export type QuoteGreeksSource = "massive" | "thetadata" | "computed";
12
8
  export type QuoteGreeksMode = "auto" | "provider" | "compute";
@@ -79,20 +75,24 @@ function memoizedSofrRate(dateKey: string): number {
79
75
  }
80
76
 
81
77
  export function hasQuoteGreeks(row: QuoteGreekFields): boolean {
82
- return isFiniteNumber(row.delta ?? null)
83
- && isFiniteNumber(row.gamma ?? null)
84
- && isFiniteNumber(row.theta ?? null)
85
- && isFiniteNumber(row.vega ?? null)
86
- && isFiniteNumber(row.iv ?? null);
78
+ return (
79
+ isFiniteNumber(row.delta ?? null) &&
80
+ isFiniteNumber(row.gamma ?? null) &&
81
+ isFiniteNumber(row.theta ?? null) &&
82
+ isFiniteNumber(row.vega ?? null) &&
83
+ isFiniteNumber(row.iv ?? null)
84
+ );
87
85
  }
88
86
 
89
87
  function hasProviderFirstOrderGreeks(row: QuoteGreekFields): boolean {
90
- return row.greeks_source === "thetadata"
91
- && isFiniteNumber(row.delta ?? null)
92
- && (row.gamma == null || isFiniteNumber(row.gamma))
93
- && isFiniteNumber(row.theta ?? null)
94
- && isFiniteNumber(row.vega ?? null)
95
- && isFiniteNumber(row.iv ?? null);
88
+ return (
89
+ row.greeks_source === "thetadata" &&
90
+ isFiniteNumber(row.delta ?? null) &&
91
+ (row.gamma == null || isFiniteNumber(row.gamma)) &&
92
+ isFiniteNumber(row.theta ?? null) &&
93
+ isFiniteNumber(row.vega ?? null) &&
94
+ isFiniteNumber(row.iv ?? null)
95
+ );
96
96
  }
97
97
 
98
98
  function hasExistingQuoteGreeks(row: QuoteGreekFields): boolean {
@@ -100,9 +100,11 @@ function hasExistingQuoteGreeks(row: QuoteGreekFields): boolean {
100
100
  }
101
101
 
102
102
  function hasQuoteGreekProvenanceFields(row: QuoteGreekFields): boolean {
103
- return row.rate_type === OPTION_QUOTE_GREEKS_RATE_TYPE
104
- && isFiniteNumber(row.rate_value ?? null)
105
- && row.gamma_source === OPTION_QUOTE_GREEKS_GAMMA_SOURCE;
103
+ return (
104
+ row.rate_type === OPTION_QUOTE_GREEKS_RATE_TYPE &&
105
+ isFiniteNumber(row.rate_value ?? null) &&
106
+ row.gamma_source === OPTION_QUOTE_GREEKS_GAMMA_SOURCE
107
+ );
106
108
  }
107
109
 
108
110
  export function normalizeExistingQuoteGreeks(
@@ -114,9 +116,9 @@ export function normalizeExistingQuoteGreeks(
114
116
  row.greeks_source = defaultSource;
115
117
  }
116
118
  if (
117
- row.greeks_source === "computed"
118
- && row.greeks_revision == null
119
- && hasQuoteGreekProvenanceFields(row)
119
+ row.greeks_source === "computed" &&
120
+ row.greeks_revision == null &&
121
+ hasQuoteGreekProvenanceFields(row)
120
122
  ) {
121
123
  row.greeks_revision = OPTION_QUOTE_GREEKS_REVISION;
122
124
  }
@@ -131,15 +133,7 @@ export function computeQuoteGreeks(params: {
131
133
  expiration: string;
132
134
  contractType: ContractRow["contract_type"];
133
135
  }): QuoteGreekFields | null {
134
- const {
135
- optionPrice,
136
- underlyingPrice,
137
- strike,
138
- date,
139
- time,
140
- expiration,
141
- contractType,
142
- } = params;
136
+ const { optionPrice, underlyingPrice, strike, date, time, expiration, contractType } = params;
143
137
  if (!(optionPrice > 0) || !(underlyingPrice > 0) || !(strike > 0)) return null;
144
138
  const dte = computeFractionalDte(date, time.slice(0, 5), expiration);
145
139
  if (!(dte >= 0)) return null;
@@ -3,18 +3,14 @@ function parseDateUtc(date: string): Date {
3
3
  }
4
4
 
5
5
  function minutesFromTime(time: string): number {
6
- const [hour, minute] = time.slice(0, 5).split(':').map(Number);
6
+ const [hour, minute] = time.slice(0, 5).split(":").map(Number);
7
7
  return hour * 60 + minute;
8
8
  }
9
9
 
10
- export function computeFractionalDte(
11
- date: string,
12
- time: string,
13
- expiration: string,
14
- ): number {
10
+ export function computeFractionalDte(date: string, time: string, expiration: string): number {
15
11
  const startDay = parseDateUtc(date).getTime();
16
12
  const expiryDay = parseDateUtc(expiration).getTime();
17
13
  const dayDiff = Math.round((expiryDay - startDay) / 86_400_000);
18
- const remainingMinutes = Math.max((16 * 60) - minutesFromTime(time), 0);
19
- return Math.max(dayDiff + (remainingMinutes / (24 * 60)), 0);
14
+ const remainingMinutes = Math.max(16 * 60 - minutesFromTime(time), 0);
15
+ return Math.max(dayDiff + remainingMinutes / (24 * 60), 0);
20
16
  }
@@ -98,10 +98,7 @@ export function formatPercent(value: number, decimals: number = 2): string {
98
98
  /**
99
99
  * Format a ratio with specified decimals
100
100
  */
101
- export function formatRatio(
102
- value: number | undefined,
103
- decimals: number = 2
104
- ): string {
101
+ export function formatRatio(value: number | undefined, decimals: number = 2): string {
105
102
  if (value === undefined || value === null || !isFinite(value)) {
106
103
  return "N/A";
107
104
  }
@@ -3,10 +3,7 @@ import {
3
3
  type MarketDataProvider,
4
4
  type ProviderCapabilities,
5
5
  } from "./market-provider.ts";
6
- import {
7
- resolveMassiveDataTier,
8
- type MassiveDataTier,
9
- } from "./massive-tier.ts";
6
+ import { resolveMassiveDataTier, type MassiveDataTier } from "./massive-tier.ts";
10
7
 
11
8
  export interface ResolvedProviderCapabilities extends ProviderCapabilities {
12
9
  provider: MarketDataProvider;