tradeblocks-mcp 3.0.2 → 3.0.3

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 (214) hide show
  1. package/README.md +82 -68
  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-BKQ4PM4Y.js → chunk-6S37CXUA.js} +11 -13
  7. package/dist/chunk-6S37CXUA.js.map +1 -0
  8. package/dist/{chunk-PRAYH3RT.js → chunk-AP7IHUUR.js} +29 -12
  9. package/dist/chunk-AP7IHUUR.js.map +1 -0
  10. package/dist/{chunk-QTTR7AAW.js → chunk-C6LL746C.js} +67 -84
  11. package/dist/{chunk-QTTR7AAW.js.map → chunk-C6LL746C.js.map} +1 -1
  12. package/dist/{chunk-W2PP3LEH.js → chunk-SEUZYQGQ.js} +17 -8
  13. package/dist/chunk-SEUZYQGQ.js.map +1 -0
  14. package/dist/{chunk-4BLCXNQ6.js → chunk-UBUC5A66.js} +105 -114
  15. package/dist/chunk-UBUC5A66.js.map +1 -0
  16. package/dist/{chunk-XXYOUIZY.js → chunk-VDU25Z6X.js} +63 -80
  17. package/dist/chunk-VDU25Z6X.js.map +1 -0
  18. package/dist/daily-log-processor-BY3ISY6K.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-H3ARIVZ4.js +16 -0
  22. package/dist/{proto-3HZTCWK4.js → proto-V23GIZG2.js} +2 -2
  23. package/dist/{sync-PO4IPCYV.js → sync-EVLKB3ZJ.js} +7 -7
  24. package/dist/test-exports.js +358 -254
  25. package/dist/test-exports.js.map +1 -1
  26. package/dist/trade-processor-EYA3I3XB.js +9 -0
  27. package/dist/{trades-store-LOL3FQSF.js → trades-store-R3NL25T2.js} +2 -2
  28. package/manifest.json +3 -11
  29. package/package.json +1 -1
  30. package/server/{chunk-NZO6PT64.js → chunk-4P7D7YZP.js} +102 -113
  31. package/server/chunk-4P7D7YZP.js.map +1 -0
  32. package/server/{chunk-72GKJE2U.js → chunk-BOPHW5M6.js} +521 -235
  33. package/server/chunk-BOPHW5M6.js.map +1 -0
  34. package/server/{chunk-WA5AAPCH.js → chunk-GH2552SE.js} +17 -8
  35. package/server/chunk-GH2552SE.js.map +1 -0
  36. package/server/{chunk-5EBXHT6C.js → chunk-OBYKFW2B.js} +11 -13
  37. package/server/chunk-OBYKFW2B.js.map +1 -0
  38. package/server/{chunk-FBNDMCT5.js → chunk-T66KH2XH.js} +13 -11
  39. package/server/chunk-T66KH2XH.js.map +1 -0
  40. package/server/{chunk-NRFXAJF7.js → chunk-W5E7FHC4.js} +24 -52
  41. package/server/chunk-W5E7FHC4.js.map +1 -0
  42. package/server/{chunk-CSDVJPBB.js → chunk-YUCOAJ4Z.js} +29 -12
  43. package/server/chunk-YUCOAJ4Z.js.map +1 -0
  44. package/server/{chunk-PNKG7RY7.js → chunk-ZBJCF4ZG.js} +63 -80
  45. package/server/chunk-ZBJCF4ZG.js.map +1 -0
  46. package/server/{config-6IZXEFEX.js → config-DK7KOMNL.js} +1 -1
  47. package/server/config-DK7KOMNL.js.map +1 -0
  48. package/server/daily-log-processor-ENEUT22A.js +10 -0
  49. package/server/{daily-logs-store-NU7M4L5C.js → daily-logs-store-YFNXTB7J.js} +2 -2
  50. package/server/http-server.js +2 -5
  51. package/server/index.js +1771 -1538
  52. package/server/index.js.map +1 -1
  53. package/server/iv-solver-worker.js +9 -1
  54. package/server/market-provider-B437HKLW.js +17 -0
  55. package/server/{proto-DWRZJO4E.js → proto-YZ4TLX2N.js} +2 -2
  56. package/server/{sync-QFI5L7S7.js → sync-V25UQJA3.js} +7 -7
  57. package/server/trade-processor-L3PIQ5TG.js +10 -0
  58. package/server/{trades-store-VY26MWER.js → trades-store-RTTEYMXH.js} +2 -2
  59. package/src/auth/clients-store.ts +4 -4
  60. package/src/auth/code-store.ts +1 -1
  61. package/src/auth/config.ts +11 -12
  62. package/src/auth/login-page.ts +8 -10
  63. package/src/auth/provider.ts +35 -30
  64. package/src/auth/token.ts +17 -15
  65. package/src/db/backtest-schemas.ts +12 -4
  66. package/src/db/connection.ts +107 -40
  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 +127 -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/similarity.ts +316 -283
  114. package/src/tools/edge-decay.ts +124 -197
  115. package/src/tools/exit-analysis.ts +130 -77
  116. package/src/tools/greeks-attribution.ts +84 -35
  117. package/src/tools/guides.ts +4 -6
  118. package/src/tools/imports.ts +9 -12
  119. package/src/tools/market-data.ts +1067 -757
  120. package/src/tools/market-enrichment.ts +3 -3
  121. package/src/tools/market-fetch.ts +148 -67
  122. package/src/tools/market-imports.ts +12 -12
  123. package/src/tools/middleware/sync-middleware.ts +5 -6
  124. package/src/tools/performance.ts +185 -302
  125. package/src/tools/profile-analysis.ts +52 -66
  126. package/src/tools/profiles.ts +106 -69
  127. package/src/tools/regime-advisor.ts +20 -45
  128. package/src/tools/replay.ts +81 -77
  129. package/src/tools/reports/discrepancies.ts +298 -328
  130. package/src/tools/reports/fields.ts +7 -25
  131. package/src/tools/reports/helpers.ts +18 -49
  132. package/src/tools/reports/predictive.ts +27 -70
  133. package/src/tools/reports/slippage-trends.ts +315 -345
  134. package/src/tools/reports/slippage.ts +1 -4
  135. package/src/tools/reports/strategy-matches.ts +399 -441
  136. package/src/tools/schema.ts +43 -40
  137. package/src/tools/shared/filters.ts +3 -9
  138. package/src/tools/snapshot.ts +9 -30
  139. package/src/tools/sql.ts +15 -14
  140. package/src/tools/tickers.ts +1 -4
  141. package/src/utils/batch-exit-analysis.ts +31 -42
  142. package/src/utils/black-scholes.ts +39 -29
  143. package/src/utils/block-loader.ts +68 -82
  144. package/src/utils/calibration-probe.ts +1 -2
  145. package/src/utils/chain-loader.ts +3 -3
  146. package/src/utils/csv-discovery.ts +16 -22
  147. package/src/utils/data-quality.ts +24 -36
  148. package/src/utils/exit-triggers.ts +91 -96
  149. package/src/utils/field-timing.ts +94 -79
  150. package/src/utils/filter-predicates.ts +13 -9
  151. package/src/utils/flatfile-importer.ts +94 -64
  152. package/src/utils/greeks-decomposition.ts +152 -100
  153. package/src/utils/iv-solver-pool.ts +55 -25
  154. package/src/utils/iv-solver-worker.ts +5 -5
  155. package/src/utils/market-enricher.ts +528 -497
  156. package/src/utils/market-importer.ts +31 -12
  157. package/src/utils/market-provider.ts +21 -23
  158. package/src/utils/massive-tier.ts +5 -7
  159. package/src/utils/migrate-option-data-helpers.ts +2 -8
  160. package/src/utils/option-quote-greeks.ts +25 -31
  161. package/src/utils/option-time.ts +4 -8
  162. package/src/utils/output-formatter.ts +1 -4
  163. package/src/utils/provider-capabilities.ts +1 -4
  164. package/src/utils/providers/massive.ts +59 -93
  165. package/src/utils/providers/thetadata/backfill.ts +14 -23
  166. package/src/utils/providers/thetadata/client.ts +12 -8
  167. package/src/utils/providers/thetadata/decode.ts +2 -20
  168. package/src/utils/providers/thetadata/endpoints.ts +32 -40
  169. package/src/utils/providers/thetadata/join.ts +11 -10
  170. package/src/utils/providers/thetadata/proto.ts +12 -10
  171. package/src/utils/providers/thetadata/quote-mid-greeks.ts +5 -5
  172. package/src/utils/providers/thetadata.ts +11 -10
  173. package/src/utils/quote-enricher.ts +4 -4
  174. package/src/utils/quote-parquet-projection.ts +3 -11
  175. package/src/utils/sample-date-selector.ts +3 -5
  176. package/src/utils/schema-metadata.ts +102 -70
  177. package/src/utils/ticker.ts +5 -9
  178. package/src/utils/trade-replay.ts +77 -68
  179. package/dist/chunk-4BLCXNQ6.js.map +0 -1
  180. package/dist/chunk-BKQ4PM4Y.js.map +0 -1
  181. package/dist/chunk-FGZH632F.js.map +0 -1
  182. package/dist/chunk-LDKTV7GW.js.map +0 -1
  183. package/dist/chunk-PRAYH3RT.js.map +0 -1
  184. package/dist/chunk-W2PP3LEH.js.map +0 -1
  185. package/dist/chunk-XXYOUIZY.js.map +0 -1
  186. package/dist/daily-log-processor-6MWJ23JK.js +0 -9
  187. package/dist/market-provider-VDRJUEF2.js +0 -16
  188. package/dist/trade-processor-NHU4VWRX.js +0 -9
  189. package/server/chunk-5EBXHT6C.js.map +0 -1
  190. package/server/chunk-72GKJE2U.js.map +0 -1
  191. package/server/chunk-CSDVJPBB.js.map +0 -1
  192. package/server/chunk-FBNDMCT5.js.map +0 -1
  193. package/server/chunk-NRFXAJF7.js.map +0 -1
  194. package/server/chunk-NZO6PT64.js.map +0 -1
  195. package/server/chunk-PNKG7RY7.js.map +0 -1
  196. package/server/chunk-WA5AAPCH.js.map +0 -1
  197. package/server/config-6IZXEFEX.js.map +0 -1
  198. package/server/daily-log-processor-Y3PVSVBM.js +0 -10
  199. package/server/market-provider-VOYYVYWT.js +0 -17
  200. package/server/trade-processor-JWVS37KM.js +0 -10
  201. /package/dist/{daily-log-processor-6MWJ23JK.js.map → daily-log-processor-BY3ISY6K.js.map} +0 -0
  202. /package/dist/{daily-logs-store-D3QC2XPV.js.map → daily-logs-store-3C3OTGPK.js.map} +0 -0
  203. /package/dist/{market-provider-VDRJUEF2.js.map → market-provider-H3ARIVZ4.js.map} +0 -0
  204. /package/dist/{proto-3HZTCWK4.js.map → proto-V23GIZG2.js.map} +0 -0
  205. /package/dist/{sync-PO4IPCYV.js.map → sync-EVLKB3ZJ.js.map} +0 -0
  206. /package/dist/{trade-processor-NHU4VWRX.js.map → trade-processor-EYA3I3XB.js.map} +0 -0
  207. /package/dist/{trades-store-LOL3FQSF.js.map → trades-store-R3NL25T2.js.map} +0 -0
  208. /package/server/{daily-log-processor-Y3PVSVBM.js.map → daily-log-processor-ENEUT22A.js.map} +0 -0
  209. /package/server/{daily-logs-store-NU7M4L5C.js.map → daily-logs-store-YFNXTB7J.js.map} +0 -0
  210. /package/server/{market-provider-VOYYVYWT.js.map → market-provider-B437HKLW.js.map} +0 -0
  211. /package/server/{proto-DWRZJO4E.js.map → proto-YZ4TLX2N.js.map} +0 -0
  212. /package/server/{sync-QFI5L7S7.js.map → sync-V25UQJA3.js.map} +0 -0
  213. /package/server/{trade-processor-JWVS37KM.js.map → trade-processor-L3PIQ5TG.js.map} +0 -0
  214. /package/server/{trades-store-VY26MWER.js.map → trades-store-RTTEYMXH.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/providers/massive.ts","../src/utils/black-scholes.ts","../src/utils/massive-tier.ts","../src/utils/trade-replay.ts","../src/utils/providers/thetadata/auth.ts","../src/utils/providers/thetadata/client.ts","../src/utils/providers/thetadata/decode.ts","../src/utils/providers/thetadata/endpoints.ts","../src/utils/option-time.ts","../src/utils/iv-solver-pool.ts","../src/utils/iv-solver-worker.ts","../src/utils/option-quote-greeks.ts","../src/utils/providers/thetadata/join.ts","../src/utils/providers/thetadata/quote-mid-greeks.ts","../src/utils/providers/thetadata.ts","../src/utils/market-provider.ts"],"sourcesContent":["/**\n * Massive.com (Polygon.io) Market Data Provider\n *\n * Implements MarketDataProvider for the Massive.com REST API.\n * Combines the former massive-client.ts (OHLCV bars) and massive-snapshot.ts\n * (option chain snapshots) into a single provider adapter.\n *\n * Key design decisions:\n * - API key read at call site via process.env.MASSIVE_API_KEY\n * - Pagination loop guard with seen-cursor Set + MAX_PAGES=500 safety net\n * - adjusted=false and limit=50000 in all aggregate API calls\n * - 429 retry with Retry-After header or exponential backoff\n * - Ticker prefixes: I: for indices, O: for options\n * - Timestamps are Unix milliseconds from the Massive aggregates API\n */\n\nimport { z } from \"zod\";\nimport type {\n MarketDataProvider,\n ProviderCapabilities,\n BarRow,\n FetchBarsOptions,\n FetchSnapshotOptions,\n FetchSnapshotResult,\n OptionContract,\n AssetClass,\n FetchContractListOptions,\n FetchContractListResult,\n ContractReference,\n BulkDownloadOptions,\n BulkDownloadResult,\n MinuteQuote,\n} from \"../market-provider.ts\";\nimport { computeLegGreeks } from \"../black-scholes.ts\";\nimport { resolveMassiveDataTier } from \"../massive-tier.ts\";\n\n// ===========================================================================\n// Zod Schemas — Aggregates (OHLCV Bars)\n// ===========================================================================\n\nexport const MassiveBarSchema = z.object({\n v: z.number().optional(),\n vw: z.number().optional(),\n o: z.number(),\n c: z.number(),\n h: z.number(),\n l: z.number(),\n t: z.number(),\n n: z.number().optional(),\n});\n\nexport type MassiveBar = z.infer<typeof MassiveBarSchema>;\n\nexport const MassiveAggregateResponseSchema = z.object({\n ticker: z.string(),\n queryCount: z.number(),\n resultsCount: z.number().optional(),\n adjusted: z.boolean().optional(),\n results: z.array(MassiveBarSchema).default([]),\n status: z.string(),\n request_id: z.string(),\n next_url: z.string().optional(),\n});\n\nexport type MassiveAggregateResponse = z.infer<typeof MassiveAggregateResponseSchema>;\n\n// ===========================================================================\n// Zod Schemas — Quotes (Historical Bid/Ask)\n// ===========================================================================\n\nexport const MassiveQuoteSchema = z.object({\n bid_price: z.number(),\n ask_price: z.number(),\n sip_timestamp: z.number(), // nanoseconds\n bid_size: z.number(),\n ask_size: z.number(),\n sequence_number: z.number(),\n});\n\nexport type MassiveQuote = z.infer<typeof MassiveQuoteSchema>;\n\nexport const MassiveQuotesResponseSchema = z.object({\n status: z.string(),\n request_id: z.string(),\n results: z.array(MassiveQuoteSchema).default([]),\n next_url: z.string().optional(),\n});\n\nexport type MassiveQuotesResponse = z.infer<typeof MassiveQuotesResponseSchema>;\n\n// ===========================================================================\n// Zod Schemas — Snapshot (Option Chain)\n// ===========================================================================\n\nexport const MassiveSnapshotGreeksSchema = z.object({\n delta: z.number(),\n gamma: z.number(),\n theta: z.number(),\n vega: z.number(),\n});\n\nexport const MassiveSnapshotDaySchema = z.object({\n open: z.number(),\n high: z.number(),\n low: z.number(),\n close: z.number(),\n change: z.number(),\n change_percent: z.number(),\n volume: z.number().optional(),\n vwap: z.number().optional(),\n previous_close: z.number(),\n last_updated: z.number(),\n});\n\nexport const MassiveSnapshotQuoteSchema = z.object({\n bid: z.number(),\n ask: z.number(),\n midpoint: z.number(),\n bid_size: z.number(),\n ask_size: z.number(),\n last_updated: z.number(),\n timeframe: z.string(),\n});\n\nexport const MassiveSnapshotTradeSchema = z.object({\n price: z.number(),\n size: z.number(),\n sip_timestamp: z.number(),\n conditions: z.array(z.number()).optional(),\n timeframe: z.string(),\n});\n\nexport const MassiveSnapshotDetailsSchema = z.object({\n ticker: z.string(),\n contract_type: z.string(),\n strike_price: z.number(),\n expiration_date: z.string(),\n exercise_style: z.string(),\n shares_per_contract: z.number(),\n});\n\nexport const MassiveSnapshotUnderlyingSchema = z.object({\n ticker: z.string(),\n price: z.number(),\n change_to_break_even: z.number(),\n last_updated: z.number(),\n timeframe: z.string(),\n});\n\nexport const MassiveSnapshotContractSchema = z.object({\n break_even_price: z.number(),\n implied_volatility: z.number(),\n open_interest: z.number(),\n greeks: MassiveSnapshotGreeksSchema.optional(),\n day: MassiveSnapshotDaySchema,\n last_quote: MassiveSnapshotQuoteSchema,\n last_trade: MassiveSnapshotTradeSchema.optional(),\n details: MassiveSnapshotDetailsSchema,\n underlying_asset: MassiveSnapshotUnderlyingSchema,\n});\n\nexport const MassiveSnapshotResponseSchema = z.object({\n request_id: z.string(),\n status: z.string(),\n results: z.array(MassiveSnapshotContractSchema),\n next_url: z.string().optional(),\n});\n\n// ===========================================================================\n// Zod Schemas — Contract List (Reference Endpoint)\n// ===========================================================================\n\nexport const MassiveContractReferenceSchema = z.object({\n ticker: z.string(),\n strike_price: z.number(),\n expiration_date: z.string(),\n contract_type: z.string(),\n exercise_style: z.string().optional().default(\"american\"),\n});\n\nexport const MassiveContractListResponseSchema = z.object({\n results: z.array(MassiveContractReferenceSchema),\n next_url: z.string().nullable().optional(),\n count: z.number().optional(),\n});\n\n// ===========================================================================\n// Constants\n// ===========================================================================\n\nexport const MASSIVE_BASE_URL = \"https://api.massive.com\";\nexport const MASSIVE_MAX_LIMIT = 50000;\nexport const MASSIVE_MAX_PAGES = 500;\n\n// ===========================================================================\n// Ticker Normalization\n// ===========================================================================\n\nexport function toMassiveTicker(ticker: string, assetClass: AssetClass): string {\n if (assetClass === \"index\") return ticker.startsWith(\"I:\") ? ticker : `I:${ticker}`;\n if (assetClass === \"option\") return ticker.startsWith(\"O:\") ? ticker : `O:${ticker}`;\n return ticker;\n}\n\nexport function fromMassiveTicker(apiTicker: string): string {\n return apiTicker.replace(/^[IO]:/, \"\");\n}\n\n// ===========================================================================\n// Timestamp Conversion\n// ===========================================================================\n\nexport function massiveTimestampToETDate(unixMs: number): string {\n return new Date(unixMs).toLocaleDateString(\"en-CA\", {\n timeZone: \"America/New_York\",\n });\n}\n\nexport function massiveTimestampToETTime(unixMs: number): string {\n return new Date(unixMs).toLocaleTimeString(\"en-US\", {\n timeZone: \"America/New_York\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n hour12: false,\n });\n}\n\n/**\n * Converts a nanosecond sip_timestamp to \"YYYY-MM-DD HH:MM\" ET minute key.\n * Used for matching quotes to intraday bars by minute bucket.\n */\nexport function nanosToETMinuteKey(nanosTimestamp: number): string {\n const ms = Math.floor(nanosTimestamp / 1_000_000);\n const date = massiveTimestampToETDate(ms);\n const time = massiveTimestampToETTime(ms);\n return `${date} ${time}`;\n}\n\nfunction etOffsetMinutesForDate(dateStr: string): number {\n const probe = new Date(`${dateStr}T12:00:00Z`);\n const offsetToken = probe.toLocaleString(\"en-US\", {\n timeZone: \"America/New_York\",\n timeZoneName: \"shortOffset\",\n }).match(/GMT([+-]\\d{1,2})(?::(\\d{2}))?/);\n if (!offsetToken) {\n throw new Error(`Unable to resolve ET offset for ${dateStr}`);\n }\n const hours = Number(offsetToken[1]);\n const minutes = offsetToken[2] ? Number(offsetToken[2]) : 0;\n return hours * 60 + Math.sign(hours || 1) * minutes;\n}\n\nfunction etDateTimeToUtcIso(dateStr: string, timeStr: string): string {\n const [year, month, day] = dateStr.split(\"-\").map(Number);\n const [hour, minute] = timeStr.split(\":\").map(Number);\n const offsetMinutes = etOffsetMinutesForDate(dateStr);\n const utcMs = Date.UTC(year, month - 1, day, hour, minute) - offsetMinutes * 60_000;\n return new Date(utcMs).toISOString().replace(\".000Z\", \"Z\");\n}\n\n// ===========================================================================\n// Internal Helpers\n// ===========================================================================\n\nfunction getApiKey(): string {\n const key = process.env.MASSIVE_API_KEY;\n if (!key) {\n throw new Error(\n \"Set MASSIVE_API_KEY environment variable to use Massive.com data import\"\n );\n }\n return key;\n}\n\nasync function fetchWithRetry(\n url: string,\n headers: Record<string, string>,\n maxRetries = 2\n): Promise<Response> {\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const response = await fetch(url, {\n headers,\n signal: AbortSignal.timeout(30_000),\n });\n\n if (response.status === 429) {\n if (attempt === maxRetries) {\n throw new Error(\n \"Massive.com rate limit exceeded — try again in a few minutes\"\n );\n }\n const retryAfter = response.headers.get(\"Retry-After\");\n const backoffMs = retryAfter\n ? parseInt(retryAfter, 10) * 1000\n : Math.pow(2, attempt + 1) * 1000;\n await new Promise((resolve) => setTimeout(resolve, backoffMs));\n continue;\n }\n\n return response;\n }\n throw new Error(\"Massive.com rate limit exceeded after retries\");\n}\n\n// ===========================================================================\n// Snapshot Helpers\n// ===========================================================================\n\nconst INDEX_TICKERS = new Set([\n \"SPX\", \"NDX\", \"RUT\", \"DJX\", \"VIX\", \"VIX9D\", \"VIX3M\", \"OEX\", \"XSP\",\n]);\n\nfunction detectSnapshotAssetClass(ticker: string): AssetClass {\n return INDEX_TICKERS.has(ticker.toUpperCase()) ? \"index\" : \"stock\";\n}\n\nfunction computeDTE(expirationDate: string): number {\n const expMatch = expirationDate.match(/^(\\d{4})-(\\d{2})-(\\d{2})/);\n if (!expMatch) return 0;\n const [, expYearS, expMonthS, expDayS] = expMatch;\n const expYear = parseInt(expYearS, 10);\n const expMonth = parseInt(expMonthS, 10);\n const expDay = parseInt(expDayS, 10);\n\n const todayET = new Date().toLocaleDateString(\"en-CA\", {\n timeZone: \"America/New_York\",\n });\n const todayMatch = todayET.match(/^(\\d{4})-(\\d{2})-(\\d{2})/);\n if (!todayMatch) return 0;\n const [, todayYearS, todayMonthS, todayDayS] = todayMatch;\n const todayYear = parseInt(todayYearS, 10);\n const todayMonth = parseInt(todayMonthS, 10);\n const todayDay = parseInt(todayDayS, 10);\n\n const dte =\n (Date.UTC(expYear, expMonth - 1, expDay) -\n Date.UTC(todayYear, todayMonth - 1, todayDay)) /\n 86_400_000;\n\n return dte <= 0 ? 0.001 : dte;\n}\n\nfunction mapContract(\n contract: z.infer<typeof MassiveSnapshotContractSchema>,\n): OptionContract {\n const hasApiGreeks =\n contract.greeks != null && contract.greeks.delta != null;\n\n let delta: number | null = null;\n let gamma: number | null = null;\n let theta: number | null = null;\n let vega: number | null = null;\n let iv: number | null = null;\n let greeksSource: \"massive\" | \"computed\" = \"computed\";\n\n if (hasApiGreeks) {\n delta = contract.greeks!.delta;\n gamma = contract.greeks!.gamma;\n theta = contract.greeks!.theta;\n vega = contract.greeks!.vega;\n iv = contract.implied_volatility;\n greeksSource = \"massive\";\n } else {\n const optionPrice =\n contract.last_trade?.price ?? contract.last_quote.midpoint;\n const underlyingPrice = contract.underlying_asset.price;\n const strike = contract.details.strike_price;\n const dte = computeDTE(contract.details.expiration_date);\n const type = contract.details.contract_type === \"call\" ? \"C\" : \"P\";\n const riskFreeRate = 0.045;\n const dividendYield = 0.015;\n\n const result = computeLegGreeks(\n optionPrice,\n underlyingPrice,\n strike,\n dte,\n type as \"C\" | \"P\",\n riskFreeRate,\n dividendYield,\n );\n\n if (result.iv !== null) {\n delta = result.delta;\n gamma = result.gamma;\n theta = result.theta;\n vega = result.vega;\n iv = result.iv;\n }\n greeksSource = \"computed\";\n }\n\n return {\n ticker: fromMassiveTicker(contract.details.ticker),\n underlying_ticker: fromMassiveTicker(contract.underlying_asset.ticker),\n underlying_price: contract.underlying_asset.price,\n contract_type: contract.details.contract_type as \"call\" | \"put\",\n strike: contract.details.strike_price,\n expiration: contract.details.expiration_date,\n exercise_style: contract.details.exercise_style,\n delta,\n gamma,\n theta,\n vega,\n iv,\n greeks_source: greeksSource,\n bid: contract.last_quote.bid,\n ask: contract.last_quote.ask,\n midpoint: contract.last_quote.midpoint,\n last_price: contract.last_trade?.price ?? null,\n open_interest: contract.open_interest,\n volume: contract.day.volume ?? 0,\n break_even: contract.break_even_price,\n };\n}\n\n// ===========================================================================\n// MassiveProvider\n// ===========================================================================\n\nexport class MassiveProvider implements MarketDataProvider {\n readonly name = \"massive\";\n\n capabilities(): ProviderCapabilities {\n const tier = resolveMassiveDataTier();\n return {\n tradeBars: true,\n quotes: tier === 'quotes',\n greeks: false, // Massive does not provide greeks — we compute via BSM\n flatFiles: true, // S3 flat files available via rclone\n bulkByRoot: false, // Massive is per-ticker, not bulk-by-root\n perTicker: true,\n minuteBars: true,\n dailyBars: true,\n dataAvailability: {\n option: { from: '2014-01-02' },\n index: { from: '2023-02-14' },\n stock: { from: '2014-01-02' },\n },\n };\n }\n\n async fetchBars(options: FetchBarsOptions): Promise<BarRow[]> {\n const apiKey = getApiKey();\n const {\n ticker,\n from,\n to,\n timespan = \"day\",\n multiplier = 1,\n assetClass = \"stock\",\n } = options;\n\n const apiTicker = toMassiveTicker(ticker, assetClass);\n const storageTicker = fromMassiveTicker(apiTicker);\n const headers = { Authorization: `Bearer ${apiKey}` };\n\n let url: string | null =\n `${MASSIVE_BASE_URL}/v2/aggs/ticker/${encodeURIComponent(apiTicker)}/range/${multiplier}/${timespan}/${from}/${to}?adjusted=false&limit=${MASSIVE_MAX_LIMIT}`;\n\n const allRows: BarRow[] = [];\n const seenCursors = new Set<string>();\n let pageCount = 0;\n\n while (url) {\n pageCount++;\n if (pageCount > MASSIVE_MAX_PAGES) {\n throw new Error(\n `Pagination safety limit reached (${MASSIVE_MAX_PAGES} pages) — possible API issue`\n );\n }\n\n const response = await fetchWithRetry(url, headers);\n\n if (response.status === 401) {\n throw new Error(\n \"MASSIVE_API_KEY rejected by Massive.com — check your key\"\n );\n }\n\n if (!response.ok) {\n throw new Error(\n `Massive.com API error: HTTP ${response.status} ${response.statusText}`\n );\n }\n\n const json = await response.json();\n\n const parsed = MassiveAggregateResponseSchema.safeParse(json);\n if (!parsed.success) {\n const issues = parsed.error.issues\n .map((i) => `${i.path.join(\".\")}: ${i.message}`)\n .join(\"; \");\n throw new Error(`Massive API response validation failed: ${issues}`);\n }\n\n const data = parsed.data;\n\n for (const bar of data.results) {\n const row: BarRow = {\n date: massiveTimestampToETDate(bar.t),\n open: bar.o,\n high: bar.h,\n low: bar.l,\n close: bar.c,\n volume: bar.v ?? 0,\n ticker: storageTicker,\n };\n if (timespan !== \"day\") {\n row.time = massiveTimestampToETTime(bar.t);\n }\n allRows.push(row);\n }\n\n if (data.next_url) {\n const nextUrlObj = new URL(data.next_url);\n const cursor = nextUrlObj.searchParams.get(\"cursor\") ?? data.next_url;\n if (seenCursors.has(cursor)) {\n throw new Error(\n `Pagination loop detected — cursor repeated: ${cursor.slice(0, 50)}...`\n );\n }\n seenCursors.add(cursor);\n url = data.next_url;\n } else {\n url = null;\n }\n }\n\n // Quote enrichment (bid/ask backfill + synthetic gap bars) is handled\n // out-of-band by the pipeline-side `enrich_quotes` MCP tool /\n // quote-minute-cache; reads here never trigger provider writes.\n\n return allRows;\n }\n\n /**\n * Fetches historical quotes (bid/ask) for an option ticker over a date range.\n * Returns a Map keyed by \"YYYY-MM-DD HH:MM\" ET minute key.\n * Any error (network, HTTP error, parse failure) silently returns an empty Map.\n */\n /**\n * Fetch the last NBBO quote for each trading minute in the date range.\n *\n * Uses per-minute requests (`order=desc&limit=1`) in parallel batches.\n * This is much faster than paginating through tick-level quotes: ~400\n * small requests vs millions of raw NBBO ticks. With concurrency=20,\n * a full day completes in ~6-7 seconds and results are cached so\n * subsequent fetches are instant.\n */\n private async fetchQuotesForBars(\n apiTicker: string,\n headers: Record<string, string>,\n from: string,\n to: string,\n ): Promise<Map<string, MinuteQuote>> {\n const result = new Map<string, MinuteQuote>();\n\n // Iterate trading days in the range\n const startDate = new Date(from + 'T00:00:00');\n const endDate = new Date(to + 'T00:00:00');\n const encodedTicker = encodeURIComponent(apiTicker);\n\n for (let d = new Date(startDate); d <= endDate; d.setDate(d.getDate() + 1)) {\n const day = d.getDay();\n if (day === 0 || day === 6) continue; // skip weekends\n const dateStr = d.toISOString().slice(0, 10);\n\n // Convert RTH window (09:30-16:00 ET) to UTC using real America/New_York\n // timezone rules. Month-based DST guesses shift pre-DST March quotes by 1 hour.\n const fromTs = etDateTimeToUtcIso(dateStr, \"09:30\");\n const toTs = etDateTimeToUtcIso(dateStr, \"16:00\");\n\n // Paginated fetch: up to 50K quotes per page, ~3 pages for a full day\n let url: string | null =\n `${MASSIVE_BASE_URL}/v3/quotes/${encodedTicker}?timestamp.gte=${fromTs}&timestamp.lte=${toTs}&limit=50000&order=asc`;\n\n const dayQuotes: MassiveQuote[] = [];\n let pages = 0;\n\n while (url && pages < 50) {\n pages++;\n try {\n const response = await fetch(url, { headers, signal: AbortSignal.timeout(30_000) });\n if (!response.ok) break;\n const json = await response.json();\n const parsed = MassiveQuotesResponseSchema.safeParse(json);\n if (!parsed.success) break;\n dayQuotes.push(...parsed.data.results);\n url = parsed.data.next_url ?? null;\n } catch {\n break;\n }\n }\n\n // Aggregate tick quotes to minute-level NBBO (last quote per minute wins)\n const byMinute = new Map<string, MinuteQuote>();\n for (const q of dayQuotes) {\n const key = nanosToETMinuteKey(q.sip_timestamp);\n const [keyDate, keyTime] = key.split(\" \");\n if (keyDate !== dateStr || !keyTime) continue;\n if (keyTime < \"09:30\" || keyTime > \"16:00\") continue;\n byMinute.set(key, { bid: q.bid_price, ask: q.ask_price, source: \"nbbo\" });\n }\n\n for (const [key, val] of byMinute) {\n result.set(key, val);\n }\n }\n\n return result;\n }\n\n /**\n * Developer-tier fallback. When MASSIVE_DATA_TIER ≠ 'quotes' the user\n * doesn't have access to /v3/quotes, but /v2/aggs minute bars are included\n * in lower tiers (Developer plan). We fetch option minute OHLCV via the\n * shared bar-aggregates path and synthesize {bid: close, ask: close} per\n * minute. Downstream `enrichQuoteRows` averages bid+ask, so this surfaces\n * `close` as the mid — a reasonable proxy when true NBBO is unavailable.\n * Tagged source='synth_close' in Task 6 so consumers can distinguish from\n * true NBBO (locked-spread NBBO can also have bid==ask, so the source\n * column is the authoritative signal — not the bid/ask equality).\n */\n private async fetchQuotesViaMinuteBars(\n ticker: string,\n from: string,\n to: string,\n ): Promise<Map<string, MinuteQuote>> {\n const bars = await this.fetchBars({\n ticker,\n from,\n to,\n timespan: \"minute\",\n multiplier: 1,\n assetClass: \"option\",\n });\n\n const out = new Map<string, MinuteQuote>();\n for (const bar of bars) {\n if (!bar.time) continue;\n const time = bar.time.slice(0, 5); // \"HH:MM\"\n // RTH window only — match the /v3/quotes path's behavior\n if (time < \"09:30\" || time > \"16:00\") continue;\n const key = `${bar.date} ${time}`;\n out.set(key, { bid: bar.close, ask: bar.close, source: \"synth_close\" });\n }\n return out;\n }\n\n async fetchQuotes(ticker: string, from: string, to: string): Promise<Map<string, MinuteQuote>> {\n const tier = resolveMassiveDataTier();\n if (tier !== \"quotes\") {\n // Developer / OHLC / trades tiers: /v3/quotes is gated. Fall back to\n // /v2/aggs minute bars and synthesize bid=ask=close. See\n // fetchQuotesViaMinuteBars JSDoc for the trade-off.\n return this.fetchQuotesViaMinuteBars(ticker, from, to);\n }\n const apiKey = getApiKey();\n const apiTicker = toMassiveTicker(ticker, \"option\");\n const headers = { Authorization: `Bearer ${apiKey}` };\n return this.fetchQuotesForBars(apiTicker, headers, from, to);\n }\n\n async downloadFlatFile(date: string, assetClass: string): Promise<string | null> {\n const [year, month] = date.split('-');\n const assetPathMap: Record<string, string> = {\n option: 'us_options_opra/minute_aggs_v1',\n index: 'us_indices/minute_aggs_v1',\n stock: 'us_stocks_sip/minute_aggs_v1',\n };\n const assetPath = assetPathMap[assetClass] ?? assetPathMap.stock;\n const s3Path = `s3massive:flatfiles/${assetPath}/${year}/${month}/${date}.csv.gz`;\n // Separate tmp dirs per asset class to avoid file collisions\n const tmpDir = assetClass === 'index' ? '/tmp/massive-flat-index' : '/tmp/massive-flat';\n const localPath = `${tmpDir}/${date}.csv.gz`;\n\n const { existsSync, mkdirSync } = await import('fs');\n const { execFile } = await import('child_process');\n const { promisify } = await import('util');\n const execFileAsync = promisify(execFile);\n\n mkdirSync(tmpDir, { recursive: true });\n if (existsSync(localPath)) return localPath;\n\n try {\n await execFileAsync('rclone', ['copy', s3Path, `${tmpDir}/`], { timeout: 120_000 });\n } catch {\n return null;\n }\n return existsSync(localPath) ? localPath : null;\n }\n\n async downloadBulkData(options: BulkDownloadOptions): Promise<BulkDownloadResult> {\n const { date, dataset, assetClass, tickers, outputPath } = options;\n\n // Skip if output Parquet already exists\n const { existsSync: exists, mkdirSync: mkdir } = await import('fs');\n if (exists(outputPath)) {\n return { rowCount: 0, skipped: true };\n }\n\n // Skip if date is before provider's data availability for this asset class\n const availability = this.capabilities().dataAvailability?.[assetClass];\n if (availability && date < availability.from) {\n return { rowCount: 0, skipped: true };\n }\n\n const { execFile } = await import('child_process');\n const { promisify } = await import('util');\n const { dirname } = await import('path');\n const execFileAsync = promisify(execFile);\n\n // S3 path mapping\n const s3PathMap: Record<string, Record<string, string>> = {\n option: {\n minute_bars: 'us_options_opra/minute_aggs_v1',\n daily_bars: 'us_options_opra/day_aggs_v1',\n trades: 'us_options_opra/trades_v1',\n },\n index: {\n minute_bars: 'us_indices/minute_aggs_v1',\n daily_bars: 'us_indices/day_aggs_v1',\n },\n };\n\n const s3Subpath = s3PathMap[assetClass]?.[dataset];\n if (!s3Subpath) {\n throw new Error(`Unsupported asset class/dataset combination: ${assetClass}/${dataset}`);\n }\n\n const [year, month] = date.split('-');\n const s3Path = `s3massive:flatfiles/${s3Subpath}/${year}/${month}/${date}.csv.gz`;\n const tmpDir = `/tmp/massive-bulk-${assetClass}-${dataset}`;\n const localCsv = `${tmpDir}/${date}.csv.gz`;\n\n mkdir(tmpDir, { recursive: true });\n // Don't create output dir yet — only after successful download + filter\n\n try {\n // Download CSV.gz from S3 via rclone (if not already cached)\n if (!exists(localCsv)) {\n await execFileAsync('rclone', ['copy', s3Path, `${tmpDir}/`], { timeout: 300_000 });\n if (!exists(localCsv)) {\n throw new Error(`rclone download failed — file not found: ${localCsv}`);\n }\n }\n\n // Build ticker filter WHERE clause\n const prefix = assetClass === 'option' ? 'O:' : 'I:';\n const tickerConditions = tickers\n .map(t => `ticker LIKE '${prefix}${t}%'`)\n .join(' OR ');\n const whereClause = `WHERE ${tickerConditions}`;\n\n // CSV column definitions differ by asset class\n const isOption = assetClass === 'option';\n const csvColumns = isOption\n ? \"columns = {'ticker': 'VARCHAR', 'volume': 'BIGINT', 'open': 'DOUBLE', 'close': 'DOUBLE', 'high': 'DOUBLE', 'low': 'DOUBLE', 'window_start': 'BIGINT', 'transactions': 'BIGINT'}\"\n : \"columns = {'ticker': 'VARCHAR', 'open': 'DOUBLE', 'close': 'DOUBLE', 'high': 'DOUBLE', 'low': 'DOUBLE', 'window_start': 'BIGINT'}\";\n\n // EDT/EST offset logic in DuckDB SQL:\n // EDT (UTC-4): months 4-10 always; month 3 if day >= 8; month 11 if day < 7\n // EST (UTC-5): all other times\n const etConversion = `\n make_timestamp(CAST(window_start / 1000 AS BIGINT)) AS utc_ts,\n CASE\n WHEN month(make_timestamp(CAST(window_start / 1000 AS BIGINT))) > 3\n AND month(make_timestamp(CAST(window_start / 1000 AS BIGINT))) < 11 THEN 4\n WHEN month(make_timestamp(CAST(window_start / 1000 AS BIGINT))) = 3\n AND day(make_timestamp(CAST(window_start / 1000 AS BIGINT))) >= 8 THEN 4\n WHEN month(make_timestamp(CAST(window_start / 1000 AS BIGINT))) = 11\n AND day(make_timestamp(CAST(window_start / 1000 AS BIGINT))) < 7 THEN 4\n ELSE 5\n END AS et_offset\n `;\n\n // Build full COPY query: read CSV.gz → filter tickers → convert timestamps → write Parquet\n const sql = `\n COPY (\n SELECT\n replace(replace(ticker, 'O:', ''), 'I:', '') AS ticker,\n strftime(utc_ts - et_offset * INTERVAL '1' HOUR, '%Y-%m-%d') AS date,\n strftime(utc_ts - et_offset * INTERVAL '1' HOUR, '%H:%M') AS time,\n open,\n high,\n low,\n close,\n NULL::DOUBLE AS bid,\n NULL::DOUBLE AS ask\n FROM (\n SELECT *, ${etConversion}\n FROM read_csv('${localCsv}', ${csvColumns}, header = true, compression = 'gzip')\n ${whereClause}\n ) sub\n ) TO '${outputPath}' (FORMAT PARQUET, COMPRESSION ZSTD)\n `;\n\n // Use in-memory DuckDB to run the conversion\n const { DuckDBInstance } = await import('@duckdb/node-api');\n const db = await DuckDBInstance.create(':memory:');\n const conn = await db.connect();\n\n try {\n mkdir(dirname(outputPath), { recursive: true });\n await conn.run(sql);\n\n // Get row count from the written Parquet\n const countResult = await conn.runAndReadAll(\n `SELECT count(*) AS cnt FROM '${outputPath}'`\n );\n const rowCount = Number(countResult.getRows()[0][0]);\n return { rowCount, skipped: false };\n } finally {\n conn.closeSync();\n }\n } finally {\n // Clean up temp CSV (keep output Parquet)\n try {\n const { unlinkSync } = await import('fs');\n if (exists(localCsv)) unlinkSync(localCsv);\n } catch {\n // Ignore cleanup errors\n }\n }\n }\n\n async fetchOptionSnapshot(options: FetchSnapshotOptions): Promise<FetchSnapshotResult> {\n const apiKey = getApiKey();\n const { underlying } = options;\n\n const assetClass = detectSnapshotAssetClass(underlying);\n const apiTicker = toMassiveTicker(underlying, assetClass);\n const headers = { Authorization: `Bearer ${apiKey}` };\n\n const params = new URLSearchParams({ limit: \"250\" });\n if (options.strike_price_gte != null) {\n params.set(\"strike_price.gte\", String(options.strike_price_gte));\n }\n if (options.strike_price_lte != null) {\n params.set(\"strike_price.lte\", String(options.strike_price_lte));\n }\n if (options.expiration_date_gte != null) {\n params.set(\"expiration_date.gte\", options.expiration_date_gte);\n }\n if (options.expiration_date_lte != null) {\n params.set(\"expiration_date.lte\", options.expiration_date_lte);\n }\n if (options.contract_type != null) {\n params.set(\"contract_type\", options.contract_type);\n }\n\n let url: string | null =\n `${MASSIVE_BASE_URL}/v3/snapshot/options/${encodeURIComponent(apiTicker)}?${params.toString()}`;\n\n const allContracts: OptionContract[] = [];\n const seenCursors = new Set<string>();\n let pageCount = 0;\n let underlyingPrice = 0;\n let underlyingTicker = underlying;\n\n while (url) {\n pageCount++;\n if (pageCount > MASSIVE_MAX_PAGES) {\n throw new Error(\n `Pagination safety limit reached (${MASSIVE_MAX_PAGES} pages) — possible API issue`,\n );\n }\n\n const response = await fetchWithRetry(url, headers);\n\n if (response.status === 401) {\n throw new Error(\n \"MASSIVE_API_KEY rejected by Massive.com — check your key\",\n );\n }\n\n if (!response.ok) {\n throw new Error(\n `Massive.com API error: HTTP ${response.status} ${response.statusText}`,\n );\n }\n\n const json = await response.json();\n\n const parsed = MassiveSnapshotResponseSchema.safeParse(json);\n if (!parsed.success) {\n const issues = parsed.error.issues\n .map((i) => `${String(i.path.join(\".\"))}: ${i.message}`)\n .join(\"; \");\n throw new Error(`Massive API response validation failed: ${issues}`);\n }\n\n const data = parsed.data;\n\n if (data.results.length > 0 && underlyingPrice === 0) {\n underlyingPrice = data.results[0].underlying_asset.price;\n underlyingTicker = fromMassiveTicker(\n data.results[0].underlying_asset.ticker,\n );\n }\n\n for (const contract of data.results) {\n allContracts.push(mapContract(contract));\n }\n\n if (data.next_url) {\n const nextUrlObj = new URL(data.next_url);\n const cursor = nextUrlObj.searchParams.get(\"cursor\") ?? data.next_url;\n if (seenCursors.has(cursor)) {\n throw new Error(\n `Pagination loop detected — cursor repeated: ${cursor.slice(0, 50)}...`,\n );\n }\n seenCursors.add(cursor);\n url = data.next_url;\n } else {\n url = null;\n }\n }\n\n return {\n contracts: allContracts,\n underlying_price: underlyingPrice,\n underlying_ticker: underlyingTicker,\n };\n }\n\n async fetchContractList(options: FetchContractListOptions): Promise<FetchContractListResult> {\n const apiKey = getApiKey();\n const { underlying, as_of, expired = true, expiration_date_gte, expiration_date_lte } = options;\n\n // The /v3/reference/options/contracts endpoint uses raw tickers (no I:/O: prefix).\n // The I: prefix is only for bars/aggs endpoints.\n const headers = { Authorization: `Bearer ${apiKey}` };\n\n const params = new URLSearchParams({\n underlying_ticker: underlying,\n limit: \"1000\",\n });\n // Polygon API: as_of and expiration_date filters are incompatible.\n // When expiration date filters are provided, drop as_of.\n if (expiration_date_gte || expiration_date_lte) {\n if (expiration_date_gte) params.set(\"expiration_date.gte\", expiration_date_gte);\n if (expiration_date_lte) params.set(\"expiration_date.lte\", expiration_date_lte);\n } else {\n params.set(\"as_of\", as_of);\n }\n if (expired) {\n params.set(\"expired\", \"true\");\n }\n\n let url: string | null =\n `${MASSIVE_BASE_URL}/v3/reference/options/contracts?${params.toString()}`;\n\n const allContracts: ContractReference[] = [];\n const seenCursors = new Set<string>();\n let pageCount = 0;\n\n while (url) {\n pageCount++;\n if (pageCount > MASSIVE_MAX_PAGES) {\n throw new Error(\n `Pagination safety limit reached (${MASSIVE_MAX_PAGES} pages) -- possible API issue`,\n );\n }\n\n const response = await fetchWithRetry(url, headers);\n\n if (response.status === 401) {\n throw new Error(\"MASSIVE_API_KEY rejected by Massive.com -- check your key\");\n }\n if (!response.ok) {\n throw new Error(`Massive.com API error: HTTP ${response.status} ${response.statusText}`);\n }\n\n const json = await response.json();\n const parsed = MassiveContractListResponseSchema.safeParse(json);\n if (!parsed.success) {\n const issues = parsed.error.issues\n .map((i) => `${String(i.path.join(\".\"))}: ${i.message}`)\n .join(\"; \");\n throw new Error(`Massive contract list response validation failed: ${issues}`);\n }\n\n for (const contract of parsed.data.results) {\n allContracts.push({\n ticker: fromMassiveTicker(contract.ticker),\n contract_type: contract.contract_type as \"call\" | \"put\",\n strike: contract.strike_price,\n expiration: contract.expiration_date,\n exercise_style: contract.exercise_style ?? \"american\",\n });\n }\n\n if (parsed.data.next_url) {\n const nextUrlObj = new URL(parsed.data.next_url);\n const cursor = nextUrlObj.searchParams.get(\"cursor\") ?? parsed.data.next_url;\n if (seenCursors.has(cursor)) {\n throw new Error(`Pagination loop detected -- cursor repeated: ${cursor.slice(0, 50)}...`);\n }\n seenCursors.add(cursor);\n url = parsed.data.next_url;\n } else {\n url = null;\n }\n }\n\n return { contracts: allContracts, underlying };\n }\n}\n","/**\n * Black-Scholes option pricing, greeks computation, and IV solver.\n * Includes Bachelier (normal) model as fallback for short-dated options.\n *\n * Pure math module — no I/O, no DuckDB, no fetch.\n * European-style BS formula with continuous dividend yield.\n *\n * References:\n * - CDF approximation: Abramowitz & Stegun 26.2.17 (rational approximation)\n * - IV solver: Newton-Raphson with bisection fallback (D-11: maxIter=100, tolerance=1e-6)\n * - Bachelier model: Brenner-Subrahmanyam (1988) normal model for near-zero DTE\n */\n\n/**\n * DTE threshold below which Bachelier normal model is used instead of Black-Scholes.\n * At very short DTE (<0.1 days / ~2.4 hours), BS gamma explodes and the lognormal assumption breaks down.\n * Bachelier (normal) model handles near-zero DTE gracefully.\n */\nexport const BACHELIER_DTE_THRESHOLD = 0.1; // days (~2.4 hours)\n\n/**\n * Result of computing greeks for a single option leg.\n */\nexport interface GreeksResult {\n delta: number | null;\n gamma: number | null;\n theta: number | null; // per day\n vega: number | null; // per 1% IV move\n iv: number | null; // annualized implied volatility (0-N, not percentage)\n model?: 'bs' | 'bachelier'; // which pricing model was used; undefined if IV solve failed\n}\n\n// --- Internal helpers (exported for Bachelier model and testing) ---\n\n/** Standard normal probability density function */\nexport function pdf(x: number): number {\n return Math.exp(-0.5 * x * x) / Math.sqrt(2 * Math.PI);\n}\n\n/**\n * Cumulative standard normal distribution function.\n * Uses Abramowitz & Stegun 26.2.17 rational approximation.\n * Accuracy: |error| < 7.5e-8\n */\nexport function cdf(x: number): number {\n if (x < -10) return 0;\n if (x > 10) return 1;\n\n const sign = x < 0 ? -1 : 1;\n const absX = Math.abs(x);\n\n const p = 0.2316419;\n const b1 = 0.319381530;\n const b2 = -0.356563782;\n const b3 = 1.781477937;\n const b4 = -1.821255978;\n const b5 = 1.330274429;\n\n const t = 1.0 / (1.0 + p * absX);\n const t2 = t * t;\n const t3 = t2 * t;\n const t4 = t3 * t;\n const t5 = t4 * t;\n\n const poly = b1 * t + b2 * t2 + b3 * t3 + b4 * t4 + b5 * t5;\n const result = 1.0 - pdf(absX) * poly;\n\n return sign === 1 ? result : 1.0 - result;\n}\n\n/** Compute d1 and d2 for Black-Scholes formula */\nfunction d1d2(\n S: number,\n K: number,\n T: number,\n r: number,\n q: number,\n sigma: number,\n): { d1: number; d2: number } {\n const sqrtT = Math.sqrt(T);\n const d1 = (Math.log(S / K) + (r - q + 0.5 * sigma * sigma) * T) / (sigma * sqrtT);\n const d2 = d1 - sigma * sqrtT;\n return { d1, d2 };\n}\n\n// --- Exported functions ---\n\n/**\n * European Black-Scholes option price with continuous dividend yield.\n *\n * @param type - \"call\" or \"put\"\n * @param S - Underlying price\n * @param K - Strike price\n * @param T - Time to expiry in years\n * @param r - Risk-free rate (e.g., 0.045)\n * @param q - Continuous dividend yield (e.g., 0.015 for SPX)\n * @param sigma - Volatility (annualized, e.g., 0.20 for 20%)\n * @returns Option price\n */\nexport function bsPrice(\n type: 'call' | 'put',\n S: number,\n K: number,\n T: number,\n r: number,\n q: number,\n sigma: number,\n): number {\n // Edge case: at or past expiry\n if (T <= 0) {\n return type === 'call' ? Math.max(S - K, 0) : Math.max(K - S, 0);\n }\n\n // Edge case: zero volatility — return discounted intrinsic\n if (sigma <= 0) {\n const forward = S * Math.exp((r - q) * T);\n if (type === 'call') {\n return Math.max(forward - K, 0) * Math.exp(-r * T);\n } else {\n return Math.max(K - forward, 0) * Math.exp(-r * T);\n }\n }\n\n const { d1, d2 } = d1d2(S, K, T, r, q, sigma);\n\n if (type === 'call') {\n return S * Math.exp(-q * T) * cdf(d1) - K * Math.exp(-r * T) * cdf(d2);\n } else {\n return K * Math.exp(-r * T) * cdf(-d2) - S * Math.exp(-q * T) * cdf(-d1);\n }\n}\n\n/**\n * Black-Scholes delta.\n * Call: N(d1) * e^(-qT)\n * Put: (N(d1) - 1) * e^(-qT)\n */\nexport function bsDelta(\n type: 'call' | 'put',\n S: number,\n K: number,\n T: number,\n r: number,\n q: number,\n sigma: number,\n): number {\n if (T <= 0 || sigma <= 0) {\n if (type === 'call') return S > K ? 1 : 0;\n return S < K ? -1 : 0;\n }\n\n const { d1 } = d1d2(S, K, T, r, q, sigma);\n const eqT = Math.exp(-q * T);\n\n if (type === 'call') {\n return cdf(d1) * eqT;\n } else {\n return (cdf(d1) - 1) * eqT;\n }\n}\n\n/**\n * Black-Scholes gamma. Same for calls and puts.\n * Gamma = N'(d1) * e^(-qT) / (S * sigma * sqrt(T))\n */\nexport function bsGamma(\n S: number,\n K: number,\n T: number,\n r: number,\n q: number,\n sigma: number,\n): number {\n if (T <= 0 || sigma <= 0) return 0;\n\n const { d1 } = d1d2(S, K, T, r, q, sigma);\n return (pdf(d1) * Math.exp(-q * T)) / (S * sigma * Math.sqrt(T));\n}\n\n/**\n * Black-Scholes theta (per calendar day).\n * Returns the daily time decay (negative for long options).\n */\nexport function bsTheta(\n type: 'call' | 'put',\n S: number,\n K: number,\n T: number,\n r: number,\n q: number,\n sigma: number,\n): number {\n if (T <= 0 || sigma <= 0) return 0;\n\n const { d1, d2 } = d1d2(S, K, T, r, q, sigma);\n const sqrtT = Math.sqrt(T);\n const eqT = Math.exp(-q * T);\n const erT = Math.exp(-r * T);\n\n // First term: -(S * e^(-qT) * N'(d1) * sigma) / (2 * sqrt(T))\n const term1 = -(S * eqT * pdf(d1) * sigma) / (2 * sqrtT);\n\n if (type === 'call') {\n const term2 = q * S * eqT * cdf(d1);\n const term3 = -r * K * erT * cdf(d2);\n return (term1 - term2 - term3) / 365;\n } else {\n const term2 = q * S * eqT * cdf(-d1);\n const term3 = -r * K * erT * cdf(-d2);\n return (term1 + term2 + term3) / 365;\n }\n}\n\n/**\n * Black-Scholes vega (per 1% IV move).\n * Vega = S * e^(-qT) * N'(d1) * sqrt(T) / 100\n */\nexport function bsVega(\n S: number,\n K: number,\n T: number,\n r: number,\n q: number,\n sigma: number,\n): number {\n if (T <= 0 || sigma <= 0) return 0;\n\n const { d1 } = d1d2(S, K, T, r, q, sigma);\n return (S * Math.exp(-q * T) * pdf(d1) * Math.sqrt(T)) / 100;\n}\n\n/**\n * Solve for implied volatility using Newton-Raphson with bisection fallback.\n *\n * @param type - \"call\" or \"put\"\n * @param marketPrice - Observed market price of the option\n * @param S - Underlying price\n * @param K - Strike price\n * @param T - Time to expiry in years\n * @param r - Risk-free rate\n * @param q - Dividend yield\n * @param maxIter - Maximum iterations (default 100, per D-11)\n * @param tolerance - Convergence tolerance (default 1e-6, per D-11)\n * @returns Implied volatility or null if convergence fails\n */\nexport function solveIV(\n type: 'call' | 'put',\n marketPrice: number,\n S: number,\n K: number,\n T: number,\n r: number,\n q: number,\n maxIter: number = 100,\n tolerance: number = 1e-6,\n): number | null {\n // Guard: invalid inputs\n if (marketPrice <= 0 || T <= 0) return null;\n\n let sigma = 0.3; // initial guess\n let lo = 0.001;\n let hi = 5.0;\n\n for (let i = 0; i < maxIter; i++) {\n const price = bsPrice(type, S, K, T, r, q, sigma);\n const diff = price - marketPrice;\n\n if (Math.abs(diff) < tolerance) {\n return sigma;\n }\n\n // Vega for Newton-Raphson step (raw vega, not per-1%-move)\n const { d1 } = d1d2(S, K, T, r, q, sigma);\n const rawVega = S * Math.exp(-q * T) * pdf(d1) * Math.sqrt(T);\n\n if (rawVega < 1e-10) {\n // Bisection fallback when vega is near zero\n const mid = (lo + hi) / 2;\n if (diff > 0) {\n hi = sigma;\n } else {\n lo = sigma;\n }\n sigma = mid;\n } else {\n // Newton-Raphson step\n const newSigma = sigma - diff / rawVega;\n // Clamp to reasonable range\n if (newSigma <= 0 || newSigma > 10) {\n // Fall back to bisection\n if (diff > 0) {\n hi = sigma;\n } else {\n lo = sigma;\n }\n sigma = (lo + hi) / 2;\n } else {\n sigma = newSigma;\n }\n }\n }\n\n // Did not converge\n return null;\n}\n\n// --- Bachelier (Normal) Model ---\n\n/**\n * Bachelier (normal) European option price with continuous dividend yield.\n * Uses forward price F = S * e^((r-q)*T) as the underlying.\n *\n * For near-zero DTE, the lognormal assumption in Black-Scholes breaks down.\n * Bachelier's model (normal distribution of returns) handles this gracefully.\n *\n * @param type - \"call\" or \"put\"\n * @param S - Underlying price\n * @param K - Strike price\n * @param T - Time to expiry in years\n * @param r - Risk-free rate (e.g., 0.045)\n * @param q - Continuous dividend yield (e.g., 0.015 for SPX)\n * @param sigma_n - Normal (dollar) volatility (e.g., 800 for SPX ~$800/year normal vol)\n * @returns Option price\n */\nexport function bachelierPrice(\n type: 'call' | 'put',\n S: number,\n K: number,\n T: number,\n r: number,\n q: number,\n sigma_n: number,\n): number {\n if (T <= 0) return type === 'call' ? Math.max(S - K, 0) : Math.max(K - S, 0);\n if (sigma_n <= 0) {\n const forward = S * Math.exp((r - q) * T);\n return Math.exp(-r * T) * (type === 'call' ? Math.max(forward - K, 0) : Math.max(K - forward, 0));\n }\n const forward = S * Math.exp((r - q) * T);\n const sqrtT = Math.sqrt(T);\n const d = (forward - K) / (sigma_n * sqrtT);\n const discount = Math.exp(-r * T);\n if (type === 'call') {\n return discount * ((forward - K) * cdf(d) + sigma_n * sqrtT * pdf(d));\n } else {\n return discount * ((K - forward) * cdf(-d) + sigma_n * sqrtT * pdf(d));\n }\n}\n\n/**\n * Bachelier delta.\n * Call: e^(-rT) * N(d)\n * Put: -e^(-rT) * N(-d)\n */\nexport function bachelierDelta(\n type: 'call' | 'put',\n S: number,\n K: number,\n T: number,\n r: number,\n q: number,\n sigma_n: number,\n): number {\n if (T <= 0 || sigma_n <= 0) {\n if (type === 'call') return S > K ? 1 : 0;\n return S < K ? -1 : 0;\n }\n const forward = S * Math.exp((r - q) * T);\n const d = (forward - K) / (sigma_n * Math.sqrt(T));\n const discount = Math.exp(-r * T);\n return type === 'call' ? discount * cdf(d) : -discount * cdf(-d);\n}\n\n/**\n * Bachelier gamma (same for calls and puts).\n * Gamma = e^(-rT) * n(d) / (sigma_n * sqrt(T))\n */\nexport function bachelierGamma(\n S: number,\n K: number,\n T: number,\n r: number,\n q: number,\n sigma_n: number,\n): number {\n if (T <= 0 || sigma_n <= 0) return 0;\n const forward = S * Math.exp((r - q) * T);\n const sqrtT = Math.sqrt(T);\n const d = (forward - K) / (sigma_n * sqrtT);\n return Math.exp(-r * T) * pdf(d) / (sigma_n * sqrtT);\n}\n\n/**\n * Bachelier theta (per calendar day).\n * Returns the daily time decay (negative for long options).\n * Formula: -(e^(-rT) * sigma_n * n(d) / (2 * sqrt(T)) - r * price) / 365\n */\nexport function bachelierTheta(\n type: 'call' | 'put',\n S: number,\n K: number,\n T: number,\n r: number,\n q: number,\n sigma_n: number,\n): number {\n if (T <= 0 || sigma_n <= 0) return 0;\n const forward = S * Math.exp((r - q) * T);\n const sqrtT = Math.sqrt(T);\n const d = (forward - K) / (sigma_n * sqrtT);\n const discount = Math.exp(-r * T);\n const price = bachelierPrice(type, S, K, T, r, q, sigma_n);\n // dV/dT = -e^(-rT) * sigma_n * n(d) / (2*sqrt(T)) + r * price (positive = more time = more value)\n // theta = -dV/dT per year, then / 365 for per-calendar-day\n // annualTheta is negative for long options (time decay)\n const annualTheta = -discount * sigma_n * pdf(d) / (2 * sqrtT) + r * price;\n return annualTheta / 365;\n}\n\n/**\n * Bachelier vega (per 1% normal vol move).\n * Raw vega = e^(-rT) * sqrt(T) * n(d). Per 1% = raw / 100.\n */\nexport function bachelierVega(\n S: number,\n K: number,\n T: number,\n r: number,\n q: number,\n sigma_n: number,\n): number {\n if (T <= 0 || sigma_n <= 0) return 0;\n const forward = S * Math.exp((r - q) * T);\n const d = (forward - K) / (sigma_n * Math.sqrt(T));\n return Math.exp(-r * T) * Math.sqrt(T) * pdf(d) / 100;\n}\n\n/**\n * Solve for normal (Bachelier) implied volatility using Newton-Raphson.\n *\n * @param type - \"call\" or \"put\"\n * @param marketPrice - Observed market price of the option\n * @param S - Underlying price\n * @param K - Strike price\n * @param T - Time to expiry in years\n * @param r - Risk-free rate\n * @param q - Dividend yield\n * @param maxIter - Maximum iterations (default 100)\n * @param tolerance - Convergence tolerance (default 1e-6)\n * @returns Normal implied volatility (dollar vol, e.g., ~800 for SPX) or null\n */\nexport function solveNormalIV(\n type: 'call' | 'put',\n marketPrice: number,\n S: number,\n K: number,\n T: number,\n r: number,\n q: number,\n maxIter: number = 100,\n tolerance: number = 1e-6,\n): number | null {\n if (marketPrice <= 0 || T <= 0) return null;\n // Initial guess: Brenner-Subrahmanyam for normal model\n // sigma_n ~ marketPrice / sqrt(T/(2*pi))\n let sigma_n = marketPrice / Math.sqrt(T / (2 * Math.PI));\n // Clamp initial guess to reasonable range\n sigma_n = Math.max(sigma_n, 1); // at least $1 normal vol\n\n // Bisection bounds — normal vol is in dollar terms (typically 10-10000 for index options)\n let lo = 0.01;\n let hi = 50000;\n\n for (let i = 0; i < maxIter; i++) {\n const price = bachelierPrice(type, S, K, T, r, q, sigma_n);\n const diff = price - marketPrice;\n if (Math.abs(diff) < tolerance) return sigma_n;\n // Raw vega for Newton step (without /100 per-1% scaling)\n const forward = S * Math.exp((r - q) * T);\n const d = (forward - K) / (sigma_n * Math.sqrt(T));\n const rawVega = Math.exp(-r * T) * Math.sqrt(T) * pdf(d);\n\n if (rawVega < 1e-10) {\n // Bisection fallback when vega is near zero\n if (diff > 0) {\n hi = sigma_n;\n } else {\n lo = sigma_n;\n }\n sigma_n = (lo + hi) / 2;\n } else {\n // Newton-Raphson step\n const newSigma = sigma_n - diff / rawVega;\n if (newSigma <= 0 || newSigma > 100000) {\n // Fall back to bisection\n if (diff > 0) {\n hi = sigma_n;\n } else {\n lo = sigma_n;\n }\n sigma_n = (lo + hi) / 2;\n } else {\n sigma_n = newSigma;\n }\n }\n }\n return null;\n}\n\n/**\n * Compute all greeks for a single option leg.\n *\n * First solves for IV from the market price, then computes delta, gamma, theta, vega.\n * Returns all nulls if IV cannot be determined.\n *\n * @param optionPrice - Market price of the option\n * @param underlyingPrice - Current underlying price (S)\n * @param strike - Option strike price (K)\n * @param dte - Days to expiry (fractional days, converted to years internally)\n * @param type - \"C\" for call, \"P\" for put\n * @param riskFreeRate - Risk-free interest rate\n * @param dividendYield - Continuous dividend yield\n * @returns GreeksResult with delta, gamma, theta, vega, iv (all nullable)\n */\nexport function computeLegGreeks(\n optionPrice: number,\n underlyingPrice: number,\n strike: number,\n dte: number,\n type: 'C' | 'P',\n riskFreeRate: number,\n dividendYield: number,\n): GreeksResult {\n const T = dte / 365;\n const bsType = type === 'C' ? 'call' : 'put';\n const nullResult: GreeksResult = { delta: null, gamma: null, theta: null, vega: null, iv: null };\n\n if (dte < BACHELIER_DTE_THRESHOLD) {\n // Bachelier normal model for short-dated options (dte < 0.1 days / ~2.4 hours).\n // iv field stores normal (dollar) volatility, not log-normal vol.\n const iv = solveNormalIV(bsType, optionPrice, underlyingPrice, strike, T, riskFreeRate, dividendYield);\n if (iv === null) return nullResult;\n return {\n delta: bachelierDelta(bsType, underlyingPrice, strike, T, riskFreeRate, dividendYield, iv),\n gamma: bachelierGamma(underlyingPrice, strike, T, riskFreeRate, dividendYield, iv),\n theta: bachelierTheta(bsType, underlyingPrice, strike, T, riskFreeRate, dividendYield, iv),\n vega: bachelierVega(underlyingPrice, strike, T, riskFreeRate, dividendYield, iv),\n iv,\n model: 'bachelier',\n };\n }\n\n // Black-Scholes for longer-dated options (dte >= 0.1 days).\n // iv field stores annualized log-normal volatility (0-N, not percentage).\n const iv = solveIV(bsType, optionPrice, underlyingPrice, strike, T, riskFreeRate, dividendYield);\n if (iv === null) return nullResult;\n return {\n delta: bsDelta(bsType, underlyingPrice, strike, T, riskFreeRate, dividendYield, iv),\n gamma: bsGamma(underlyingPrice, strike, T, riskFreeRate, dividendYield, iv),\n theta: bsTheta(bsType, underlyingPrice, strike, T, riskFreeRate, dividendYield, iv),\n vega: bsVega(underlyingPrice, strike, T, riskFreeRate, dividendYield, iv),\n iv,\n model: 'bs',\n };\n}\n","export type MassiveDataTier = 'ohlc' | 'trades' | 'quotes';\n\nexport function resolveMassiveDataTier(\n env: NodeJS.ProcessEnv = process.env,\n): MassiveDataTier {\n const tier = (env.MASSIVE_DATA_TIER ?? '').toLowerCase();\n if (tier === 'quotes' || tier === 'trades' || tier === 'ohlc') {\n return tier;\n }\n return 'ohlc';\n}\n","/**\n * Trade Replay Pure Logic Module\n *\n * OCC ticker construction, tradelog legs string parsing, multi-leg P&L path\n * computation with HL2 mark pricing, and MFE/MAE calculation.\n *\n * All functions are pure — no fetch, no DuckDB.\n */\n\nimport type { BarRow } from './market-provider.ts';\nimport { computeLegGreeks, type GreeksResult } from './black-scholes.ts';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** A parsed leg from a tradelog \"legs\" string (before OCC ticker resolution). */\nexport interface ParsedLeg {\n root: string; // \"SPY\", \"SPX\", \"SPXW\"\n strike: number; // Numeric strike price\n type: 'C' | 'P'; // Call or Put\n quantity: number; // +1 or -1 (direction derived from position in spread)\n}\n\n/** A fully resolved leg ready for replay (after OCC ticker construction). */\nexport interface ReplayLeg {\n occTicker: string; // Full OCC ticker for Massive API fetch\n quantity: number; // Positive = long, negative = short\n entryPrice: number; // Per-contract entry price\n multiplier: number; // 100 for standard equity/index options\n}\n\n/** A single point on the strategy P&L path. */\nexport interface PnlPoint {\n timestamp: string; // \"YYYY-MM-DD HH:MM\" ET\n strategyPnl: number; // Combined P&L across all legs at this minute\n legPrices: number[]; // Mark price for each leg at this minute (bid/ask mid or HL2 fallback)\n underlyingPrice?: number; // Underlying price used for greeks / decomposition at this timestamp\n // Per-leg greeks (Phase 69) — array parallel to legPrices\n legGreeks?: GreeksResult[];\n // Net position greeks — quantity-weighted aggregation across legs\n netDelta?: number | null;\n netGamma?: number | null;\n netTheta?: number | null;\n netVega?: number | null;\n // IVP from canonical market datasets (typically VIX ticker rows in market.enriched)\n ivp?: number | null;\n // True when all legs have synchronized quotes at this minute; false when one or more\n // legs lack a fresh quote. Triggers like profitTarget gate hit-counting on this so\n // unsynchronized bars don't count toward confirmation and don't reset the counter.\n // When undefined (no producer populates the field) consumers treat the bar as synchronized.\n // TODO: populated by a future quote-sync detector — currently forward-compat only.\n allLegsSync?: boolean;\n}\n\n/** Configuration for greeks computation in P&L path. */\nexport interface GreeksConfig {\n underlyingPrices: Map<string, number>; // timestamp -> underlying price\n legs: Array<{ strike: number; type: 'C' | 'P'; expiryDate: string }>; // per-leg BS inputs\n riskFreeRate: number; // e.g. 0.045\n dividendYield: number; // e.g. 0.015 for SPX, 0 otherwise\n ivpByDate?: Map<string, number>; // date -> IVP value\n /** Sorted intraday timestamps from underlyingPrices for nearest-timestamp binary search. */\n sortedTimestamps?: string[];\n}\n\n/** Complete replay result with P&L path, MFE/MAE, and metadata. */\nexport interface ReplayResult {\n pnlPath: PnlPoint[];\n mfe: number; // Max of strategyPnl series\n mae: number; // Min of strategyPnl series\n mfeTimestamp: string; // When MFE occurred\n maeTimestamp: string; // When MAE occurred\n totalPnl: number; // Final P&L at last bar\n totalBars?: number; // Total minute bars before format filtering\n legs: ReplayLeg[]; // The legs that were replayed\n greeksWarning?: string | null; // D-12: warning when >50% of leg-timestamps have null greeks\n}\n\n// ---------------------------------------------------------------------------\n// markPrice\n// ---------------------------------------------------------------------------\n\n/**\n * Prefer (bid+ask)/2 when both are present and non-zero; fall back to HL2.\n *\n * When providers supply bid/ask data (e.g., option chains), the midpoint is a\n * more accurate mark price than HL2. This is opt-in — existing data without\n * bid/ask continues to use HL2 identically.\n *\n * Guards against broken exchange quotes (crossed bid>ask; blown ask>10×bid\n * with mid>$1) by falling back to HL2.\n */\nexport function markPrice(bar: Pick<BarRow, 'high' | 'low' | 'bid' | 'ask'>): number {\n const { bid, ask } = bar;\n const hl2 = (bar.high + bar.low) / 2;\n if (bid != null && ask != null && (bid > 0 || ask > 0)) {\n if (bid > 0 && ask > 0) {\n if (bid > ask) return hl2;\n if (ask > 10 * bid && (bid + ask) / 2 > 1) return hl2;\n }\n return (bid + ask) / 2;\n }\n return hl2;\n}\n\n// ---------------------------------------------------------------------------\n// findNearestTimestamp\n// ---------------------------------------------------------------------------\n\n/**\n * Find the nearest timestamp in a sorted array within tolerance (seconds).\n * Uses binary search for O(log n) performance.\n *\n * Timestamps are compared by minutes-since-midnight (HH:MM format).\n * Returns undefined if no timestamp is within the tolerance.\n *\n * Per D-07/D-08: Tolerates up to 60s mismatch between option and underlying bars.\n */\nexport function findNearestTimestamp(\n sortedTimestamps: string[],\n target: string,\n toleranceSec: number = 60,\n): string | undefined {\n if (sortedTimestamps.length === 0) return undefined;\n\n const targetMin = timestampToMinutes(target);\n if (targetMin === null) return undefined;\n\n let lo = 0, hi = sortedTimestamps.length - 1;\n let bestIdx = 0;\n let bestDiff = Infinity;\n\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1;\n const midMin = timestampToMinutes(sortedTimestamps[mid]);\n if (midMin === null) { lo = mid + 1; continue; }\n\n const diff = Math.abs(midMin - targetMin);\n if (diff < bestDiff) { bestDiff = diff; bestIdx = mid; }\n if (midMin < targetMin) lo = mid + 1;\n else if (midMin > targetMin) hi = mid - 1;\n else break; // exact match\n }\n\n // bestDiff is in minutes; convert tolerance from seconds\n return bestDiff <= toleranceSec / 60 ? sortedTimestamps[bestIdx] : undefined;\n}\n\nfunction timestampToMinutes(ts: string): number | null {\n const timePart = ts.split(' ')[1];\n if (!timePart) return null;\n const [h, m] = timePart.split(':').map(Number);\n if (isNaN(h) || isNaN(m)) return null;\n return h * 60 + m;\n}\n\n// ---------------------------------------------------------------------------\n// parseLegsString\n// ---------------------------------------------------------------------------\n\n// Compact format with root: \"SPY 470C\", \"SPX 4500P\", \"SPY 0.50C\"\nconst COMPACT_LEG_RE = /^([A-Z]+)\\s+(\\d+(?:\\.\\d+)?)\\s*(C|P)$/i;\n\n// Compact format without root (subsequent legs in spreads): \"465C\", \"500C\"\nconst COMPACT_NO_ROOT_RE = /^(\\d+(?:\\.\\d+)?)\\s*(C|P)$/i;\n\n// Verbose format: \"SPY Jan25 470 Call\", \"SPX Feb25 4500 Put\"\nconst VERBOSE_LEG_RE = /^([A-Z]+)\\s+\\w+\\s+(\\d+(?:\\.\\d+)?)\\s+(Call|Put)$/i;\n\n// Option Omega format: \"{contracts} {Mon} {day} {strike} {P|C} {STO|BTO} {price}\"\n// Example: \"397 Mar 12 6610 P STO 35.85\"\n// Captures: (1)contracts (2)month (3)day (4)strike (5)C|P (6)STO|BTO (7)price\nconst OO_LEG_RE = /^(\\d+)\\s+(\\w+)\\s+(\\d+)\\s+(\\d+(?:\\.\\d+)?)\\s+(C|P)\\s+(STO|BTO|STC|BTC)\\s+(\\d+(?:\\.\\d+)?)$/i;\n\n/** Extended parsed leg with entry price from OO format. */\nexport interface ParsedLegOO extends ParsedLeg {\n entryPrice?: number; // Fill price from OO leg (e.g., 35.85)\n contracts?: number; // Contract count from OO leg\n expiryHint?: string; // \"Mon DD\" from OO format (e.g., \"Mar 12\") for multi-expiry strategies\n}\n\n/**\n * Parse a tradelog \"legs\" string into structured ParsedLeg objects.\n *\n * Supported formats:\n * - \"SPY 470C\" (single leg)\n * - \"SPY 470C/465C\" (two-leg spread, \"/\" delimiter)\n * - \"SPY 490C/500C/510C\" (butterfly)\n * - \"SPY Jan25 470 Call\" (verbose format)\n * - Option Omega pipe-delimited format:\n * \"397 Mar 12 6610 P STO 35.85 | 397 Mar 12 6925 C STO 10.90 | ...\"\n * Direction: STO = short (-1), BTO = long (+1)\n * Includes per-leg entry price and contract count\n *\n * @throws Error if legs string is empty or cannot be parsed\n */\nexport function parseLegsString(legsStr: string): ParsedLegOO[] {\n if (!legsStr || legsStr.trim() === '') {\n throw new Error('Cannot parse legs \"\" — use hypothetical mode with explicit strikes');\n }\n\n // Detect Option Omega pipe-delimited format\n if (legsStr.includes('|')) {\n return parseOOLegs(legsStr);\n }\n\n const parts = legsStr.includes('/') ? legsStr.split('/') : [legsStr];\n const legs: ParsedLegOO[] = [];\n let inheritedRoot = '';\n\n for (let i = 0; i < parts.length; i++) {\n const raw = parts[i].trim();\n let root: string;\n let strike: number;\n let type: 'C' | 'P';\n\n const compactMatch = raw.match(COMPACT_LEG_RE);\n if (compactMatch) {\n root = compactMatch[1].toUpperCase();\n strike = parseFloat(compactMatch[2]);\n type = compactMatch[3].toUpperCase() as 'C' | 'P';\n } else {\n // Try compact without root (e.g., \"465C\" in \"SPY 470C/465C\")\n const noRootMatch = raw.match(COMPACT_NO_ROOT_RE);\n if (noRootMatch && inheritedRoot) {\n root = inheritedRoot;\n strike = parseFloat(noRootMatch[1]);\n type = noRootMatch[2].toUpperCase() as 'C' | 'P';\n } else {\n const verboseMatch = raw.match(VERBOSE_LEG_RE);\n if (verboseMatch) {\n root = verboseMatch[1].toUpperCase();\n strike = parseFloat(verboseMatch[2]);\n type = verboseMatch[3].toLowerCase() === 'call' ? 'C' : 'P';\n } else {\n throw new Error(\n `Cannot parse legs \"${legsStr}\" — use hypothetical mode with explicit strikes`\n );\n }\n }\n }\n\n // Propagate root to subsequent legs that may omit it\n if (i === 0) inheritedRoot = root;\n\n // First leg is bought (+1), subsequent alternate -1, +1, -1...\n const quantity = i === 0 ? 1 : (i % 2 === 0 ? 1 : -1);\n\n legs.push({ root, strike, type, quantity });\n }\n\n return legs;\n}\n\n/**\n * Parse Option Omega pipe-delimited legs format.\n *\n * Each segment: \"{contracts} {Mon} {day} {strike} {P|C} {STO|BTO} {price}\"\n * STO = sell-to-open (short, quantity = -1), BTO = buy-to-open (long, quantity = +1)\n *\n * Dedup key includes date+strike+type to handle:\n * - Calendar spreads: same strike, different expiry (both kept)\n * - Open+close fills: same strike, same date, opposite direction (close dropped)\n */\nfunction parseOOLegs(legsStr: string): ParsedLegOO[] {\n const segments = legsStr.split('|').map(s => s.trim());\n const legs: ParsedLegOO[] = [];\n const seen = new Set<string>();\n\n for (const seg of segments) {\n const match = seg.match(OO_LEG_RE);\n if (!match) {\n throw new Error(\n `Cannot parse OO leg segment \"${seg}\" — use hypothetical mode with explicit strikes`\n );\n }\n\n const contracts = parseInt(match[1], 10);\n const month = match[2];\n const day = match[3];\n const strike = parseFloat(match[4]);\n const type = match[5].toUpperCase() as 'C' | 'P';\n const direction = match[6].toUpperCase();\n const price = parseFloat(match[7]);\n\n // Dedup by date+strike+type: keeps calendar legs (different dates),\n // drops close fills (same date+strike+type, opposite direction)\n const key = `${month}${day}:${strike}${type}`;\n if (seen.has(key)) continue;\n seen.add(key);\n\n legs.push({\n root: '', // OO format doesn't include root — caller provides via trade's ticker field\n strike,\n type,\n quantity: direction === 'BTO' ? 1 : -1,\n entryPrice: price,\n contracts,\n expiryHint: `${month} ${day}`,\n });\n }\n\n return legs;\n}\n\n// ---------------------------------------------------------------------------\n// buildOccTicker\n// ---------------------------------------------------------------------------\n\n/**\n * Build an OCC-format option ticker from components.\n *\n * Format: {root}{YYMMDD}{C|P}{strike*1000 padded to 8 digits}\n *\n * Example: SPY, 2025-01-17, C, 470 -> \"SPY250117C00470000\"\n */\nexport function buildOccTicker(\n root: string,\n expiry: string,\n type: 'C' | 'P',\n strike: number,\n): string {\n // Extract YYMMDD from \"YYYY-MM-DD\"\n const [yyyy, mm, dd] = expiry.split('-');\n const yy = yyyy.slice(2);\n\n // Strike * 1000 padded to 8 digits\n const strikeInt = Math.round(strike * 1000);\n const strikePadded = String(strikeInt).padStart(8, '0');\n\n return `${root}${yy}${mm}${dd}${type}${strikePadded}`;\n}\n\n// ---------------------------------------------------------------------------\n// computeStrategyPnlPath\n// ---------------------------------------------------------------------------\n\n/**\n * Combine per-leg minute bars into a single strategy P&L path.\n *\n * Mark price at each minute = (bid+ask)/2 when available, else HL2 = (high + low) / 2.\n * Combined P&L = sum across legs of (currentMark - entryPrice) * quantity * multiplier.\n *\n * Only includes timestamps where ALL legs have a bar.\n * Returns empty array if any leg has no bars.\n */\nexport function computeStrategyPnlPath(\n legs: ReplayLeg[],\n barsByLeg: BarRow[][],\n greeksConfig?: GreeksConfig,\n): PnlPoint[] {\n if (legs.length === 0 || barsByLeg.length === 0) return [];\n\n // Check if any leg has no bars\n for (const bars of barsByLeg) {\n if (bars.length === 0) return [];\n }\n\n // Build maps of timestamp -> bar for each leg\n const legMaps: Map<string, BarRow>[] = barsByLeg.map((bars) => {\n const map = new Map<string, BarRow>();\n for (const bar of bars) {\n const ts = `${bar.date} ${bar.time ?? ''}`.trim();\n map.set(ts, bar);\n }\n return map;\n });\n\n // Collect ALL unique timestamps across ALL legs (union, not intersection)\n const allTimestamps = new Set<string>();\n for (const bars of barsByLeg) {\n for (const bar of bars) {\n allTimestamps.add(`${bar.date} ${bar.time ?? ''}`.trim());\n }\n }\n const sortedTimestamps = [...allTimestamps].sort();\n\n // Build P&L path with forward-fill for missing bars\n const path: PnlPoint[] = [];\n const lastBar: (BarRow | undefined)[] = new Array(legs.length).fill(undefined);\n\n\n for (const ts of sortedTimestamps) {\n let complete = true;\n const legPrices: number[] = [];\n let strategyPnl = 0;\n\n for (let i = 0; i < legs.length; i++) {\n const bar = legMaps[i].get(ts);\n if (bar) {\n lastBar[i] = bar;\n }\n const effective = bar ?? lastBar[i];\n if (!effective) {\n complete = false;\n break;\n }\n const hl2 = markPrice(effective);\n legPrices.push(hl2);\n strategyPnl += (hl2 - legs[i].entryPrice) * legs[i].quantity * legs[i].multiplier;\n }\n\n if (complete) {\n const point: PnlPoint = { timestamp: ts, strategyPnl, legPrices };\n\n // Compute greeks if config provided\n if (greeksConfig) {\n // Look up underlying price — try exact timestamp, then nearest within 60s, then date-only\n let underlyingPrice = greeksConfig.underlyingPrices.get(ts);\n if (underlyingPrice === undefined && greeksConfig.sortedTimestamps) {\n const nearest = findNearestTimestamp(greeksConfig.sortedTimestamps, ts, 60);\n if (nearest) underlyingPrice = greeksConfig.underlyingPrices.get(nearest);\n }\n if (underlyingPrice === undefined) {\n const dateOnly = ts.split(' ')[0];\n underlyingPrice = greeksConfig.underlyingPrices.get(dateOnly);\n }\n\n if (underlyingPrice !== undefined) {\n point.underlyingPrice = underlyingPrice;\n const legGreeksArr: GreeksResult[] = [];\n let netDelta = 0, netGamma = 0, netTheta = 0, netVega = 0;\n let allNull = true;\n\n for (let j = 0; j < legs.length; j++) {\n const legCfg = greeksConfig.legs[j];\n if (!legCfg || !legCfg.expiryDate) {\n legGreeksArr.push({ delta: null, gamma: null, theta: null, vega: null, iv: null });\n continue;\n }\n\n // Compute fractional DTE from bar timestamp to leg expiry\n const dateStr = ts.split(' ')[0];\n const timePart = ts.split(' ')[1] ?? '09:30';\n const [eyy, emm, edd] = legCfg.expiryDate.split('-').map(Number);\n const [byy, bmm, bdd] = dateStr.split('-').map(Number);\n const [hh, min] = timePart.split(':').map(Number);\n\n const expiryMs = new Date(eyy, emm - 1, edd).getTime() + 16 * 60 * 60 * 1000; // 4:00 PM ET\n const barMs = new Date(byy, bmm - 1, bdd).getTime() + (hh * 60 + min) * 60 * 1000;\n const dte = (expiryMs - barMs) / (1000 * 60 * 60 * 24);\n\n if (dte <= 0) {\n legGreeksArr.push({ delta: null, gamma: null, theta: null, vega: null, iv: null });\n continue;\n }\n\n const g = computeLegGreeks(\n legPrices[j],\n underlyingPrice,\n legCfg.strike,\n dte,\n legCfg.type,\n greeksConfig.riskFreeRate,\n greeksConfig.dividendYield,\n );\n legGreeksArr.push(g);\n\n if (g.delta !== null) {\n allNull = false;\n const weight = legs[j].quantity * legs[j].multiplier / 100;\n netDelta += g.delta * weight;\n netGamma += g.gamma! * weight;\n netTheta += g.theta! * weight;\n netVega += g.vega! * weight;\n }\n }\n\n point.legGreeks = legGreeksArr;\n point.netDelta = allNull ? null : netDelta;\n point.netGamma = allNull ? null : netGamma;\n point.netTheta = allNull ? null : netTheta;\n point.netVega = allNull ? null : netVega;\n\n\n // IVP lookup by date\n const ivpDate = ts.split(' ')[0];\n point.ivp = greeksConfig.ivpByDate?.get(ivpDate) ?? null;\n }\n }\n\n path.push(point);\n }\n }\n\n return path;\n}\n\n// ---------------------------------------------------------------------------\n// computeReplayMfeMae\n// ---------------------------------------------------------------------------\n\n/**\n * Compute MFE (Maximum Favorable Excursion) and MAE (Maximum Adverse Excursion)\n * from a P&L path.\n *\n * MFE = max of strategyPnl series\n * MAE = min of strategyPnl series\n */\nexport function computeReplayMfeMae(pnlPath: PnlPoint[]): {\n mfe: number;\n mae: number;\n mfeTimestamp: string;\n maeTimestamp: string;\n} {\n if (pnlPath.length === 0) {\n return { mfe: 0, mae: 0, mfeTimestamp: '', maeTimestamp: '' };\n }\n\n let mfe = pnlPath[0].strategyPnl;\n let mae = pnlPath[0].strategyPnl;\n let mfeTimestamp = pnlPath[0].timestamp;\n let maeTimestamp = pnlPath[0].timestamp;\n\n for (let i = 1; i < pnlPath.length; i++) {\n const pnl = pnlPath[i].strategyPnl;\n if (pnl > mfe) {\n mfe = pnl;\n mfeTimestamp = pnlPath[i].timestamp;\n }\n if (pnl < mae) {\n mae = pnl;\n maeTimestamp = pnlPath[i].timestamp;\n }\n }\n\n return { mfe, mae, mfeTimestamp, maeTimestamp };\n}\n","import { readFileSync } from \"fs\";\n\nexport interface ThetaCredentials {\n email: string;\n password: string;\n source: string;\n}\n\nexport interface ThetaAuthResult {\n sessionId: string;\n stockSubscription?: number;\n optionsSubscription?: number;\n indicesSubscription?: number;\n}\n\nconst TERMINAL_KEY = \"cf58ada4-4175-11f0-860f-1e2e95c79e64\";\nconst AUTH_URL = \"https://nexus-api.thetadata.us/identity/terminal/auth_user\";\n\nfunction nonEmpty(value: string | undefined): string | undefined {\n const trimmed = value?.trim();\n return trimmed ? trimmed : undefined;\n}\n\nexport function resolveThetaCredentials(env: NodeJS.ProcessEnv = process.env): ThetaCredentials {\n const email = nonEmpty(env.THETADATA_EMAIL);\n const password = nonEmpty(env.THETADATA_PASSWORD);\n if (email && password) return { email, password, source: \"env\" };\n\n const filePath = nonEmpty(env.THETADATA_CREDENTIALS_FILE);\n if (filePath) {\n const [fileEmail, filePassword] = readFileSync(filePath, \"utf8\")\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter(Boolean);\n if (fileEmail && filePassword) {\n return { email: fileEmail, password: filePassword, source: filePath };\n }\n throw new Error(`ThetaData credentials file is missing email or password: ${filePath}`);\n }\n\n throw new Error(\n \"ThetaData credentials missing. Set THETADATA_EMAIL and THETADATA_PASSWORD, or THETADATA_CREDENTIALS_FILE.\",\n );\n}\n\nexport function thetaConcurrencyForTier(tier: number | undefined): number {\n if (!Number.isInteger(tier) || tier == null || tier < 0) return 1;\n return Math.max(1, 2 ** tier);\n}\n\nfunction statusLabel(response: Response): string {\n const statusText = nonEmpty(response.statusText);\n return statusText ? `${response.status} ${statusText}` : String(response.status);\n}\n\nfunction integerOrUndefined(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isInteger(value) ? value : undefined;\n}\n\nexport async function authenticateThetaData(\n credentials: ThetaCredentials,\n fetchImpl: typeof fetch = fetch,\n): Promise<ThetaAuthResult> {\n const response = await fetchImpl(AUTH_URL, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"TD-TERMINAL-KEY\": TERMINAL_KEY,\n },\n body: JSON.stringify({\n email: credentials.email,\n password: credentials.password,\n }),\n });\n\n if (!response.ok) {\n throw new Error(`ThetaData authentication failed (${statusLabel(response)})`);\n }\n\n const parsed = JSON.parse(await response.text()) as {\n sessionId?: unknown;\n user?: {\n stockSubscription?: unknown;\n optionsSubscription?: unknown;\n indicesSubscription?: unknown;\n };\n };\n const sessionId = typeof parsed.sessionId === \"string\" ? nonEmpty(parsed.sessionId) : undefined;\n if (!sessionId) throw new Error(\"ThetaData authentication response missing sessionId\");\n return {\n sessionId,\n stockSubscription: integerOrUndefined(parsed.user?.stockSubscription),\n optionsSubscription: integerOrUndefined(parsed.user?.optionsSubscription),\n indicesSubscription: integerOrUndefined(parsed.user?.indicesSubscription),\n };\n}\n","import * as grpc from \"@grpc/grpc-js\";\nimport { authenticateThetaData, resolveThetaCredentials, thetaConcurrencyForTier } from \"./auth.ts\";\n\nexport interface ThetaMddsConfig {\n target: string;\n maxAttempts: number;\n retryBaseMs: number;\n maxConcurrency?: number;\n}\n\nfunction positiveInteger(value: string | undefined, fallback: number): number {\n const parsed = Number(value);\n return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback;\n}\n\nfunction optionalPositiveInteger(value: string | undefined): number | undefined {\n const parsed = Number(value);\n return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined;\n}\n\nexport function getThetaMddsConfig(env: NodeJS.ProcessEnv = process.env): ThetaMddsConfig {\n const host = env.THETADATA_MDDS_HOST || \"mdds-01.thetadata.us\";\n const port = env.THETADATA_MDDS_PORT || \"443\";\n return {\n target: `${host}:${port}`,\n maxAttempts: positiveInteger(env.THETADATA_MDDS_MAX_ATTEMPTS, 4),\n retryBaseMs: positiveInteger(env.THETADATA_MDDS_RETRY_BASE_MS, 250),\n maxConcurrency: optionalPositiveInteger(env.THETADATA_MDDS_MAX_CONCURRENCY),\n };\n}\n\nexport function buildThetaQueryInfo(sessionId: string, env: NodeJS.ProcessEnv = process.env) {\n const clientType = env.THETADATA_MDDS_CLIENT_TYPE || \"terminal\";\n return {\n authToken: { sessionUuid: sessionId },\n queryParameters: { client: \"terminal\" },\n clientType,\n terminalGitCommit: \"\",\n terminalVersion: \"tradeblocks-mdds\",\n };\n}\n\nexport function isRetryableGrpcCode(code: number | undefined): boolean {\n return code === grpc.status.UNAVAILABLE\n || code === grpc.status.DEADLINE_EXCEEDED\n || code === grpc.status.RESOURCE_EXHAUSTED;\n}\n\ninterface MddsStreamCall<T = unknown> {\n on(event: \"data\", listener: (chunk: T) => void): unknown;\n on(event: \"error\", listener: (error: unknown) => void): unknown;\n on(event: \"end\", listener: () => void): unknown;\n}\n\ntype MddsStreamMethod = (this: MddsClientStub, request: unknown) => MddsStreamCall;\ninterface MddsClientStub {\n [method: string]: MddsStreamMethod | (() => void) | undefined;\n close?: () => void;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport class ThetaMddsClient {\n private sessionId: string | null = null;\n private stub: MddsClientStub | null = null;\n private connectPromise: Promise<void> | null = null;\n private connectionGeneration = 0;\n private concurrencyLimit = 1;\n private inFlight = 0;\n private waiters: Array<{ resolve: () => void; reject: (error: unknown) => void }> = [];\n\n private readonly env: NodeJS.ProcessEnv;\n private readonly fetchImpl: typeof fetch;\n private readonly loadGrpcPackage: () => Promise<unknown>;\n constructor(\n env: NodeJS.ProcessEnv = process.env,\n fetchImpl: typeof fetch = fetch,\n loadGrpcPackage: () => Promise<unknown> = async () => {\n const { loadMddsGrpcPackage } = await import(\"./proto.ts\");\n return loadMddsGrpcPackage();\n },\n ) {\n this.env = env;\n this.fetchImpl = fetchImpl;\n this.loadGrpcPackage = loadGrpcPackage;\n }\n\n async connect(): Promise<void> {\n if (this.stub) return;\n if (!this.connectPromise) {\n const generation = this.connectionGeneration;\n const promise = this.establishConnection(generation).catch((error: unknown) => {\n if (this.connectPromise === promise) this.connectPromise = null;\n throw error;\n });\n this.connectPromise = promise;\n }\n await this.connectPromise;\n }\n\n private async establishConnection(generation: number): Promise<void> {\n const credentials = resolveThetaCredentials(this.env);\n const auth = await authenticateThetaData(credentials, this.fetchImpl);\n const config = getThetaMddsConfig(this.env);\n const pkg = await this.loadGrpcPackage() as {\n BetaEndpoints?: {\n BetaThetaTerminal?: new (\n target: string,\n creds: grpc.ChannelCredentials,\n options?: grpc.ChannelOptions,\n ) => MddsClientStub;\n };\n };\n const Ctor = pkg.BetaEndpoints?.BetaThetaTerminal;\n if (!Ctor) throw new Error(\"ThetaData MDDS proto missing BetaEndpoints.BetaThetaTerminal\");\n const stub = new Ctor(config.target, grpc.credentials.createSsl(), {\n \"grpc.max_receive_message_length\": 256 * 1024 * 1024,\n \"grpc.keepalive_time_ms\": 30_000,\n });\n if (generation !== this.connectionGeneration) {\n stub.close?.();\n throw new Error(\"ThetaMddsClient connection was closed before it completed\");\n }\n this.sessionId = auth.sessionId;\n this.concurrencyLimit = config.maxConcurrency ?? thetaConcurrencyForTier(auth.optionsSubscription);\n this.stub = stub;\n }\n\n close(): void {\n this.connectionGeneration++;\n this.stub?.close?.();\n this.stub = null;\n this.sessionId = null;\n this.connectPromise = null;\n this.inFlight = 0;\n const waiters = this.waiters.splice(0);\n for (const waiter of waiters) {\n waiter.reject(new Error(\"ThetaMddsClient is closed\"));\n }\n }\n\n queryInfo(): ReturnType<typeof buildThetaQueryInfo> {\n if (!this.sessionId) throw new Error(\"ThetaMddsClient is not connected\");\n return buildThetaQueryInfo(this.sessionId, this.env);\n }\n\n private async acquire(): Promise<void> {\n if (this.inFlight < this.concurrencyLimit) {\n this.inFlight++;\n return;\n }\n await new Promise<void>((resolve, reject) => this.waiters.push({ resolve, reject }));\n }\n\n private release(): void {\n const next = this.waiters.shift();\n if (next) {\n next.resolve();\n return;\n }\n this.inFlight = Math.max(0, this.inFlight - 1);\n }\n\n private assertOpen(generation: number): void {\n if (generation !== this.connectionGeneration || !this.stub) {\n throw new Error(\"ThetaMddsClient is closed\");\n }\n }\n\n private getStreamMethod(stub: MddsClientStub, method: string): MddsStreamMethod {\n const candidate = method === \"close\" ? undefined : stub[method];\n if (typeof candidate !== \"function\") {\n throw new Error(`ThetaData MDDS method not found: ${method}`);\n }\n return candidate as MddsStreamMethod;\n }\n\n async callStream<T>(method: string, request: unknown): Promise<T[]> {\n if (!this.stub) await this.connect();\n const callGeneration = this.connectionGeneration;\n const config = getThetaMddsConfig(this.env);\n let lastError: unknown;\n for (let attempt = 1; attempt <= config.maxAttempts; attempt++) {\n this.assertOpen(callGeneration);\n await this.acquire();\n let releasePermit = true;\n try {\n this.assertOpen(callGeneration);\n const stub = this.stub!;\n const streamMethod = this.getStreamMethod(stub, method);\n const call = streamMethod.call(stub, request) as MddsStreamCall<T>;\n return await new Promise<T[]>((resolve, reject) => {\n const rows: T[] = [];\n call.on(\"data\", (chunk: T) => rows.push(chunk));\n call.on(\"error\", reject);\n call.on(\"end\", () => resolve(rows));\n });\n } catch (error) {\n lastError = error;\n const code = typeof error === \"object\" && error && \"code\" in error\n ? Number((error as { code: unknown }).code)\n : undefined;\n if (!isRetryableGrpcCode(code) || attempt === config.maxAttempts) throw error;\n this.release();\n releasePermit = false;\n await sleep(config.retryBaseMs * attempt);\n this.assertOpen(callGeneration);\n } finally {\n if (releasePermit) this.release();\n }\n }\n throw lastError;\n }\n}\n","import { decompress } from \"fzstd\";\nimport { loadMddsProtoRoot } from \"./proto.ts\";\n\nexport type ThetaCellValue = string | number | null;\n\nexport interface DecodedThetaTable {\n headers: string[];\n rows: Array<Record<string, ThetaCellValue>>;\n}\n\nexport interface ThetaPriceLike {\n value: number;\n type: number;\n}\n\nconst PRICE_TYPE_FACTORS = [\n 0,\n 1e-9,\n 1e-8,\n 1e-7,\n 1e-6,\n 1e-5,\n 1e-4,\n 1e-3,\n 1e-2,\n 1e-1,\n 1,\n 10,\n 100,\n 1000,\n 10000,\n 100000,\n 1000000,\n 10000000,\n 100000000,\n 1000000000,\n] as const;\n\nconst ET_MINUTE_PATTERN = /^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}$/;\n\n// Constructing an Intl.DateTimeFormat is expensive (it builds an ICU formatter)\n// and the options are constant. Build it once at module load instead of per\n// call — this function runs once per decoded quote row, so a per-row construct\n// dominated the decode cost on dense chains.\nconst ET_MINUTE_FORMAT = new Intl.DateTimeFormat(\"en-CA\", {\n timeZone: \"America/New_York\",\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n hour12: false,\n hourCycle: \"h23\",\n});\n\nexport function thetaPriceToNumber(price: ThetaPriceLike): number {\n return price.type === 0 ? Number.NaN : price.value * PRICE_TYPE_FACTORS[price.type];\n}\n\nexport function thetaTimestampToEtMinute(value: string | number | Date): string {\n if (typeof value === \"string\" && ET_MINUTE_PATTERN.test(value)) return value;\n const date = value instanceof Date ? value : new Date(value);\n const parts = ET_MINUTE_FORMAT.formatToParts(date);\n const get = (type: string) => parts.find((part) => part.type === type)?.value ?? \"\";\n return `${get(\"year\")}-${get(\"month\")}-${get(\"day\")} ${get(\"hour\")}:${get(\"minute\")}`;\n}\n\nfunction hasOwn(value: object, key: string): boolean {\n return Object.prototype.hasOwnProperty.call(value, key);\n}\n\nfunction toNumber(value: unknown): number {\n return typeof value === \"object\" && value !== null && \"toNumber\" in value\n ? (value as { toNumber: () => number }).toNumber()\n : Number(value);\n}\n\nfunction decodeCell(value: unknown): ThetaCellValue {\n if (!value || typeof value !== \"object\") return null;\n const cell = value as Record<string, unknown>;\n if (hasOwn(cell, \"text\")) return String(cell.text);\n if (hasOwn(cell, \"number\")) return toNumber(cell.number);\n if (hasOwn(cell, \"price\")) return thetaPriceToNumber(cell.price as ThetaPriceLike);\n if (hasOwn(cell, \"timestamp\")) {\n const timestamp = cell.timestamp as { epochMs?: unknown };\n return thetaTimestampToEtMinute(toNumber(timestamp.epochMs));\n }\n if (hasOwn(cell, \"nullValue\")) return null;\n return null;\n}\n\nexport function decodeThetaDataTablePayload(payload: Buffer | Uint8Array): DecodedThetaTable {\n try {\n const DataTable = loadMddsProtoRoot().lookupType(\"BetaEndpoints.DataTable\");\n const table = DataTable.decode(payload) as unknown as {\n headers: string[];\n dataTable: Array<{ values: unknown[] }>;\n };\n return {\n headers: table.headers,\n rows: table.dataTable.map((row) => {\n const out: Record<string, ThetaCellValue> = {};\n table.headers.forEach((header, index) => {\n out[header] = decodeCell(row.values[index]);\n });\n return out;\n }),\n };\n } catch (error) {\n throw new Error(\n `ThetaData DataTable decode failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n}\n\nexport function decodeThetaResponseData(response: {\n compressedData: Buffer | Uint8Array;\n compressionDescription?: { algo?: string | number };\n}): DecodedThetaTable {\n const algo = response.compressionDescription?.algo;\n const compressed = response.compressedData;\n let payload: Buffer;\n if (algo === undefined || algo === \"NONE\" || algo === 0) {\n payload = Buffer.from(compressed);\n } else if (algo === \"ZSTD\" || algo === 1) {\n try {\n payload = Buffer.from(decompress(new Uint8Array(compressed)));\n } catch (error) {\n throw new Error(\n `ThetaData ResponseData decompression failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n } else {\n throw new Error(`ThetaData ResponseData compression unsupported: ${String(algo)}`);\n }\n return decodeThetaDataTablePayload(payload);\n}\n","import type {\n ThetaContractListRow,\n ThetaFirstOrderGreekRow,\n ThetaImpliedVolatilityRow,\n ThetaIndexEodRow,\n ThetaIndexOhlcRow,\n ThetaOpenInterestRow,\n ThetaQuoteRow,\n ThetaRight,\n ThetaStockEodRow,\n ThetaStockOhlcRow,\n} from \"./types.ts\";\nimport {\n decodeThetaResponseData,\n thetaTimestampToEtMinute,\n type ThetaCellValue,\n} from \"./decode.ts\";\nimport { buildOccTicker } from \"../../trade-replay.ts\";\nimport type { ThetaMddsClient } from \"./client.ts\";\n\ntype ThetaResponseData = {\n compressedData: Buffer | Uint8Array;\n compressionDescription?: { algo?: string | number };\n};\n\nconst HYPHEN_DATE_PATTERN = /^\\d{4}-\\d{2}-\\d{2}$/;\nconst THETA_WILDCARD_STRIKE = \"*\";\n\nfunction asNumber(value: ThetaCellValue | undefined): number | null {\n if (typeof value === \"number\" && Number.isFinite(value)) return value;\n if (typeof value === \"string\" && value.trim()) {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : null;\n }\n return null;\n}\n\nfunction asText(value: ThetaCellValue | undefined): string {\n return String(value ?? \"\");\n}\n\nfunction requiredText(value: ThetaCellValue | undefined, context: string, field: string): string {\n const text = asText(value).trim();\n if (!text) throw new Error(`ThetaData ${context} missing ${field}`);\n return text;\n}\n\nfunction requiredNumber(value: ThetaCellValue | undefined, context: string, field: string): number {\n const number = asNumber(value);\n if (number == null) throw new Error(`ThetaData ${context} invalid ${field}`);\n return number;\n}\n\nfunction normalizeThetaDate(value: ThetaCellValue | undefined, context: string): string {\n const text = requiredText(value, context, \"date\");\n // Common wire formats: YYYY-MM-DD, YYYYMMDD, or \"YYYY-MM-DD HH:MM[:SS]\"\n // (the EOD endpoints return last_trade as the latter).\n const leadingDate = text.match(/^(\\d{4}-\\d{2}-\\d{2})/);\n if (leadingDate) return leadingDate[1];\n if (/^\\d{8}$/.test(text)) return `${text.slice(0, 4)}-${text.slice(4, 6)}-${text.slice(6, 8)}`;\n throw new Error(`ThetaData ${context} invalid date`);\n}\n\nfunction normalizeRight(value: unknown): ThetaRight {\n const raw = String(value ?? \"\").toLowerCase();\n if (raw === \"c\" || raw === \"call\") return \"call\";\n if (raw === \"p\" || raw === \"put\") return \"put\";\n throw new Error(`Unsupported ThetaData right: ${String(value)}`);\n}\n\nexport function thetaRequestRight(right: ThetaRight): string {\n return right;\n}\n\nexport function normalizeThetaQuoteRow(row: Record<string, ThetaCellValue>): ThetaQuoteRow {\n const timestamp = requiredText(row.timestamp, \"quote row\", \"timestamp\");\n return {\n symbol: requiredText(row.symbol, \"quote row\", \"symbol\").toUpperCase(),\n expiration: requiredText(row.expiration, \"quote row\", \"expiration\"),\n strike: requiredNumber(row.strike, \"quote row\", \"strike\"),\n right: normalizeRight(row.right),\n timestamp: thetaTimestampToEtMinute(timestamp),\n bid: asNumber(row.bid),\n ask: asNumber(row.ask),\n };\n}\n\nexport function normalizeThetaFirstOrderGreekRow(\n row: Record<string, ThetaCellValue>,\n): ThetaFirstOrderGreekRow {\n return {\n ...normalizeThetaQuoteRow(row),\n delta: asNumber(row.delta),\n theta: asNumber(row.theta),\n vega: asNumber(row.vega),\n iv: asNumber(row.implied_vol ?? row.implied_volatility),\n underlyingTimestamp: row.underlying_timestamp == null\n ? null\n : thetaTimestampToEtMinute(asText(row.underlying_timestamp)),\n underlyingPrice: asNumber(row.underlying_price),\n };\n}\n\nexport function normalizeThetaImpliedVolatilityRow(\n row: Record<string, ThetaCellValue>,\n): ThetaImpliedVolatilityRow {\n return {\n ...normalizeThetaQuoteRow(row),\n bidIv: asNumber(row.bid_implied_vol),\n midIv: asNumber(row.implied_vol ?? row.midpoint_implied_vol),\n askIv: asNumber(row.ask_implied_vol),\n ivError: asNumber(row.iv_error),\n underlyingTimestamp: row.underlying_timestamp == null\n ? null\n : thetaTimestampToEtMinute(asText(row.underlying_timestamp)),\n underlyingPrice: asNumber(row.underlying_price),\n };\n}\n\nexport function normalizeThetaContractListRow(\n row: Record<string, ThetaCellValue>,\n): ThetaContractListRow {\n return {\n symbol: requiredText(row.symbol, \"contract-list row\", \"symbol\").toUpperCase(),\n expiration: requiredText(row.expiration, \"contract-list row\", \"expiration\"),\n strike: requiredNumber(row.strike, \"contract-list row\", \"strike\"),\n right: normalizeRight(row.right),\n };\n}\n\nexport function normalizeThetaOpenInterestRow(\n row: Record<string, ThetaCellValue>,\n): ThetaOpenInterestRow {\n const symbol = requiredText(row.symbol, \"open-interest row\", \"symbol\").toUpperCase();\n const expiration = requiredText(row.expiration, \"open-interest row\", \"expiration\");\n const strike = requiredNumber(row.strike, \"open-interest row\", \"strike\");\n const right = normalizeRight(row.right);\n // The gRPC OI stream names the report-date column `timestamp` (carrying a\n // \"YYYY-MM-DD HH:MM\" ET value), matching the REST v3 OI response header.\n // Accept `date` too for any provider variant; normalizeThetaDate strips the\n // leading calendar date off either shape.\n const date = normalizeThetaDate(row.timestamp ?? row.date, \"open-interest row\");\n const rightChar = right === \"call\" ? \"C\" : \"P\";\n return {\n ticker: buildOccTicker(symbol, expiration, rightChar, strike),\n symbol,\n expiration,\n strike,\n right,\n date,\n openInterest: requiredNumber(row.open_interest, \"open-interest row\", \"open_interest\"),\n };\n}\n\n// Parse the wire `timestamp` \"YYYY-MM-DD HH:MM\" ET into the legacy date + msOfDay\n// pair the consumer (stockOhlcRowToBar) expects. Falls back to discrete fields\n// if a provider variant returns the older date/ms_of_day shape.\nfunction parseThetaOhlcDateAndMsOfDay(\n row: Record<string, ThetaCellValue>,\n context: string,\n): { date: string; msOfDay: number } {\n const rawTimestamp = typeof row.timestamp === \"string\" ? row.timestamp : null;\n if (rawTimestamp) {\n const match = rawTimestamp.match(/^(\\d{4}-\\d{2}-\\d{2})[ T](\\d{2}):(\\d{2})/);\n if (!match) {\n throw new Error(`ThetaData ${context} invalid timestamp: ${rawTimestamp}`);\n }\n const [, date, hh, mm] = match;\n return { date, msOfDay: (Number(hh) * 60 + Number(mm)) * 60_000 };\n }\n return {\n date: normalizeThetaDate(row.date, context),\n msOfDay: requiredNumber(row.ms_of_day ?? row.msOfDay, context, \"ms_of_day\"),\n };\n}\n\n// ThetaData stock OHLC rows: wire format returns a single `timestamp` string\n// (\"YYYY-MM-DD HH:MM\" ET) alongside open/high/low/close/volume.\nexport function normalizeThetaStockOhlcRow(\n row: Record<string, ThetaCellValue>,\n): ThetaStockOhlcRow {\n const { date, msOfDay } = parseThetaOhlcDateAndMsOfDay(row, \"stock OHLC row\");\n return {\n date,\n msOfDay,\n open: requiredNumber(row.open, \"stock OHLC row\", \"open\"),\n high: requiredNumber(row.high, \"stock OHLC row\", \"high\"),\n low: requiredNumber(row.low, \"stock OHLC row\", \"low\"),\n close: requiredNumber(row.close, \"stock OHLC row\", \"close\"),\n volume: asNumber(row.volume),\n };\n}\n\n// ThetaData EOD wire format uses `last_trade` for the trading-day date\n// (mirrors the index variant). Accept `date` too for any provider variant.\nexport function normalizeThetaStockEodRow(\n row: Record<string, ThetaCellValue>,\n): ThetaStockEodRow {\n return {\n date: normalizeThetaDate(row.last_trade ?? row.date, \"stock EOD row\"),\n open: requiredNumber(row.open, \"stock EOD row\", \"open\"),\n high: requiredNumber(row.high, \"stock EOD row\", \"high\"),\n low: requiredNumber(row.low, \"stock EOD row\", \"low\"),\n close: requiredNumber(row.close, \"stock EOD row\", \"close\"),\n volume: asNumber(row.volume),\n };\n}\n\nexport function normalizeThetaIndexOhlcRow(\n row: Record<string, ThetaCellValue>,\n): ThetaIndexOhlcRow {\n const { date, msOfDay } = parseThetaOhlcDateAndMsOfDay(row, \"index OHLC row\");\n return {\n date,\n msOfDay,\n open: requiredNumber(row.open, \"index OHLC row\", \"open\"),\n high: requiredNumber(row.high, \"index OHLC row\", \"high\"),\n low: requiredNumber(row.low, \"index OHLC row\", \"low\"),\n close: requiredNumber(row.close, \"index OHLC row\", \"close\"),\n volume: asNumber(row.volume),\n };\n}\n\nexport function normalizeThetaIndexEodRow(\n row: Record<string, ThetaCellValue>,\n): ThetaIndexEodRow {\n return {\n date: normalizeThetaDate(row.last_trade ?? row.date, \"index EOD row\"),\n open: requiredNumber(row.open, \"index EOD row\", \"open\"),\n high: requiredNumber(row.high, \"index EOD row\", \"high\"),\n low: requiredNumber(row.low, \"index EOD row\", \"low\"),\n close: requiredNumber(row.close, \"index EOD row\", \"close\"),\n volume: asNumber(row.volume),\n };\n}\n\nfunction endpointRequest(queryInfo: unknown, params: Record<string, unknown>) {\n return { queryInfo, params };\n}\n\nfunction mddsTime(value: string | undefined, fallback: string): string {\n const raw = value ?? fallback;\n return raw.length === 5 ? `${raw}:00.000` : raw.length === 8 ? `${raw}.000` : raw;\n}\n\nfunction decodeThetaRows(chunks: ThetaResponseData[]) {\n return chunks.flatMap((chunk) => decodeThetaResponseData(chunk).rows);\n}\n\nfunction validateHyphenDate(value: string, field: \"date\" | \"expiration\"): string {\n const text = value.trim();\n if (!HYPHEN_DATE_PATTERN.test(text)) {\n throw new Error(`ThetaData ${field} must use YYYY-MM-DD`);\n }\n const date = new Date(`${text}T00:00:00.000Z`);\n if (Number.isNaN(date.getTime()) || date.toISOString().slice(0, 10) !== text) {\n throw new Error(`ThetaData ${field} must be a valid calendar date`);\n }\n return text;\n}\n\nfunction validateSymbol(value: string): string {\n const text = value.trim();\n if (!text) throw new Error(\"ThetaData symbol is required\");\n return text;\n}\n\nfunction validateStrike(value: string | number): string {\n const text = String(value).trim();\n if (text === \"*\") return text;\n const parsed = Number(text);\n if (!text || !Number.isFinite(parsed)) throw new Error(\"ThetaData strike must be finite\");\n return text;\n}\n\nfunction optionalPositiveInteger(value: number | undefined, field: string): number | undefined {\n if (value == null) return undefined;\n if (!Number.isInteger(value) || value <= 0) {\n throw new Error(`ThetaData ${field} must be a positive integer`);\n }\n return value;\n}\n\nexport async function optionHistoryQuote(\n client: ThetaMddsClient,\n params: {\n symbol: string;\n expiration: string;\n strike: string;\n right: ThetaRight;\n date: string;\n interval?: string;\n startTime?: string;\n endTime?: string;\n },\n): Promise<ThetaQuoteRow[]> {\n const symbol = validateSymbol(params.symbol);\n const expiration = validateHyphenDate(params.expiration, \"expiration\");\n const strike = validateStrike(params.strike);\n const date = validateHyphenDate(params.date, \"date\");\n const chunks = await client.callStream<ThetaResponseData>(\n \"GetOptionHistoryQuote\",\n endpointRequest(client.queryInfo(), {\n contractSpec: {\n symbol,\n expiration,\n strike,\n right: thetaRequestRight(params.right),\n },\n expiration,\n date,\n interval: params.interval ?? \"1m\",\n startTime: mddsTime(params.startTime, \"09:30:00.000\"),\n endTime: mddsTime(params.endTime, \"16:00:00.000\"),\n }),\n );\n return decodeThetaRows(chunks).map(normalizeThetaQuoteRow);\n}\n\nexport async function stockHistoryOhlc(\n client: ThetaMddsClient,\n params: {\n symbol: string;\n startDate: string;\n endDate: string;\n interval: string;\n startTime?: string;\n endTime?: string;\n venue?: string;\n },\n): Promise<ThetaStockOhlcRow[]> {\n const symbol = validateSymbol(params.symbol);\n const startDate = validateHyphenDate(params.startDate, \"date\");\n const endDate = validateHyphenDate(params.endDate, \"date\");\n const interval = params.interval.trim();\n if (!interval) throw new Error(\"ThetaData interval is required\");\n // ThetaData stock OHLC requires an explicit venue. UTP is the canonical\n // composite feed; specify it when the caller doesn't.\n const venue = params.venue ?? \"utp\";\n const chunks = await client.callStream<ThetaResponseData>(\n \"GetStockHistoryOhlc\",\n endpointRequest(client.queryInfo(), {\n symbol,\n startDate,\n endDate,\n interval,\n startTime: mddsTime(params.startTime, \"09:30:00.000\"),\n endTime: mddsTime(params.endTime, \"16:00:00.000\"),\n venue,\n }),\n );\n // ThetaData stock OHLC streams can include null-OHLC rows on auction/pre-open\n // ticks. Drop those before normalizing so downstream BarRow stays numeric.\n return decodeThetaRows(chunks)\n .filter((row) =>\n Number.isFinite(row.open as number) &&\n Number.isFinite(row.high as number) &&\n Number.isFinite(row.low as number) &&\n Number.isFinite(row.close as number),\n )\n .map(normalizeThetaStockOhlcRow);\n}\n\nexport async function stockHistoryEod(\n client: ThetaMddsClient,\n params: {\n symbol: string;\n startDate: string;\n endDate: string;\n },\n): Promise<ThetaStockEodRow[]> {\n const symbol = validateSymbol(params.symbol);\n const startDate = validateHyphenDate(params.startDate, \"date\");\n const endDate = validateHyphenDate(params.endDate, \"date\");\n const chunks = await client.callStream<ThetaResponseData>(\n \"GetStockHistoryEod\",\n endpointRequest(client.queryInfo(), {\n symbol,\n startDate,\n endDate,\n }),\n );\n return decodeThetaRows(chunks).map(normalizeThetaStockEodRow);\n}\n\nexport async function indexHistoryOhlc(\n client: ThetaMddsClient,\n params: {\n symbol: string;\n startDate: string;\n endDate: string;\n interval: string;\n startTime?: string;\n endTime?: string;\n },\n): Promise<ThetaIndexOhlcRow[]> {\n const symbol = validateSymbol(params.symbol);\n const startDate = validateHyphenDate(params.startDate, \"date\");\n const endDate = validateHyphenDate(params.endDate, \"date\");\n const interval = params.interval.trim();\n if (!interval) throw new Error(\"ThetaData interval is required\");\n const chunks = await client.callStream<ThetaResponseData>(\n \"GetIndexHistoryOhlc\",\n endpointRequest(client.queryInfo(), {\n symbol,\n startDate,\n endDate,\n interval,\n startTime: mddsTime(params.startTime, \"09:30:00.000\"),\n endTime: mddsTime(params.endTime, \"16:00:00.000\"),\n }),\n );\n // ThetaData sometimes returns auction/pre-open rows with null OHLC (e.g. VIX\n // 09:30 print). Drop those before normalizing so the strict number contract\n // on downstream BarRow still holds.\n return decodeThetaRows(chunks)\n .filter((row) =>\n Number.isFinite(row.open as number) &&\n Number.isFinite(row.high as number) &&\n Number.isFinite(row.low as number) &&\n Number.isFinite(row.close as number),\n )\n .map(normalizeThetaIndexOhlcRow);\n}\n\nexport async function indexHistoryEod(\n client: ThetaMddsClient,\n params: {\n symbol: string;\n startDate: string;\n endDate: string;\n },\n): Promise<ThetaIndexEodRow[]> {\n const symbol = validateSymbol(params.symbol);\n const startDate = validateHyphenDate(params.startDate, \"date\");\n const endDate = validateHyphenDate(params.endDate, \"date\");\n const chunks = await client.callStream<ThetaResponseData>(\n \"GetIndexHistoryEod\",\n endpointRequest(client.queryInfo(), {\n symbol,\n startDate,\n endDate,\n }),\n );\n return decodeThetaRows(chunks).map(normalizeThetaIndexEodRow);\n}\n\nexport async function optionAtTimeQuote(\n client: ThetaMddsClient,\n params: {\n symbol: string;\n expiration: string;\n strike: string;\n right: ThetaRight;\n date: string;\n time: string;\n strikeRange?: number;\n },\n): Promise<ThetaQuoteRow[]> {\n const symbol = validateSymbol(params.symbol);\n const expiration = validateHyphenDate(params.expiration, \"expiration\");\n const strike = validateStrike(params.strike);\n const date = validateHyphenDate(params.date, \"date\");\n const strikeRange = optionalPositiveInteger(params.strikeRange, \"strike_range\");\n const chunks = await client.callStream<ThetaResponseData>(\n \"GetOptionAtTimeQuote\",\n endpointRequest(client.queryInfo(), {\n contractSpec: {\n symbol,\n expiration,\n strike,\n right: thetaRequestRight(params.right),\n },\n startDate: date,\n endDate: date,\n timeOfDay: mddsTime(params.time, \"09:45:00.000\"),\n expiration,\n ...(strikeRange == null ? {} : { strikeRange }),\n }),\n );\n return decodeThetaRows(chunks).map(normalizeThetaQuoteRow);\n}\n\nexport async function optionHistoryGreeksFirstOrder(\n client: ThetaMddsClient,\n params: {\n symbol: string;\n expiration: string;\n strike: string;\n right: ThetaRight;\n date: string;\n interval?: string;\n rateType?: string;\n startTime?: string;\n endTime?: string;\n strikeRange?: number;\n },\n): Promise<ThetaFirstOrderGreekRow[]> {\n const symbol = validateSymbol(params.symbol);\n const expiration = validateHyphenDate(params.expiration, \"expiration\");\n const strike = validateStrike(params.strike);\n const date = validateHyphenDate(params.date, \"date\");\n const strikeRange = optionalPositiveInteger(params.strikeRange, \"strike_range\");\n const chunks = await client.callStream<ThetaResponseData>(\n \"GetOptionHistoryGreeksFirstOrder\",\n endpointRequest(client.queryInfo(), {\n contractSpec: {\n symbol,\n expiration,\n strike,\n right: thetaRequestRight(params.right),\n },\n expiration,\n date,\n interval: params.interval ?? \"1m\",\n startTime: mddsTime(params.startTime, \"09:30:00.000\"),\n endTime: mddsTime(params.endTime, \"16:00:00.000\"),\n rateType: params.rateType ?? \"sofr\",\n version: \"latest\",\n ...(strikeRange == null ? {} : { strikeRange }),\n }),\n );\n return decodeThetaRows(chunks).map(normalizeThetaFirstOrderGreekRow);\n}\n\nexport async function optionHistoryGreeksFirstOrderBand(\n client: ThetaMddsClient,\n params: {\n symbol: string;\n expiration: string;\n date: string;\n strikeRange: number;\n interval?: string;\n rateType?: string;\n startTime?: string;\n endTime?: string;\n },\n): Promise<ThetaFirstOrderGreekRow[]> {\n const symbol = validateSymbol(params.symbol);\n // Accept \"*\" wildcard to fetch all expirations in one call.\n const expiration = params.expiration === \"*\"\n ? \"*\"\n : validateHyphenDate(params.expiration, \"expiration\");\n const date = validateHyphenDate(params.date, \"date\");\n const strikeRange = optionalPositiveInteger(params.strikeRange, \"strike_range\");\n const chunks = await client.callStream<ThetaResponseData>(\n \"GetOptionHistoryGreeksFirstOrder\",\n endpointRequest(client.queryInfo(), {\n contractSpec: {\n symbol,\n expiration,\n strike: THETA_WILDCARD_STRIKE,\n right: \"both\",\n },\n expiration,\n date,\n interval: params.interval ?? \"1m\",\n startTime: mddsTime(params.startTime, \"09:30:00.000\"),\n endTime: mddsTime(params.endTime, \"16:00:00.000\"),\n rateType: params.rateType ?? \"sofr\",\n version: \"latest\",\n strikeRange,\n }),\n );\n return decodeThetaRows(chunks).map(normalizeThetaFirstOrderGreekRow);\n}\n\n/**\n * IV-only endpoint: GetOptionHistoryGreeksImpliedVolatility.\n *\n * Lighter than first-order greeks — returns bid/mid/ask IVs and an iv_error\n * quality field, no delta/theta/vega. Use this when you only need IV from\n * ThetaData and intend to compute downstream greeks locally at your own\n * (r, q, T) convention.\n *\n * `annualDividend` and `rateType` control the IV solver convention server-side.\n */\nexport async function optionHistoryImpliedVolatilityBand(\n client: ThetaMddsClient,\n params: {\n symbol: string;\n expiration: string;\n date: string;\n strikeRange: number;\n interval?: string;\n rateType?: string;\n annualDividend?: number;\n startTime?: string;\n endTime?: string;\n },\n): Promise<ThetaImpliedVolatilityRow[]> {\n const symbol = validateSymbol(params.symbol);\n // Allow \"*\" wildcard like optionHistoryQuoteBand — server returns all active\n // expirations in one call. Each row carries its own expiration. Subject to\n // the same 1-concurrent-stream-per-session cap as wildcard quote calls.\n const expiration = params.expiration === \"*\"\n ? \"*\"\n : validateHyphenDate(params.expiration, \"expiration\");\n const date = validateHyphenDate(params.date, \"date\");\n const strikeRange = optionalPositiveInteger(params.strikeRange, \"strike_range\");\n const chunks = await client.callStream<ThetaResponseData>(\n \"GetOptionHistoryGreeksImpliedVolatility\",\n endpointRequest(client.queryInfo(), {\n contractSpec: {\n symbol,\n expiration,\n strike: THETA_WILDCARD_STRIKE,\n right: \"both\",\n },\n expiration,\n date,\n interval: params.interval ?? \"1m\",\n startTime: mddsTime(params.startTime, \"09:30:00.000\"),\n endTime: mddsTime(params.endTime, \"16:00:00.000\"),\n rateType: params.rateType ?? \"sofr\",\n ...(params.annualDividend == null ? {} : { annualDividend: params.annualDividend }),\n version: \"latest\",\n strikeRange,\n }),\n );\n return decodeThetaRows(chunks).map(normalizeThetaImpliedVolatilityRow);\n}\n\nexport async function optionHistoryQuoteBand(\n client: ThetaMddsClient,\n params: {\n symbol: string;\n expiration: string;\n date: string;\n strikeRange?: number;\n interval?: string;\n startTime?: string;\n endTime?: string;\n },\n): Promise<ThetaQuoteRow[]> {\n const symbol = validateSymbol(params.symbol);\n // Allow \"*\" wildcard — MDDS server returns all active expirations in one call\n // (each row carries its own expiration). Empirically ~1.6x faster than\n // iterating per-expiration; only one wildcard stream allowed per session.\n const expiration = params.expiration === \"*\"\n ? \"*\"\n : validateHyphenDate(params.expiration, \"expiration\");\n const date = validateHyphenDate(params.date, \"date\");\n const strikeRange = optionalPositiveInteger(params.strikeRange, \"strike_range\");\n const chunks = await client.callStream<ThetaResponseData>(\n \"GetOptionHistoryQuote\",\n endpointRequest(client.queryInfo(), {\n contractSpec: {\n symbol,\n expiration,\n strike: THETA_WILDCARD_STRIKE,\n right: \"both\",\n },\n expiration,\n date,\n interval: params.interval ?? \"1m\",\n startTime: mddsTime(params.startTime, \"09:30:00.000\"),\n endTime: mddsTime(params.endTime, \"16:00:00.000\"),\n ...(strikeRange == null ? {} : { strikeRange }),\n }),\n );\n return decodeThetaRows(chunks).map(normalizeThetaQuoteRow);\n}\n\n/**\n * Daily open-interest endpoint: GetOptionHistoryOpenInterest.\n *\n * Returns one open-interest value per contract per day across the\n * [startDate, endDate] range (open interest is daily granularity). Modeled on\n * the date-range EOD wrappers — the request query carries `start_date` /\n * `end_date` rather than a single intraday `date`.\n *\n * Accepts the `\"*\"` expiration wildcard like `optionHistoryQuoteBand` — the\n * MDDS server returns every active expiration in one stream (each row carries\n * its own expiration). Subject to the same one-wildcard-stream-per-session cap\n * as wildcard quote calls.\n */\nexport async function optionHistoryOpenInterest(\n client: ThetaMddsClient,\n params: {\n symbol: string;\n expiration: string;\n startDate: string;\n endDate: string;\n strikeRange?: number;\n },\n): Promise<ThetaOpenInterestRow[]> {\n const symbol = validateSymbol(params.symbol);\n const expiration = params.expiration === \"*\"\n ? \"*\"\n : validateHyphenDate(params.expiration, \"expiration\");\n const startDate = validateHyphenDate(params.startDate, \"date\");\n const endDate = validateHyphenDate(params.endDate, \"date\");\n const strikeRange = optionalPositiveInteger(params.strikeRange, \"strike_range\");\n const chunks = await client.callStream<ThetaResponseData>(\n \"GetOptionHistoryOpenInterest\",\n endpointRequest(client.queryInfo(), {\n contractSpec: {\n symbol,\n expiration,\n strike: THETA_WILDCARD_STRIKE,\n right: \"both\",\n },\n expiration,\n startDate,\n endDate,\n ...(strikeRange == null ? {} : { strikeRange }),\n }),\n );\n return decodeThetaRows(chunks).map(normalizeThetaOpenInterestRow);\n}\n\nexport async function optionListContracts(\n client: ThetaMddsClient,\n params: {\n symbol: string;\n date: string;\n requestType?: \"quote\" | \"trade\";\n },\n): Promise<ThetaContractListRow[]> {\n const symbol = validateSymbol(params.symbol);\n const date = validateHyphenDate(params.date, \"date\");\n const chunks = await client.callStream<ThetaResponseData>(\n \"GetOptionListContracts\",\n endpointRequest(client.queryInfo(), {\n requestType: params.requestType ?? \"quote\",\n symbol: [symbol],\n date,\n }),\n );\n return decodeThetaRows(chunks).map(normalizeThetaContractListRow);\n}\n","function parseDateUtc(date: string): Date {\n return new Date(`${date}T00:00:00Z`);\n}\n\nfunction minutesFromTime(time: string): number {\n const [hour, minute] = time.slice(0, 5).split(':').map(Number);\n return hour * 60 + minute;\n}\n\nexport function computeFractionalDte(\n date: string,\n time: string,\n expiration: string,\n): number {\n const startDay = parseDateUtc(date).getTime();\n const expiryDay = parseDateUtc(expiration).getTime();\n const dayDiff = Math.round((expiryDay - startDay) / 86_400_000);\n const remainingMinutes = Math.max((16 * 60) - minutesFromTime(time), 0);\n return Math.max(dayDiff + (remainingMinutes / (24 * 60)), 0);\n}\n","/**\n * iv-solver-pool.ts\n *\n * A small worker_threads pool that fans the option-greeks Newton-Raphson solve\n * out across CPU cores. The solve is pure CPU over independent rows\n * (embarrassingly parallel), so splitting a batch across N workers scales\n * close to linearly until memory-bandwidth / scheduling overhead dominates.\n *\n * Output parity is exact: each worker runs the identical `computeLegGreeks`\n * over flat numeric jobs (see iv-solver-worker.ts), so the greeks it returns\n * are bit-identical to the single-threaded path. The pool only decides *where*\n * the loop runs, never *what* it computes.\n *\n * Degrade-to-inline rules (no worker spawned):\n * - host reports <= 1 usable core\n * - batch is smaller than the inline threshold (worker round-trip +\n * structured-clone overhead would dominate the solve)\n * - the pool is disabled via TRADEBLOCKS_IV_WORKERS=0\n * In every inline case the result is produced by the same `solveIvBatch`\n * function the worker runs, so inline and parallel are interchangeable.\n */\n\nimport { Worker } from \"node:worker_threads\";\nimport { availableParallelism } from \"node:os\";\nimport { existsSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n solveIvBatch,\n type IvSolveBatchRequest,\n type IvSolveBatchReply,\n} from \"./iv-solver-worker.ts\";\n\n/**\n * One job = one option row to solve. Flat numbers only — nothing here is a\n * closure or a Map, so the batch transfers cleanly to a worker.\n */\nexport interface IvSolveJob {\n optionPrice: number;\n underlyingPrice: number;\n strike: number;\n dte: number;\n type: \"C\" | \"P\";\n riskFreeRate: number;\n dividendYield: number;\n}\n\nexport interface IvSolveJobResult {\n delta: number;\n gamma: number;\n theta: number;\n vega: number;\n iv: number;\n ok: boolean;\n}\n\n/**\n * Pre-built column batch — the hot-path input that avoids materializing an\n * `IvSolveJob[]` of plain objects. Callers fill these typed arrays directly\n * during row resolution; the pool shards and dispatches them without a copy.\n */\nexport interface IvSolveColumns {\n count: number;\n optionPrice: Float64Array;\n underlyingPrice: Float64Array;\n strike: Float64Array;\n dte: Float64Array;\n riskFreeRate: Float64Array;\n dividendYield: Float64Array;\n type: Uint8Array; // 0 = call, 1 = put\n}\n\n/** Reply columns — one entry per input row, in input order. */\nexport interface IvSolveColumnsResult {\n count: number;\n delta: Float64Array;\n gamma: Float64Array;\n theta: Float64Array;\n vega: Float64Array;\n iv: Float64Array;\n ok: Uint8Array; // 1 = finite greeks, 0 = solve failed\n}\n\nexport interface IvSolverPoolOptions {\n /** Max workers. Defaults to availableParallelism()-1, clamped to >= 1. */\n maxWorkers?: number;\n /**\n * Below this many jobs the whole batch is solved inline on the calling\n * thread — the worker round-trip isn't worth it for small batches.\n */\n inlineThreshold?: number;\n}\n\nconst DEFAULT_INLINE_THRESHOLD = 2_000;\n// Don't bother splitting into shards smaller than this; tiny shards waste a\n// worker round-trip. A batch is divided into at most `ceil(count / MIN_SHARD)`\n// shards, never more than the worker count.\nconst MIN_SHARD = 1_000;\n\nfunction resolveWorkerUrl(): URL {\n // Prefer the bundled sibling (.js) when present — that's the production\n // `dist/` runtime. Fall back to the .ts source for dev / test / ad-hoc node,\n // which Node strips types from natively.\n const jsUrl = new URL(\"./iv-solver-worker.js\", import.meta.url);\n if (existsSync(fileURLToPath(jsUrl))) return jsUrl;\n return new URL(\"./iv-solver-worker.ts\", import.meta.url);\n}\n\nfunction workersDisabledByEnv(): boolean {\n const flag = process.env.TRADEBLOCKS_IV_WORKERS;\n return flag === \"0\" || flag === \"false\" || flag === \"off\";\n}\n\nfunction defaultMaxWorkers(): number {\n const cores = Math.max(1, availableParallelism());\n return Math.max(1, cores - 1);\n}\n\ninterface PoolWorker {\n worker: Worker;\n busy: boolean;\n}\n\nfunction jobsToColumns(jobs: IvSolveJob[]): IvSolveColumns {\n const count = jobs.length;\n const cols: IvSolveColumns = {\n count,\n optionPrice: new Float64Array(count),\n underlyingPrice: new Float64Array(count),\n strike: new Float64Array(count),\n dte: new Float64Array(count),\n riskFreeRate: new Float64Array(count),\n dividendYield: new Float64Array(count),\n type: new Uint8Array(count),\n };\n for (let i = 0; i < count; i++) {\n const job = jobs[i];\n cols.optionPrice[i] = job.optionPrice;\n cols.underlyingPrice[i] = job.underlyingPrice;\n cols.strike[i] = job.strike;\n cols.dte[i] = job.dte;\n cols.riskFreeRate[i] = job.riskFreeRate;\n cols.dividendYield[i] = job.dividendYield;\n cols.type[i] = job.type === \"C\" ? 0 : 1;\n }\n return cols;\n}\n\n/** Slice a column batch into a per-shard request, copying the [lo, hi) window. */\nfunction shardRequest(cols: IvSolveColumns, id: number, lo: number, hi: number): IvSolveBatchRequest {\n return {\n id,\n count: hi - lo,\n optionPrice: cols.optionPrice.slice(lo, hi),\n underlyingPrice: cols.underlyingPrice.slice(lo, hi),\n strike: cols.strike.slice(lo, hi),\n dte: cols.dte.slice(lo, hi),\n riskFreeRate: cols.riskFreeRate.slice(lo, hi),\n dividendYield: cols.dividendYield.slice(lo, hi),\n type: cols.type.slice(lo, hi),\n };\n}\n\nfunction wholeRequest(cols: IvSolveColumns, id: number): IvSolveBatchRequest {\n return {\n id,\n count: cols.count,\n optionPrice: cols.optionPrice,\n underlyingPrice: cols.underlyingPrice,\n strike: cols.strike,\n dte: cols.dte,\n riskFreeRate: cols.riskFreeRate,\n dividendYield: cols.dividendYield,\n type: cols.type,\n };\n}\n\nfunction columnsResultFrom(reply: IvSolveBatchReply): IvSolveColumnsResult {\n return {\n count: reply.count,\n delta: reply.delta,\n gamma: reply.gamma,\n theta: reply.theta,\n vega: reply.vega,\n iv: reply.iv,\n ok: reply.ok,\n };\n}\n\nfunction resultsFromColumns(cols: IvSolveColumnsResult): IvSolveJobResult[] {\n const out: IvSolveJobResult[] = new Array(cols.count);\n for (let i = 0; i < cols.count; i++) {\n out[i] = {\n delta: cols.delta[i],\n gamma: cols.gamma[i],\n theta: cols.theta[i],\n vega: cols.vega[i],\n iv: cols.iv[i],\n ok: cols.ok[i] === 1,\n };\n }\n return out;\n}\n\nexport class IvSolverPool {\n private readonly maxWorkers: number;\n private readonly inlineThreshold: number;\n private readonly workerUrl: URL;\n private readonly enabled: boolean;\n private pool: PoolWorker[] = [];\n private nextRequestId = 1;\n // Serializes parallel solves against the shared worker set. The `busy`/slot\n // accounting in solveColumnsParallel is only correct when a single solve\n // owns the whole pool; without this gate, two concurrent callers could route\n // shards onto the same worker and corrupt the busy bookkeeping. Inline solves\n // don't touch workers and bypass the gate.\n private parallelChain: Promise<unknown> = Promise.resolve();\n\n constructor(options: IvSolverPoolOptions = {}) {\n this.maxWorkers = Math.max(1, options.maxWorkers ?? defaultMaxWorkers());\n this.inlineThreshold = options.inlineThreshold ?? DEFAULT_INLINE_THRESHOLD;\n this.workerUrl = resolveWorkerUrl();\n this.enabled = !workersDisabledByEnv() && this.maxWorkers > 1;\n }\n\n /**\n * Solve a batch of jobs, returning one result per job in input order. Thin\n * wrapper over `solveColumns` — convenient for callers (and tests) that hold\n * an `IvSolveJob[]`. The hot ingest path uses `solveColumns` directly to\n * avoid materializing the object array.\n */\n async solve(jobs: IvSolveJob[]): Promise<IvSolveJobResult[]> {\n if (jobs.length === 0) return [];\n const result = await this.solveColumns(jobsToColumns(jobs));\n return resultsFromColumns(result);\n }\n\n /**\n * Solve a pre-built column batch. Uses the worker pool when the batch is\n * large enough and workers are enabled; otherwise solves inline via the same\n * `solveIvBatch` the workers run (so inline and parallel are interchangeable).\n * The reply columns are positionally aligned with the input.\n */\n async solveColumns(cols: IvSolveColumns): Promise<IvSolveColumnsResult> {\n if (cols.count === 0) {\n return {\n count: 0,\n delta: new Float64Array(0),\n gamma: new Float64Array(0),\n theta: new Float64Array(0),\n vega: new Float64Array(0),\n iv: new Float64Array(0),\n ok: new Uint8Array(0),\n };\n }\n const shardCount = this.enabled\n ? Math.min(this.maxWorkers, Math.ceil(cols.count / MIN_SHARD))\n : 1;\n if (shardCount <= 1 || cols.count < this.inlineThreshold) {\n return columnsResultFrom(solveIvBatch(wholeRequest(cols, 0)));\n }\n // Single-flight: chain this parallel solve after any in-flight one so each\n // owns the worker pool exclusively. Errors don't poison the chain.\n const run = this.parallelChain\n .catch(() => undefined)\n .then(() => this.solveColumnsParallel(cols, shardCount));\n this.parallelChain = run;\n return run;\n }\n\n private async solveColumnsParallel(\n cols: IvSolveColumns,\n shardCount: number,\n ): Promise<IvSolveColumnsResult> {\n this.ensureWorkers(shardCount);\n\n const out: IvSolveColumnsResult = {\n count: cols.count,\n delta: new Float64Array(cols.count),\n gamma: new Float64Array(cols.count),\n theta: new Float64Array(cols.count),\n vega: new Float64Array(cols.count),\n iv: new Float64Array(cols.count),\n ok: new Uint8Array(cols.count),\n };\n\n const base = Math.floor(cols.count / shardCount);\n const remainder = cols.count % shardCount;\n const shardPromises: Promise<void>[] = [];\n let cursor = 0;\n for (let s = 0; s < shardCount; s++) {\n const size = base + (s < remainder ? 1 : 0);\n const lo = cursor;\n const hi = cursor + size;\n cursor = hi;\n if (size === 0) continue;\n const request = shardRequest(cols, this.nextRequestId++, lo, hi);\n shardPromises.push(\n this.runOnWorker(request).then((reply) => {\n out.delta.set(reply.delta, lo);\n out.gamma.set(reply.gamma, lo);\n out.theta.set(reply.theta, lo);\n out.vega.set(reply.vega, lo);\n out.iv.set(reply.iv, lo);\n out.ok.set(reply.ok, lo);\n }),\n );\n }\n\n await Promise.all(shardPromises);\n return out;\n }\n\n private ensureWorkers(target: number): void {\n while (this.pool.length < target) {\n const worker = new Worker(this.workerUrl);\n worker.setMaxListeners(0);\n // Surface a worker crash by failing loud; an unhandled worker error\n // would otherwise leave the pending shard promise hanging forever.\n worker.on(\"error\", (err) => {\n throw err;\n });\n this.pool.push({ worker, busy: false });\n }\n }\n\n private runOnWorker(request: IvSolveBatchRequest): Promise<IvSolveBatchReply> {\n return new Promise<IvSolveBatchReply>((resolve, reject) => {\n const slot = this.acquire();\n const onMessage = (reply: IvSolveBatchReply) => {\n if (reply.id !== request.id) return;\n cleanup();\n slot.busy = false;\n resolve(reply);\n };\n const onError = (err: Error) => {\n cleanup();\n slot.busy = false;\n reject(err);\n };\n const cleanup = () => {\n slot.worker.off(\"message\", onMessage);\n slot.worker.off(\"error\", onError);\n };\n slot.worker.on(\"message\", onMessage);\n slot.worker.once(\"error\", onError);\n // All request columns are freshly-allocated ArrayBuffer-backed typed\n // arrays (never SharedArrayBuffer), so transferring their buffers is safe.\n slot.worker.postMessage(request, [\n request.optionPrice.buffer,\n request.underlyingPrice.buffer,\n request.strike.buffer,\n request.dte.buffer,\n request.riskFreeRate.buffer,\n request.dividendYield.buffer,\n request.type.buffer,\n ] as ArrayBuffer[]);\n });\n }\n\n private acquire(): PoolWorker {\n const free = this.pool.find((w) => !w.busy);\n // ensureWorkers always provisions one worker per shard before dispatch, so\n // a free slot is guaranteed here.\n const slot = free ?? this.pool[0];\n slot.busy = true;\n return slot;\n }\n\n /** Terminate all workers. Idempotent. */\n async destroy(): Promise<void> {\n const workers = this.pool;\n this.pool = [];\n await Promise.all(workers.map(({ worker }) => worker.terminate()));\n }\n}\n\nlet sharedPool: IvSolverPool | null = null;\n\n/**\n * Process-wide shared pool. The ingest path reuses one pool across batches so\n * workers are spawned once, not per batch.\n */\nexport function getSharedIvSolverPool(): IvSolverPool {\n if (!sharedPool) {\n sharedPool = new IvSolverPool();\n }\n return sharedPool;\n}\n\nexport async function destroySharedIvSolverPool(): Promise<void> {\n if (sharedPool) {\n const pool = sharedPool;\n sharedPool = null;\n await pool.destroy();\n }\n}\n","/**\n * iv-solver-worker.ts\n *\n * worker_threads entry point for the parallel option-greeks solve.\n *\n * The Newton-Raphson IV solve in `computeLegGreeks` is pure CPU over\n * independent rows. This worker runs the identical `computeLegGreeks` on a\n * batch of flat numeric jobs and posts back the resulting greeks. Only plain\n * numbers cross the worker boundary, so the output is bit-identical to the\n * inline path (same code, same inputs, same IEEE-754 arithmetic).\n *\n * The batch is encoded as parallel typed arrays for cheap structured-clone\n * transfer:\n * - optionPrice, underlyingPrice, strike, dte, riskFreeRate, dividendYield\n * as Float64Array (one entry per job)\n * - type as Uint8Array (0 = call \"C\", 1 = put \"P\")\n * The reply mirrors that shape: delta/gamma/theta/vega/iv as Float64Array plus\n * an `ok` Uint8Array flag (1 = greeks finite, 0 = solve failed → caller treats\n * the row as math-failed, exactly as the inline path's null result does).\n */\n\nimport { parentPort } from \"node:worker_threads\";\nimport { computeLegGreeks } from \"./black-scholes.ts\";\n\nexport interface IvSolveBatchRequest {\n id: number;\n count: number;\n optionPrice: Float64Array;\n underlyingPrice: Float64Array;\n strike: Float64Array;\n dte: Float64Array;\n riskFreeRate: Float64Array;\n dividendYield: Float64Array;\n type: Uint8Array; // 0 = call, 1 = put\n}\n\nexport interface IvSolveBatchReply {\n id: number;\n count: number;\n delta: Float64Array;\n gamma: Float64Array;\n theta: Float64Array;\n vega: Float64Array;\n iv: Float64Array;\n ok: Uint8Array; // 1 = all five greeks finite, 0 = solve failed\n}\n\nfunction isFiniteNumber(value: number | null): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\n/**\n * Run `computeLegGreeks` over a flat batch. Shared by the worker message\n * handler and by the inline fallback in the pool, so both paths execute the\n * exact same loop.\n */\nexport function solveIvBatch(req: IvSolveBatchRequest): IvSolveBatchReply {\n const { id, count } = req;\n const delta = new Float64Array(count);\n const gamma = new Float64Array(count);\n const theta = new Float64Array(count);\n const vega = new Float64Array(count);\n const iv = new Float64Array(count);\n const ok = new Uint8Array(count);\n\n for (let i = 0; i < count; i++) {\n const result = computeLegGreeks(\n req.optionPrice[i],\n req.underlyingPrice[i],\n req.strike[i],\n req.dte[i],\n req.type[i] === 0 ? \"C\" : \"P\",\n req.riskFreeRate[i],\n req.dividendYield[i],\n );\n if (\n isFiniteNumber(result.delta)\n && isFiniteNumber(result.gamma)\n && isFiniteNumber(result.theta)\n && isFiniteNumber(result.vega)\n && isFiniteNumber(result.iv)\n ) {\n delta[i] = result.delta;\n gamma[i] = result.gamma;\n theta[i] = result.theta;\n vega[i] = result.vega;\n iv[i] = result.iv;\n ok[i] = 1;\n } else {\n ok[i] = 0;\n }\n }\n\n return { id, count, delta, gamma, theta, vega, iv, ok };\n}\n\nif (parentPort) {\n const port = parentPort;\n port.on(\"message\", (req: IvSolveBatchRequest) => {\n const reply = solveIvBatch(req);\n // Transfer the result buffers back to the main thread to avoid a copy.\n // These are freshly-allocated ArrayBuffer-backed typed arrays.\n port.postMessage(reply, [\n reply.delta.buffer,\n reply.gamma.buffer,\n reply.theta.buffer,\n reply.vega.buffer,\n reply.iv.buffer,\n reply.ok.buffer,\n ] as ArrayBuffer[]);\n });\n}\n","import { getSofrRateByKey } from \"@tradeblocks/lib\";\nimport type { ContractRow } from \"./chain-loader.ts\";\nimport { computeLegGreeks } from \"./black-scholes.ts\";\nimport { computeFractionalDte } from \"./option-time.ts\";\nimport {\n getSharedIvSolverPool,\n type IvSolveColumns,\n type IvSolverPool,\n} from \"./iv-solver-pool.ts\";\n\nexport type QuoteGreeksSource = \"massive\" | \"thetadata\" | \"computed\";\nexport type QuoteGreeksMode = \"auto\" | \"provider\" | \"compute\";\n\nexport interface QuoteGreekFields {\n delta?: number | null;\n gamma?: number | null;\n theta?: number | null;\n vega?: number | null;\n iv?: number | null;\n greeks_source?: QuoteGreeksSource | null;\n greeks_revision?: number | null;\n rate_type?: string | null;\n rate_value?: number | null;\n gamma_source?: string | null;\n}\n\nexport interface QuoteGreeksContractMeta {\n contract_type: ContractRow[\"contract_type\"];\n strike: number;\n expiration: string;\n}\n\nexport interface QuoteGreeksStats {\n rowsVisited: number;\n existingGreeksRows: number;\n computedRows: number;\n missingContractRows: number;\n missingUnderlyingRows: number;\n // Underlying-price lookup succeeded but `computeQuoteGreeks` returned null\n // (zero/negative option price, corrupt expiration → negative DTE, malformed\n // strike). Drives the `compute_failure` ingest-skipped reason —\n // distinguishes BS-math failure from spot/chain coverage gaps so operators\n // chase the right root cause.\n mathFailedRows: number;\n unresolvedRows: number;\n}\n\n/**\n * Greeks computation revision.\n * - 1 (legacy): hardcoded r = 0.045, q = 0.015\n * - 2: per-day SOFR rate, q = 0 (rate-convention switch)\n * - 3: revision 2 + provenance fields (rate_type, rate_value, gamma_source)\n */\nexport const OPTION_QUOTE_GREEKS_REVISION = 3;\n// Convention: SOFR overnight rate + zero dividend yield. Stored alongside each\n// computed greek row via `rate_type`, `rate_value`, and `gamma_source` so older\n// partitions remain distinguishable from revision-3 writes.\nexport const OPTION_QUOTE_GREEKS_RATE_TYPE = \"sofr\";\nexport const OPTION_QUOTE_GREEKS_GAMMA_SOURCE = \"computed_sofr_q0\";\nexport const OPTION_QUOTE_GREEKS_DIVIDEND_YIELD = 0;\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\n// `getSofrRateByKey` does a binary search over the rate table on every call,\n// but within a quote-ingest batch the date is constant (one partition = one\n// trading day) and across batches a date repeats for every row of that day.\n// Memoize the lookup by date key — the function is a pure deterministic map\n// from key → rate, so the cached value is identical to a fresh lookup.\nconst sofrRateByDateKey = new Map<string, number>();\n\nfunction memoizedSofrRate(dateKey: string): number {\n const cached = sofrRateByDateKey.get(dateKey);\n if (cached !== undefined) return cached;\n const rate = getSofrRateByKey(dateKey);\n sofrRateByDateKey.set(dateKey, rate);\n return rate;\n}\n\nexport function hasQuoteGreeks(row: QuoteGreekFields): boolean {\n return isFiniteNumber(row.delta ?? null)\n && isFiniteNumber(row.gamma ?? null)\n && isFiniteNumber(row.theta ?? null)\n && isFiniteNumber(row.vega ?? null)\n && isFiniteNumber(row.iv ?? null);\n}\n\nfunction hasProviderFirstOrderGreeks(row: QuoteGreekFields): boolean {\n return row.greeks_source === \"thetadata\"\n && isFiniteNumber(row.delta ?? null)\n && (row.gamma == null || isFiniteNumber(row.gamma))\n && isFiniteNumber(row.theta ?? null)\n && isFiniteNumber(row.vega ?? null)\n && isFiniteNumber(row.iv ?? null);\n}\n\nfunction hasExistingQuoteGreeks(row: QuoteGreekFields): boolean {\n return hasQuoteGreeks(row) || hasProviderFirstOrderGreeks(row);\n}\n\nfunction hasQuoteGreekProvenanceFields(row: QuoteGreekFields): boolean {\n return row.rate_type === OPTION_QUOTE_GREEKS_RATE_TYPE\n && isFiniteNumber(row.rate_value ?? null)\n && row.gamma_source === OPTION_QUOTE_GREEKS_GAMMA_SOURCE;\n}\n\nexport function normalizeExistingQuoteGreeks(\n row: QuoteGreekFields,\n defaultSource?: Exclude<QuoteGreeksSource, \"computed\">,\n): void {\n if (!hasExistingQuoteGreeks(row)) return;\n if (row.greeks_source == null && defaultSource) {\n row.greeks_source = defaultSource;\n }\n if (\n row.greeks_source === \"computed\"\n && row.greeks_revision == null\n && hasQuoteGreekProvenanceFields(row)\n ) {\n row.greeks_revision = OPTION_QUOTE_GREEKS_REVISION;\n }\n}\n\nexport function computeQuoteGreeks(params: {\n optionPrice: number;\n underlyingPrice: number;\n strike: number;\n date: string;\n time: string;\n expiration: string;\n contractType: ContractRow[\"contract_type\"];\n}): QuoteGreekFields | null {\n const {\n optionPrice,\n underlyingPrice,\n strike,\n date,\n time,\n expiration,\n contractType,\n } = params;\n if (!(optionPrice > 0) || !(underlyingPrice > 0) || !(strike > 0)) return null;\n const dte = computeFractionalDte(date, time.slice(0, 5), expiration);\n if (!(dte >= 0)) return null;\n const riskFreeRate = memoizedSofrRate(date) / 100;\n const result = computeLegGreeks(\n optionPrice,\n underlyingPrice,\n strike,\n dte,\n contractType === \"call\" ? \"C\" : \"P\",\n riskFreeRate,\n OPTION_QUOTE_GREEKS_DIVIDEND_YIELD,\n );\n if (!hasQuoteGreeks(result)) return null;\n return {\n delta: result.delta,\n gamma: result.gamma,\n theta: result.theta,\n vega: result.vega,\n iv: result.iv,\n greeks_source: \"computed\",\n greeks_revision: OPTION_QUOTE_GREEKS_REVISION,\n rate_type: OPTION_QUOTE_GREEKS_RATE_TYPE,\n rate_value: riskFreeRate,\n gamma_source: OPTION_QUOTE_GREEKS_GAMMA_SOURCE,\n };\n}\n\nexport function buildUnderlyingPriceKey(date: string, time: string): string {\n return `${date}|${time.slice(0, 5)}`;\n}\n\nexport interface ApplyQuoteGreeksParams<T extends QuoteGreekFields> {\n rows: T[];\n getDate: (row: T) => string;\n getTime: (row: T) => string;\n getMid: (row: T) => number;\n getContractMeta: (row: T) => QuoteGreeksContractMeta | undefined;\n getUnderlyingPrice: (date: string, time: string) => number | undefined;\n mode?: QuoteGreeksMode;\n defaultProviderSource?: Exclude<QuoteGreeksSource, \"computed\">;\n}\n\nfunction emptyStats(): QuoteGreeksStats {\n return {\n rowsVisited: 0,\n existingGreeksRows: 0,\n computedRows: 0,\n missingContractRows: 0,\n missingUnderlyingRows: 0,\n mathFailedRows: 0,\n unresolvedRows: 0,\n };\n}\n\n/**\n * Outcome of resolving a single row up to (but not including) the IV solve.\n * Skip kinds are fully accounted in stats and never solved. `kind: \"compute\"`\n * carries the flat solve inputs directly (no nested object — kept flat so the\n * parallel path can write them straight into typed-array columns). This is the\n * single source of truth for resolution, shared by the inline and parallel\n * apply functions so they cannot diverge.\n *\n * `type` is 0 = call (\"C\"), 1 = put (\"P\") — the same encoding the worker uses.\n */\ntype RowResolution =\n | { kind: \"existing\" }\n | { kind: \"missingContract\" }\n | { kind: \"providerUnresolved\" }\n | { kind: \"missingUnderlying\" }\n | { kind: \"mathFailed\" }\n | {\n kind: \"compute\";\n optionPrice: number;\n underlyingPrice: number;\n strike: number;\n dte: number;\n type: 0 | 1;\n riskFreeRate: number;\n };\n\nfunction resolveQuoteGreeksRow<T extends QuoteGreekFields>(\n row: T,\n params: ApplyQuoteGreeksParams<T>,\n defaultProviderSource: Exclude<QuoteGreeksSource, \"computed\"> | undefined,\n mode: QuoteGreeksMode,\n): RowResolution {\n if (mode !== \"compute\" && hasExistingQuoteGreeks(row)) {\n normalizeExistingQuoteGreeks(row, defaultProviderSource);\n return { kind: \"existing\" };\n }\n\n const meta = params.getContractMeta(row);\n if (!meta) return { kind: \"missingContract\" };\n\n if (mode === \"provider\") return { kind: \"providerUnresolved\" };\n\n const date = params.getDate(row);\n const time = params.getTime(row).slice(0, 5);\n const underlyingPrice = params.getUnderlyingPrice(date, time);\n if (!(underlyingPrice != null && underlyingPrice > 0)) {\n return { kind: \"missingUnderlying\" };\n }\n\n // Same guards and rate convention as computeQuoteGreeks — kept in lockstep\n // so the solve inputs are identical whether solved inline or on a worker.\n const optionPrice = params.getMid(row);\n if (!(optionPrice > 0) || !(meta.strike > 0)) return { kind: \"mathFailed\" };\n const dte = computeFractionalDte(date, time, meta.expiration);\n if (!(dte >= 0)) return { kind: \"mathFailed\" };\n const riskFreeRate = memoizedSofrRate(date) / 100;\n\n return {\n kind: \"compute\",\n optionPrice,\n underlyingPrice,\n strike: meta.strike,\n dte,\n type: meta.contract_type === \"call\" ? 0 : 1,\n riskFreeRate,\n };\n}\n\nfunction writeComputedGreeks<T extends QuoteGreekFields>(\n row: T,\n greeks: { delta: number; gamma: number; theta: number; vega: number; iv: number },\n riskFreeRate: number,\n): void {\n row.delta = greeks.delta;\n row.gamma = greeks.gamma;\n row.theta = greeks.theta;\n row.vega = greeks.vega;\n row.iv = greeks.iv;\n row.greeks_source = \"computed\";\n row.greeks_revision = OPTION_QUOTE_GREEKS_REVISION;\n row.rate_type = OPTION_QUOTE_GREEKS_RATE_TYPE;\n row.rate_value = riskFreeRate;\n row.gamma_source = OPTION_QUOTE_GREEKS_GAMMA_SOURCE;\n}\n\nfunction tallySkip(stats: QuoteGreeksStats, kind: RowResolution[\"kind\"]): void {\n switch (kind) {\n case \"existing\":\n stats.existingGreeksRows++;\n return;\n case \"missingContract\":\n stats.missingContractRows++;\n stats.unresolvedRows++;\n return;\n case \"providerUnresolved\":\n stats.unresolvedRows++;\n return;\n case \"missingUnderlying\":\n stats.missingUnderlyingRows++;\n stats.unresolvedRows++;\n return;\n case \"mathFailed\":\n stats.mathFailedRows++;\n stats.unresolvedRows++;\n return;\n case \"compute\":\n return;\n }\n}\n\nexport function applyQuoteGreeks<T extends QuoteGreekFields>(\n params: ApplyQuoteGreeksParams<T>,\n): QuoteGreeksStats {\n const { rows, mode = \"auto\", defaultProviderSource } = params;\n const stats = emptyStats();\n\n for (const row of rows) {\n stats.rowsVisited++;\n const resolution = resolveQuoteGreeksRow(row, params, defaultProviderSource, mode);\n if (resolution.kind !== \"compute\") {\n tallySkip(stats, resolution.kind);\n continue;\n }\n\n const result = computeLegGreeks(\n resolution.optionPrice,\n resolution.underlyingPrice,\n resolution.strike,\n resolution.dte,\n resolution.type === 0 ? \"C\" : \"P\",\n resolution.riskFreeRate,\n OPTION_QUOTE_GREEKS_DIVIDEND_YIELD,\n );\n if (!hasQuoteGreeks(result)) {\n stats.mathFailedRows++;\n stats.unresolvedRows++;\n continue;\n }\n writeComputedGreeks(\n row,\n {\n delta: result.delta as number,\n gamma: result.gamma as number,\n theta: result.theta as number,\n vega: result.vega as number,\n iv: result.iv as number,\n },\n resolution.riskFreeRate,\n );\n stats.computedRows++;\n }\n\n return stats;\n}\n\n/**\n * Parallel sibling of `applyQuoteGreeks`. Resolves every row on the calling\n * thread using the exact same `resolveQuoteGreeksRow` logic, then fans the\n * CPU-bound IV solve out across a worker pool. Greeks and provenance written\n * back are bit-identical to the inline path (the pool runs the same\n * `computeLegGreeks`); only the location of the solve loop changes.\n *\n * The pool degrades to inline automatically for small batches / single-core\n * hosts (see iv-solver-pool.ts), so this is safe to call unconditionally.\n */\nexport async function applyQuoteGreeksParallel<T extends QuoteGreekFields>(\n params: ApplyQuoteGreeksParams<T> & { pool?: IvSolverPool },\n): Promise<QuoteGreeksStats> {\n const { rows, mode = \"auto\", defaultProviderSource } = params;\n const stats = emptyStats();\n const pool = params.pool ?? getSharedIvSolverPool();\n const n = rows.length;\n\n // Resolve directly into the solve columns — no intermediate object array.\n // Sized to the row count (the compute subset is <= n); the unused tail is\n // dropped via `count` before dispatch.\n const optionPrice = new Float64Array(n);\n const underlyingPrice = new Float64Array(n);\n const strike = new Float64Array(n);\n const dte = new Float64Array(n);\n const riskFreeRate = new Float64Array(n);\n const dividendYield = new Float64Array(n);\n const type = new Uint8Array(n);\n // Maps the j-th compute job back to its source row index, so results land on\n // the right row.\n const jobRowIndex = new Int32Array(n);\n\n let count = 0;\n for (let i = 0; i < n; i++) {\n stats.rowsVisited++;\n const resolution = resolveQuoteGreeksRow(rows[i], params, defaultProviderSource, mode);\n if (resolution.kind !== \"compute\") {\n tallySkip(stats, resolution.kind);\n continue;\n }\n optionPrice[count] = resolution.optionPrice;\n underlyingPrice[count] = resolution.underlyingPrice;\n strike[count] = resolution.strike;\n dte[count] = resolution.dte;\n riskFreeRate[count] = resolution.riskFreeRate;\n dividendYield[count] = OPTION_QUOTE_GREEKS_DIVIDEND_YIELD;\n type[count] = resolution.type;\n jobRowIndex[count] = i;\n count++;\n }\n\n if (count === 0) return stats;\n\n const columns: IvSolveColumns = {\n count,\n optionPrice: optionPrice.subarray(0, count),\n underlyingPrice: underlyingPrice.subarray(0, count),\n strike: strike.subarray(0, count),\n dte: dte.subarray(0, count),\n riskFreeRate: riskFreeRate.subarray(0, count),\n dividendYield: dividendYield.subarray(0, count),\n type: type.subarray(0, count),\n };\n\n const result = await pool.solveColumns(columns);\n for (let j = 0; j < count; j++) {\n if (result.ok[j] !== 1) {\n stats.mathFailedRows++;\n stats.unresolvedRows++;\n continue;\n }\n writeComputedGreeks(\n rows[jobRowIndex[j]],\n {\n delta: result.delta[j],\n gamma: result.gamma[j],\n theta: result.theta[j],\n vega: result.vega[j],\n iv: result.iv[j],\n },\n riskFreeRate[j],\n );\n stats.computedRows++;\n }\n\n return stats;\n}\n","import { getSofrRateByKey } from \"@tradeblocks/lib\";\nimport type { BulkQuoteRow } from \"../../market-provider.ts\";\nimport { bsGamma } from \"../../black-scholes.ts\";\nimport { computeFractionalDte } from \"../../option-time.ts\";\nimport {\n OPTION_QUOTE_GREEKS_DIVIDEND_YIELD,\n OPTION_QUOTE_GREEKS_GAMMA_SOURCE,\n OPTION_QUOTE_GREEKS_RATE_TYPE,\n OPTION_QUOTE_GREEKS_REVISION,\n} from \"../../option-quote-greeks.ts\";\nimport type {\n ThetaFirstOrderGreekRow,\n ThetaQuoteRow,\n ThetaRight,\n} from \"./types.ts\";\n\nexport interface ThetaJoinedQuoteRow extends BulkQuoteRow {\n greeks_revision?: number | null;\n}\n\nexport interface ThetaQuoteGreekJoinStats {\n quoteRows: number;\n providerGreekRows: number;\n computedGammaRows: number;\n missingGreekRows: number;\n duplicateGreekRows: number;\n droppedQuoteRows: number;\n unusableGreekRows: number;\n}\n\nexport interface ThetaQuoteGreekJoinResult {\n rows: ThetaJoinedQuoteRow[];\n stats: ThetaQuoteGreekJoinStats;\n}\n\nexport interface ThetaQuoteGreekJoinOptions {\n quotes: ThetaQuoteRow[];\n providerGreeks: ThetaFirstOrderGreekRow[];\n}\n\nexport function buildTicker(params: {\n symbol: string;\n expiration: string;\n right: ThetaRight;\n strike: number;\n}): string {\n const [yyyy, mm, dd] = params.expiration.split(\"-\");\n const right = params.right === \"call\" ? \"C\" : \"P\";\n const strike = String(Math.round(params.strike * 1000)).padStart(8, \"0\");\n return `${params.symbol.toUpperCase()}${yyyy.slice(2)}${mm}${dd}${right}${strike}`;\n}\n\nfunction joinKey(\n row: Pick<ThetaQuoteRow, \"symbol\" | \"expiration\" | \"strike\" | \"right\" | \"timestamp\">,\n): string {\n return [\n row.symbol.toUpperCase(),\n row.expiration,\n row.strike.toFixed(3),\n row.right,\n row.timestamp,\n ].join(\"|\");\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\ntype CompleteThetaFirstOrderGreekRow = ThetaFirstOrderGreekRow & {\n delta: number;\n theta: number;\n vega: number;\n iv: number;\n};\n\nfunction hasProviderFirstOrderGreeks(\n row: ThetaFirstOrderGreekRow,\n): row is CompleteThetaFirstOrderGreekRow {\n return isFiniteNumber(row.delta)\n && isFiniteNumber(row.theta)\n && isFiniteNumber(row.vega)\n && isFiniteNumber(row.iv);\n}\n\nfunction splitTimestamp(timestamp: string): { date: string; time: string } {\n const [date, time = \"\"] = timestamp.split(\" \");\n return { date, time: time.slice(0, 5) };\n}\n\nfunction computeGamma(row: ThetaQuoteRow, greek: ThetaFirstOrderGreekRow): {\n gamma: number | null;\n rateValue: number | null;\n} {\n if (!isFiniteNumber(greek.iv) || !(greek.iv > 0)) return { gamma: null, rateValue: null };\n if (!isFiniteNumber(greek.underlyingPrice) || !(greek.underlyingPrice > 0)) {\n return { gamma: null, rateValue: null };\n }\n if (!(row.strike > 0)) return { gamma: null, rateValue: null };\n\n const { date, time } = splitTimestamp(row.timestamp);\n const dte = computeFractionalDte(date, time, row.expiration);\n if (!(dte > 0)) return { gamma: null, rateValue: null };\n\n const rateValue = getSofrRateByKey(date) / 100;\n return {\n gamma: bsGamma(\n greek.underlyingPrice,\n row.strike,\n dte / 365,\n rateValue,\n OPTION_QUOTE_GREEKS_DIVIDEND_YIELD,\n greek.iv,\n ),\n rateValue,\n };\n}\n\nfunction missingGreekRow(row: ThetaQuoteRow, bid: number, ask: number): ThetaJoinedQuoteRow {\n return {\n ticker: buildTicker(row),\n timestamp: row.timestamp,\n bid,\n ask,\n delta: null,\n gamma: null,\n theta: null,\n vega: null,\n iv: null,\n greeks_source: null,\n greeks_revision: null,\n rate_type: null,\n rate_value: null,\n gamma_source: null,\n };\n}\n\nexport function joinThetaQuotesAndFirstOrderGreeks(\n options: ThetaQuoteGreekJoinOptions,\n): ThetaQuoteGreekJoinResult {\n const stats: ThetaQuoteGreekJoinStats = {\n quoteRows: options.quotes.length,\n providerGreekRows: 0,\n computedGammaRows: 0,\n missingGreekRows: 0,\n duplicateGreekRows: 0,\n droppedQuoteRows: 0,\n unusableGreekRows: 0,\n };\n\n const greekByKey = new Map<string, ThetaFirstOrderGreekRow>();\n for (const row of options.providerGreeks) {\n const key = joinKey(row);\n if (greekByKey.has(key)) stats.duplicateGreekRows++;\n greekByKey.set(key, row);\n }\n\n const rows: ThetaJoinedQuoteRow[] = [];\n for (const quote of options.quotes) {\n if (!isFiniteNumber(quote.bid) || !isFiniteNumber(quote.ask)) {\n stats.droppedQuoteRows++;\n continue;\n }\n\n const greek = greekByKey.get(joinKey(quote));\n if (!greek) {\n stats.missingGreekRows++;\n rows.push(missingGreekRow(quote, quote.bid, quote.ask));\n continue;\n }\n\n if (!hasProviderFirstOrderGreeks(greek)) {\n stats.missingGreekRows++;\n stats.unusableGreekRows++;\n rows.push(missingGreekRow(quote, quote.bid, quote.ask));\n continue;\n }\n\n stats.providerGreekRows++;\n const { gamma, rateValue } = computeGamma(quote, greek);\n if (gamma != null) stats.computedGammaRows++;\n\n rows.push({\n ticker: buildTicker(quote),\n timestamp: quote.timestamp,\n bid: quote.bid,\n ask: quote.ask,\n delta: greek.delta,\n gamma,\n theta: greek.theta,\n vega: greek.vega,\n iv: greek.iv,\n greeks_source: \"thetadata\",\n greeks_revision: OPTION_QUOTE_GREEKS_REVISION,\n rate_type: gamma != null ? OPTION_QUOTE_GREEKS_RATE_TYPE : null,\n rate_value: rateValue,\n gamma_source: gamma != null ? OPTION_QUOTE_GREEKS_GAMMA_SOURCE : null,\n });\n }\n\n return { rows, stats };\n}\n","import { getSofrRateByKey } from \"@tradeblocks/lib\";\nimport type { BulkQuoteRow } from \"../../market-provider.ts\";\nimport { computeLegGreeks } from \"../../black-scholes.ts\";\nimport { computeFractionalDte } from \"../../option-time.ts\";\nimport {\n OPTION_QUOTE_GREEKS_DIVIDEND_YIELD,\n OPTION_QUOTE_GREEKS_RATE_TYPE,\n} from \"../../option-quote-greeks.ts\";\nimport { buildTicker } from \"./join.ts\";\nimport type { ThetaQuoteRow } from \"./types.ts\";\n\nexport const OPTION_QUOTE_MID_GREEKS_REVISION = 6;\nexport const OPTION_QUOTE_MID_GREEKS_DIVIDEND_YIELD = OPTION_QUOTE_GREEKS_DIVIDEND_YIELD;\nexport const OPTION_QUOTE_MID_GREEKS_GAMMA_SOURCE = \"computed_thetadata_quote_mid_sofr_q0\";\n\nexport type ThetaQuoteMidGreekRow = BulkQuoteRow & {\n greeks_revision: number;\n};\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction splitTimestamp(timestamp: string): { date: string; time: string } {\n const [date, time = \"\"] = timestamp.split(\" \");\n return { date, time: time.slice(0, 5) };\n}\n\nexport function computeThetaQuoteMidGreekRow(params: {\n quote: ThetaQuoteRow;\n underlyingPrice: number | null | undefined;\n}): ThetaQuoteMidGreekRow | null {\n const { quote, underlyingPrice } = params;\n if (!isFiniteNumber(quote.bid) || !isFiniteNumber(quote.ask)) return null;\n if (!isFiniteNumber(underlyingPrice) || !(underlyingPrice > 0)) return null;\n if (!(quote.strike > 0)) return null;\n\n const optionPrice = (quote.bid + quote.ask) / 2;\n if (!(optionPrice > 0)) return null;\n\n const { date, time } = splitTimestamp(quote.timestamp);\n const dte = computeFractionalDte(date, time, quote.expiration);\n if (!(dte > 0)) return null;\n\n const rateValue = getSofrRateByKey(date) / 100;\n const greeks = computeLegGreeks(\n optionPrice,\n underlyingPrice,\n quote.strike,\n dte,\n quote.right === \"call\" ? \"C\" : \"P\",\n rateValue,\n OPTION_QUOTE_MID_GREEKS_DIVIDEND_YIELD,\n );\n if (\n !isFiniteNumber(greeks.delta)\n || !isFiniteNumber(greeks.gamma)\n || !isFiniteNumber(greeks.theta)\n || !isFiniteNumber(greeks.vega)\n || !isFiniteNumber(greeks.iv)\n ) {\n return null;\n }\n\n return {\n ticker: buildTicker(quote),\n timestamp: quote.timestamp,\n bid: quote.bid,\n ask: quote.ask,\n delta: greeks.delta,\n gamma: greeks.gamma,\n theta: greeks.theta,\n // vega is stored per 1% IV move, matching computeLegGreeks' convention and\n // the rest of the emit path (the per-contract x100 multiplier belongs to the\n // consumer, not the stored greek).\n vega: greeks.vega,\n iv: greeks.iv,\n greeks_source: \"computed\",\n greeks_revision: OPTION_QUOTE_MID_GREEKS_REVISION,\n rate_type: OPTION_QUOTE_GREEKS_RATE_TYPE,\n rate_value: rateValue,\n gamma_source: OPTION_QUOTE_MID_GREEKS_GAMMA_SOURCE,\n };\n}\n","import { buildOccTicker } from \"../trade-replay.ts\";\nimport {\n ThetaMddsClient,\n indexHistoryEod,\n indexHistoryOhlc,\n joinThetaQuotesAndFirstOrderGreeks,\n optionHistoryGreeksFirstOrder,\n optionHistoryGreeksFirstOrderBand,\n optionHistoryOpenInterest,\n optionHistoryQuote,\n optionListContracts,\n stockHistoryEod,\n stockHistoryOhlc,\n type ThetaContractListRow,\n type ThetaFirstOrderGreekRow,\n type ThetaOpenInterestRow,\n type ThetaQuoteRow,\n type ThetaRight,\n type ThetaStockEodRow,\n type ThetaStockOhlcRow,\n} from \"./thetadata/index.ts\";\nimport type {\n BarRow,\n BulkOpenInterestOptions,\n BulkQuoteRow,\n BulkQuotesOptions,\n ContractReference,\n FetchBarsOptions,\n FetchContractListOptions,\n FetchContractListResult,\n FetchSnapshotOptions,\n FetchSnapshotResult,\n MarketDataProvider,\n MinuteQuote,\n OpenInterestRow,\n ProviderCapabilities,\n} from \"../market-provider.ts\";\n\nconst BULK_YIELD_CHUNK = 50_000;\nconst BULK_GREEKS_STRIKE_RANGE = 20;\n\nexport interface ThetaProviderDeps {\n client?: ThetaMddsClient;\n quoteEndpoint?: typeof optionHistoryQuote;\n firstOrderEndpoint?: typeof optionHistoryGreeksFirstOrder;\n firstOrderBandEndpoint?: typeof optionHistoryGreeksFirstOrderBand;\n contractListEndpoint?: typeof optionListContracts;\n openInterestEndpoint?: typeof optionHistoryOpenInterest;\n stockHistoryOhlc?: typeof stockHistoryOhlc;\n stockHistoryEod?: typeof stockHistoryEod;\n indexHistoryOhlc?: typeof indexHistoryOhlc;\n indexHistoryEod?: typeof indexHistoryEod;\n}\n\ntype GreekBandCache = Map<string, Promise<ThetaFirstOrderGreekRow[]>>;\n\ninterface ParsedOccTicker {\n root: string;\n expiration: string;\n right: ThetaRight;\n strike: number;\n}\n\nfunction parseOccTicker(ticker: string): ParsedOccTicker {\n const match = ticker.match(/^([A-Z]+)(\\d{2})(\\d{2})(\\d{2})(C|P)(\\d{8})$/);\n if (!match) {\n throw new Error(`Invalid OCC option ticker: ${ticker}`);\n }\n\n return {\n root: match[1],\n expiration: `20${match[2]}-${match[3]}-${match[4]}`,\n right: match[5] === \"C\" ? \"call\" : \"put\",\n strike: Number.parseInt(match[6], 10) / 1000,\n };\n}\n\nfunction formatStrike(strike: number): string {\n return strike.toFixed(3);\n}\n\nfunction parseIsoDate(date: string): Date {\n return new Date(`${date}T12:00:00.000Z`);\n}\n\nfunction formatIsoDate(date: Date): string {\n const year = date.getUTCFullYear();\n const month = String(date.getUTCMonth() + 1).padStart(2, \"0\");\n const day = String(date.getUTCDate()).padStart(2, \"0\");\n return `${year}-${month}-${day}`;\n}\n\nfunction enumerateDates(from: string, to: string): string[] {\n const dates: string[] = [];\n const cursor = parseIsoDate(from);\n const end = parseIsoDate(to);\n while (cursor <= end) {\n dates.push(formatIsoDate(cursor));\n cursor.setUTCDate(cursor.getUTCDate() + 1);\n }\n return dates;\n}\n\nfunction timespanToThetaInterval(\n timespan: FetchBarsOptions[\"timespan\"],\n multiplier: number | undefined,\n): string | null {\n if (timespan === \"day\") return null;\n const resolvedMultiplier = multiplier ?? 1;\n if (!Number.isInteger(resolvedMultiplier) || resolvedMultiplier <= 0) {\n throw new Error(\"ThetaData fetchBars multiplier must be a positive integer\");\n }\n if (timespan === \"hour\") return `${resolvedMultiplier * 60}m`;\n return `${resolvedMultiplier}m`;\n}\n\nfunction msOfDayToEtMinute(msOfDay: number): string {\n if (!Number.isFinite(msOfDay) || msOfDay < 0) {\n throw new Error(`ThetaData stock OHLC row invalid ms_of_day: ${String(msOfDay)}`);\n }\n const totalMinutes = Math.floor(msOfDay / 60_000);\n const hours = Math.floor(totalMinutes / 60);\n const minutes = totalMinutes % 60;\n if (hours > 23 || (hours === 23 && minutes > 59)) {\n throw new Error(`ThetaData stock OHLC row invalid ms_of_day: ${String(msOfDay)}`);\n }\n return `${String(hours).padStart(2, \"0\")}:${String(minutes).padStart(2, \"0\")}`;\n}\n\nfunction stockEodRowToBar(ticker: string, row: ThetaStockEodRow): BarRow {\n return {\n ticker,\n date: row.date,\n open: row.open,\n high: row.high,\n low: row.low,\n close: row.close,\n volume: row.volume ?? 0,\n };\n}\n\nfunction stockOhlcRowToBar(ticker: string, row: ThetaStockOhlcRow): BarRow {\n return {\n ...stockEodRowToBar(ticker, row),\n time: msOfDayToEtMinute(row.msOfDay),\n };\n}\n\n/**\n * Wire-level roots that bulk quote ingestion expands an underlying into. SPX has\n * monthly (`SPX`) and weekly/daily (`SPXW`) option roots in ThetaData.\n */\nexport function bulkQuoteRootsForUnderlying(underlying: string): string[] {\n const upper = underlying.toUpperCase();\n return upper === \"SPX\" ? [\"SPX\", \"SPXW\"] : [upper];\n}\n\n/**\n * Number of final root/right groups per date. Providers may emit additional\n * checkpoint events while processing those groups.\n */\nexport function countBulkQuoteGroupsPerDate(underlying: string): number {\n return bulkQuoteRootsForUnderlying(underlying).length * 2;\n}\n\nfunction inferExerciseStyle(symbol: string): \"american\" | \"european\" {\n const europeanRoots = new Set([\n \"SPX\",\n \"SPXW\",\n \"XSP\",\n \"NDX\",\n \"NDXP\",\n \"RUT\",\n \"RUTW\",\n \"VIX\",\n \"VIX9D\",\n \"DJX\",\n ]);\n return europeanRoots.has(symbol.toUpperCase()) ? \"european\" : \"american\";\n}\n\nfunction isGreekForBulkContract(\n row: ThetaFirstOrderGreekRow,\n root: string,\n right: ThetaRight,\n contract: ThetaContractListRow,\n): boolean {\n return row.symbol.toUpperCase() === root.toUpperCase()\n && row.expiration === contract.expiration\n && formatStrike(row.strike) === formatStrike(contract.strike)\n && row.right === right;\n}\n\nfunction toMinuteQuote(row: BulkQuoteRow & { greeks_revision?: number | null }): MinuteQuote {\n return {\n bid: row.bid,\n ask: row.ask,\n source: \"nbbo\",\n delta: row.delta ?? null,\n gamma: row.gamma ?? null,\n theta: row.theta ?? null,\n vega: row.vega ?? null,\n iv: row.iv ?? null,\n greeks_source: row.greeks_source ?? null,\n greeks_revision: row.greeks_revision ?? null,\n rate_type: row.rate_type ?? null,\n rate_value: row.rate_value ?? null,\n gamma_source: row.gamma_source ?? null,\n };\n}\n\nfunction occTickerFromQuote(row: ThetaQuoteRow): string {\n const rightChar = row.right === \"call\" ? \"C\" : \"P\";\n return buildOccTicker(row.symbol, row.expiration, rightChar, row.strike);\n}\n\nfunction contractReference(row: ThetaContractListRow): ContractReference {\n const rightChar = row.right === \"call\" ? \"C\" : \"P\";\n return {\n ticker: buildOccTicker(row.symbol, row.expiration, rightChar, row.strike),\n contract_type: row.right,\n strike: row.strike,\n expiration: row.expiration,\n exercise_style: inferExerciseStyle(row.symbol),\n };\n}\n\nexport class ThetaDataProvider implements MarketDataProvider {\n readonly name = \"thetadata\";\n private readonly client: ThetaMddsClient;\n private readonly quoteEndpoint: typeof optionHistoryQuote;\n private readonly firstOrderEndpoint: typeof optionHistoryGreeksFirstOrder;\n private readonly firstOrderBandEndpoint: typeof optionHistoryGreeksFirstOrderBand;\n private readonly contractListEndpoint: typeof optionListContracts;\n private readonly openInterestEndpoint: typeof optionHistoryOpenInterest;\n private readonly stockHistoryOhlcEndpoint: typeof stockHistoryOhlc;\n private readonly stockHistoryEodEndpoint: typeof stockHistoryEod;\n private readonly indexHistoryOhlcEndpoint: typeof indexHistoryOhlc;\n private readonly indexHistoryEodEndpoint: typeof indexHistoryEod;\n\n constructor(deps: ThetaProviderDeps = {}) {\n this.client = deps.client ?? new ThetaMddsClient();\n this.quoteEndpoint = deps.quoteEndpoint ?? optionHistoryQuote;\n this.firstOrderEndpoint = deps.firstOrderEndpoint ?? optionHistoryGreeksFirstOrder;\n this.firstOrderBandEndpoint = deps.firstOrderBandEndpoint ?? optionHistoryGreeksFirstOrderBand;\n this.contractListEndpoint = deps.contractListEndpoint ?? optionListContracts;\n this.openInterestEndpoint = deps.openInterestEndpoint ?? optionHistoryOpenInterest;\n this.stockHistoryOhlcEndpoint = deps.stockHistoryOhlc ?? stockHistoryOhlc;\n this.stockHistoryEodEndpoint = deps.stockHistoryEod ?? stockHistoryEod;\n this.indexHistoryOhlcEndpoint = deps.indexHistoryOhlc ?? indexHistoryOhlc;\n this.indexHistoryEodEndpoint = deps.indexHistoryEod ?? indexHistoryEod;\n }\n\n capabilities(): ProviderCapabilities {\n return {\n tradeBars: true,\n quotes: true,\n greeks: true,\n flatFiles: false,\n bulkByRoot: true,\n perTicker: false,\n minuteBars: true,\n dailyBars: true,\n };\n }\n\n async fetchBars(options: FetchBarsOptions): Promise<BarRow[]> {\n await this.client.connect?.();\n\n const ticker = options.ticker;\n const symbol = ticker.trim().toUpperCase();\n const timespan = options.timespan;\n const interval = timespanToThetaInterval(timespan, options.multiplier);\n const isIndex = options.assetClass === \"index\";\n const eodEndpoint = isIndex ? this.indexHistoryEodEndpoint : this.stockHistoryEodEndpoint;\n const ohlcEndpoint = isIndex ? this.indexHistoryOhlcEndpoint : this.stockHistoryOhlcEndpoint;\n\n if (interval == null) {\n const rows = await eodEndpoint(this.client, {\n symbol,\n startDate: options.from,\n endDate: options.to,\n });\n return rows.map((row) => stockEodRowToBar(ticker, row));\n }\n\n const bars: BarRow[] = [];\n for (const date of enumerateDates(options.from, options.to)) {\n const rows = await ohlcEndpoint(this.client, {\n symbol,\n startDate: date,\n endDate: date,\n interval,\n });\n bars.push(...rows.map((row) => stockOhlcRowToBar(ticker, row)));\n }\n return bars;\n }\n\n async fetchQuotes(ticker: string, from: string, to: string): Promise<Map<string, MinuteQuote>> {\n await this.client.connect?.();\n const occ = parseOccTicker(ticker);\n const result = new Map<string, MinuteQuote>();\n\n for (const date of enumerateDates(from, to)) {\n const request = {\n symbol: occ.root,\n expiration: occ.expiration,\n strike: formatStrike(occ.strike),\n right: occ.right,\n date,\n interval: \"1m\",\n } as const;\n const [quotes, providerGreeks] = await Promise.all([\n this.quoteEndpoint(this.client, request),\n this.firstOrderEndpoint(this.client, { ...request, rateType: \"sofr\" }),\n ]);\n const joined = joinThetaQuotesAndFirstOrderGreeks({ quotes, providerGreeks });\n for (const row of joined.rows) {\n result.set(row.timestamp, toMinuteQuote(row));\n }\n }\n\n return result;\n }\n\n async *fetchBulkQuotes(options: BulkQuotesOptions): AsyncGenerator<BulkQuoteRow[], void, void> {\n // Wildcard fetch path: instead of one quote request per contract (which on\n // a dense post-2024 SPX chain is 5000+ sequential gRPC calls), issue one\n // `strike=\"*\"` request per (root, expiration, right). That collapses the\n // wall time from ~hours to ~minutes per date. Greeks are not fetched from\n // ThetaData here — downstream applyQuoteGreeks computes them inline under\n // the SOFR+q=0 convention (see option-quote-greeks.ts).\n await this.client.connect?.();\n const roots = bulkQuoteRootsForUnderlying(options.underlying);\n const rights: ThetaRight[] = [\"call\", \"put\"];\n let chunk: BulkQuoteRow[] = [];\n\n const flush = function* (): Generator<BulkQuoteRow[], void, void> {\n if (chunk.length === 0) return;\n const ready = chunk;\n chunk = [];\n yield ready;\n };\n\n for (const root of roots) {\n const contracts = await this.contractListEndpoint(this.client, {\n symbol: root,\n date: options.date,\n requestType: \"quote\",\n });\n // Expirations present in the chain for this root, sorted for determinism.\n const expirationsByRight = new Map<ThetaRight, string[]>();\n for (const right of rights) {\n const expirations = new Set<string>();\n for (const c of contracts) {\n if (c.right === right) expirations.add(c.expiration);\n }\n expirationsByRight.set(right, [...expirations].sort());\n }\n\n for (const right of rights) {\n const expirations = expirationsByRight.get(right) ?? [];\n let completedExpirations = 0;\n\n try {\n for (const expiration of expirations) {\n let quotes: ThetaQuoteRow[];\n try {\n quotes = await this.quoteEndpoint(this.client, {\n symbol: root,\n expiration,\n strike: \"*\",\n right,\n date: options.date,\n interval: \"1m\",\n });\n } catch (error) {\n // ThetaData returns NOT_FOUND for (root, expiration, right)\n // combos that have no quotes on this date (e.g., zero-volume\n // expirations near the current month boundary). Treat as an\n // empty result and fall through to the per-iteration notify\n // so the final expiration in a group still emits a\n // phase=\"complete\" event when it NOT_FOUNDs.\n const msg = error instanceof Error ? error.message : String(error);\n if (!/NOT_FOUND|No data found/i.test(msg)) {\n throw error;\n }\n quotes = [];\n }\n for (const q of quotes) {\n // Drop rows missing bid or ask; the parquet schema is DOUBLE\n // NOT NULL on the price columns, and downstream applyQuoteGreeks\n // skips them anyway. Some (root, expiration, right) tuples\n // include zero-volume strikes that come back null/NaN.\n if (!Number.isFinite(q.bid as number) || !Number.isFinite(q.ask as number)) {\n continue;\n }\n chunk.push({\n ticker: occTickerFromQuote(q),\n timestamp: q.timestamp,\n bid: q.bid,\n ask: q.ask,\n delta: null,\n gamma: null,\n theta: null,\n vega: null,\n iv: null,\n greeks_source: null,\n rate_type: null,\n rate_value: null,\n gamma_source: null,\n source: \"nbbo\",\n } as BulkQuoteRow);\n if (chunk.length >= BULK_YIELD_CHUNK) {\n yield* flush();\n }\n }\n completedExpirations += 1;\n this.notifyGroupComplete(options, root, right, \"ok\", {\n phase: completedExpirations >= expirations.length ? \"complete\" : \"checkpoint\",\n completedContracts: completedExpirations,\n totalContracts: expirations.length,\n });\n }\n\n if (expirations.length === 0) {\n this.notifyGroupComplete(options, root, right, \"ok\", {\n phase: \"complete\",\n completedContracts: 0,\n totalContracts: 0,\n });\n }\n yield* flush();\n } catch (error) {\n this.notifyGroupComplete(options, root, right, \"error\", { phase: \"complete\" });\n throw error;\n }\n }\n }\n\n yield* flush();\n }\n\n async fetchContractList(options: FetchContractListOptions): Promise<FetchContractListResult> {\n await this.client.connect?.();\n const underlying = options.underlying.toUpperCase();\n const contracts: ContractReference[] = [];\n\n for (const root of bulkQuoteRootsForUnderlying(underlying)) {\n const rows = await this.contractListEndpoint(this.client, {\n symbol: root,\n date: options.as_of,\n requestType: \"quote\",\n });\n for (const row of rows) {\n if (options.expiration_date_gte && row.expiration < options.expiration_date_gte) continue;\n if (options.expiration_date_lte && row.expiration > options.expiration_date_lte) continue;\n contracts.push(contractReference(row));\n }\n }\n\n contracts.sort((left, right) => left.ticker.localeCompare(right.ticker));\n return { contracts, underlying };\n }\n\n async fetchOpenInterest(options: BulkOpenInterestOptions): Promise<OpenInterestRow[]> {\n await this.client.connect?.();\n const underlying = options.underlying.toUpperCase();\n const rows: OpenInterestRow[] = [];\n\n for (const root of bulkQuoteRootsForUnderlying(underlying)) {\n // One wildcard-expiration, wildcard-strike, both-rights stream per root\n // returns every contract's daily open interest across the range.\n let oiRows: ThetaOpenInterestRow[];\n try {\n oiRows = await this.openInterestEndpoint(this.client, {\n symbol: root,\n expiration: \"*\",\n startDate: options.from,\n endDate: options.to,\n });\n } catch (error) {\n // NOT_FOUND for a root with no contracts in the range is benign — fall\n // through to the next root rather than failing the whole fetch.\n const msg = error instanceof Error ? error.message : String(error);\n if (!/NOT_FOUND|No data found/i.test(msg)) throw error;\n oiRows = [];\n }\n for (const r of oiRows) {\n rows.push({\n ticker: r.ticker,\n underlying,\n date: r.date,\n expiration: r.expiration,\n strike: r.strike,\n right: r.right,\n open_interest: r.openInterest,\n });\n }\n }\n\n return rows;\n }\n\n async fetchOptionSnapshot(_options: FetchSnapshotOptions): Promise<FetchSnapshotResult> {\n throw new Error(\"ThetaData MDDS provider does not implement fetchOptionSnapshot yet\");\n }\n\n private async fetchBulkContractRows(\n root: string,\n right: ThetaRight,\n date: string,\n contract: ThetaContractListRow,\n greekBandCache: GreekBandCache,\n ): Promise<BulkQuoteRow[]> {\n // Quote history remains concrete per contract. First-order greeks are\n // fetched as one strike band per expiration/day and reused across rights.\n const request = {\n symbol: root,\n expiration: contract.expiration,\n strike: formatStrike(contract.strike),\n right,\n date,\n interval: \"1m\",\n } as const;\n const [quotes, bandGreeks]: [ThetaQuoteRow[], ThetaFirstOrderGreekRow[]] =\n await Promise.all([\n this.quoteEndpoint(this.client, request),\n this.fetchBulkGreekBand(root, contract.expiration, date, greekBandCache),\n ]);\n const contractBandGreeks = bandGreeks.filter((row) =>\n isGreekForBulkContract(row, root, right, contract)\n );\n const bandJoined = joinThetaQuotesAndFirstOrderGreeks({\n quotes,\n providerGreeks: contractBandGreeks,\n });\n if (quotes.length === 0 || bandJoined.stats.missingGreekRows === 0) {\n return bandJoined.rows;\n }\n\n const contractGreeks = await this.firstOrderEndpoint(this.client, {\n ...request,\n rateType: \"sofr\",\n });\n return joinThetaQuotesAndFirstOrderGreeks({\n quotes,\n providerGreeks: [...contractBandGreeks, ...contractGreeks],\n }).rows;\n }\n\n private fetchBulkGreekBand(\n root: string,\n expiration: string,\n date: string,\n greekBandCache: GreekBandCache,\n ): Promise<ThetaFirstOrderGreekRow[]> {\n const key = `${root}|${expiration}|${date}`;\n let promise = greekBandCache.get(key);\n if (!promise) {\n promise = this.firstOrderBandEndpoint(this.client, {\n symbol: root,\n expiration,\n date,\n interval: \"1m\",\n rateType: \"sofr\",\n strikeRange: BULK_GREEKS_STRIKE_RANGE,\n });\n greekBandCache.set(key, promise);\n }\n return promise;\n }\n\n private notifyGroupComplete(\n options: BulkQuotesOptions,\n root: string,\n right: ThetaRight,\n status: \"ok\" | \"error\",\n progress: {\n phase?: \"checkpoint\" | \"complete\";\n completedContracts?: number;\n totalContracts?: number;\n } = {},\n ): void {\n if (!options.onGroupComplete) return;\n try {\n options.onGroupComplete({ root, right, date: options.date, status, ...progress });\n } catch {\n // Progress hooks are best-effort; provider data flow owns the error path.\n }\n }\n}\n","/**\n * Market Data Provider Interface\n *\n * Defines the shared types and provider abstraction for fetching market data\n * from external APIs (Massive.com, ThetaData, etc.).\n *\n * All providers normalize their responses to BarRow and OptionContract types.\n * The factory function getProvider() selects the active provider based on the\n * MARKET_DATA_PROVIDER environment variable (default: \"massive\").\n */\n\nimport { MassiveProvider } from \"./providers/massive.ts\";\nimport { ThetaDataProvider } from \"./providers/thetadata.ts\";\n\n// ---------------------------------------------------------------------------\n// Shared Types\n// ---------------------------------------------------------------------------\n\n/** Normalized OHLCV bar — shared output type for all providers. */\nexport interface BarRow {\n date: string; // \"YYYY-MM-DD\" Eastern Time\n open: number;\n high: number;\n low: number;\n close: number;\n volume: number;\n ticker: string; // Plain storage format (no prefix)\n time?: string; // \"HH:MM\" ET — only set for intraday (minute/hour) bars\n bid?: number; // Best bid — only set when provider supplies quote data\n ask?: number; // Best ask — only set when provider supplies quote data\n}\n\n/** Asset classes supported by market data providers. */\nexport type AssetClass = \"stock\" | \"index\" | \"option\";\n\n/** Options for fetching OHLCV bars. */\nexport interface FetchBarsOptions {\n /** Plain ticker — VIX, AAPL, SPX251219C05000000 (no provider-specific prefix) */\n ticker: string;\n /** Start date \"YYYY-MM-DD\" */\n from: string;\n /** End date \"YYYY-MM-DD\" */\n to: string;\n /** Bar timespan (default: \"day\") */\n timespan?: \"day\" | \"minute\" | \"hour\";\n /** Bar multiplier (default: 1) */\n multiplier?: number;\n /** Asset class (default: \"stock\") */\n assetClass?: AssetClass;\n}\n\n/** Curated option contract returned by all providers. */\nexport interface OptionContract {\n ticker: string;\n underlying_ticker: string;\n underlying_price: number;\n contract_type: \"call\" | \"put\";\n strike: number;\n expiration: string; // \"YYYY-MM-DD\"\n exercise_style: string;\n delta: number | null;\n gamma: number | null;\n theta: number | null;\n vega: number | null;\n iv: number | null;\n greeks_source: \"massive\" | \"thetadata\" | \"computed\";\n bid: number;\n ask: number;\n midpoint: number;\n last_price: number | null;\n open_interest: number;\n volume: number;\n break_even: number;\n}\n\n/** Options for fetching option chain snapshots. */\nexport interface FetchSnapshotOptions {\n underlying: string;\n strike_price_gte?: number;\n strike_price_lte?: number;\n expiration_date_gte?: string;\n expiration_date_lte?: string;\n contract_type?: \"call\" | \"put\";\n}\n\n/** Result from fetching an option chain snapshot. */\nexport interface FetchSnapshotResult {\n contracts: OptionContract[];\n underlying_price: number;\n underlying_ticker: string;\n}\n\n/** Options for fetching historical option contract metadata (reference endpoint). */\nexport interface FetchContractListOptions {\n underlying: string;\n as_of: string; // \"YYYY-MM-DD\" -- historical date\n expired?: boolean; // default true for historical contract lookup\n expiration_date_gte?: string; // Only contracts expiring on or after this date\n expiration_date_lte?: string; // Only contracts expiring on or before this date\n}\n\n/** Single contract reference record (no greeks/pricing -- metadata only). */\nexport interface ContractReference {\n ticker: string; // OCC ticker without O: prefix\n contract_type: \"call\" | \"put\";\n strike: number;\n expiration: string; // \"YYYY-MM-DD\"\n exercise_style: string; // \"american\" | \"european\"\n}\n\n/** Result from contract list reference endpoint. */\nexport interface FetchContractListResult {\n contracts: ContractReference[];\n underlying: string;\n}\n\n/** Dataset types available for bulk flat-file download. */\nexport type BulkDataset = \"minute_bars\" | \"daily_bars\" | \"trades\";\n\n/** Options for downloading and filtering a full day of flat-file data to Parquet. */\nexport interface BulkDownloadOptions {\n /** Trading date \"YYYY-MM-DD\" */\n date: string;\n /** Which dataset to download */\n dataset: BulkDataset;\n /** Asset class determines S3 path and CSV format */\n assetClass: \"option\" | \"index\";\n /** Plain tickers to filter for (e.g. [\"SPX\", \"SPXW\"] for options, [\"SPX\", \"VIX\"] for indices) */\n tickers: string[];\n /** Absolute path to write the output Parquet file */\n outputPath: string;\n}\n\n/** Result from a bulk download operation. */\nexport interface BulkDownloadResult {\n /** Number of rows written to Parquet */\n rowCount: number;\n /** True if the output Parquet file already existed (skipped download) */\n skipped: boolean;\n}\n\n/** Earliest available date per asset class. */\nexport interface DataAvailability {\n /** Earliest date with data, \"YYYY-MM-DD\" */\n from: string;\n}\n\n/** Declares what data endpoints a provider supports. Used by the pipeline to build fetch plans. */\nexport interface ProviderCapabilities {\n tradeBars: boolean; // minute OHLC from trade aggregates\n /**\n * Strictly: \"true NBBO bid/ask is available via this provider's dedicated\n * quotes endpoint\". Use this when you specifically need real bid/ask spreads.\n *\n * NOTE: this is NOT the right gate for \"should I call fetchQuotes()\". A\n * provider may implement `fetchQuotes` and return useful per-minute data\n * (e.g. synthesized from OHLCV) even when `quotes === false`. Dispatch on\n * `typeof provider.fetchQuotes === 'function'` instead, and use the\n * persisted `source` column on `option_quote_minutes` ('nbbo' vs\n * 'synth_close') for per-row provenance.\n */\n quotes: boolean;\n greeks: boolean; // provider-computed greeks on contracts\n flatFiles: boolean; // bulk S3/file download of historical data\n bulkByRoot: boolean; // provider has an every-contract path for an underlying/root\n perTicker: boolean; // one call per OCC ticker (Massive/Polygon pattern)\n minuteBars: boolean; // minute-level resolution available\n dailyBars: boolean; // daily-level resolution available\n /** Earliest available data per asset class. Used by download tools and data pipelines to avoid requesting data that doesn't exist. */\n dataAvailability?: {\n option?: DataAvailability;\n index?: DataAvailability;\n stock?: DataAvailability;\n };\n}\n\n/** Options for fetching every contract's minute quotes under an underlying for a single date. */\nexport interface BulkQuotesOptions {\n /** Canonical underlying (e.g. \"SPX\"). Provider expands to its wire-level roots (e.g. SPX monthlies + SPXW dailies). */\n underlying: string;\n /** Trading date \"YYYY-MM-DD\" ET. */\n date: string;\n /**\n * Optional progress hook for bulk-by-root providers. Providers may invoke it\n * for intra-group checkpoints and final root/right completion; callers must\n * treat duplicate root/right/date tuples as progress heartbeats rather than\n * exactly-once completion records. Pure-data callback: MUST NOT throw,\n * providers are expected to wrap invocations in their own try/catch so an\n * unhandled reporter exception never propagates into stream machinery.\n */\n onGroupComplete?: (info: {\n root: string;\n right: \"call\" | \"put\";\n date: string;\n status: \"ok\" | \"error\";\n phase?: \"checkpoint\" | \"complete\";\n completedContracts?: number;\n totalContracts?: number;\n }) => void;\n}\n\n/**\n * One minute-level bid/ask tick emitted by the bulk-quote stream. The provider\n * MUST emit rows as they arrive (async iterable) — a full SPX/SPXW day can be\n * hundreds of MB when materialized, which OOMs node even at 8 GB heap. Consumers\n * batch and write in bounded chunks.\n */\nexport interface BulkQuoteRow {\n /** OCC ticker (e.g. \"SPXW260417C04800000\"). */\n ticker: string;\n /** \"YYYY-MM-DD HH:MM\" ET. */\n timestamp: string;\n bid: number;\n ask: number;\n delta?: number | null;\n gamma?: number | null;\n theta?: number | null;\n vega?: number | null;\n iv?: number | null;\n greeks_source?: \"massive\" | \"thetadata\" | \"computed\" | null;\n greeks_revision?: number | null;\n rate_type?: string | null;\n rate_value?: number | null;\n gamma_source?: string | null;\n}\n\n/** Options for fetching daily open interest for every contract under an underlying. */\nexport interface BulkOpenInterestOptions {\n /** Canonical underlying (e.g. \"SPX\"). Provider expands to its wire-level roots. */\n underlying: string;\n /** Start date \"YYYY-MM-DD\" ET (inclusive). */\n from: string;\n /** End date \"YYYY-MM-DD\" ET (inclusive). */\n to: string;\n}\n\n/**\n * One daily open-interest record for a single option contract. Open interest\n * is reported once per contract per day.\n */\nexport interface OpenInterestRow {\n /** OCC ticker (e.g. \"SPXW260417C04800000\"). */\n ticker: string;\n /** Canonical underlying the contract resolves to (e.g. \"SPX\"). */\n underlying: string;\n /** Report date \"YYYY-MM-DD\" ET. */\n date: string;\n /** Expiration \"YYYY-MM-DD\". */\n expiration: string;\n strike: number;\n right: \"call\" | \"put\";\n open_interest: number;\n}\n\nexport interface MinuteQuote {\n bid: number;\n ask: number;\n /**\n * Provenance tag for the quote.\n * - \"nbbo\": true bid/ask from a quotes-tier endpoint (Massive /v3/quotes,\n * ThetaData NBBO).\n * - \"synth_close\": synthesized from option minute OHLCV when the provider's\n * NBBO endpoint isn't available; bid === ask === close.\n * - null/undefined: legacy / unknown provenance.\n */\n source?: \"nbbo\" | \"synth_close\" | null;\n delta?: number | null;\n gamma?: number | null;\n theta?: number | null;\n vega?: number | null;\n iv?: number | null;\n greeks_source?: \"massive\" | \"thetadata\" | \"computed\" | null;\n greeks_revision?: number | null;\n rate_type?: string | null;\n rate_value?: number | null;\n gamma_source?: string | null;\n}\n\n/** The contract every market data provider must implement. */\nexport interface MarketDataProvider {\n readonly name: string;\n /** Returns what data endpoints this provider supports. */\n capabilities(): ProviderCapabilities;\n fetchBars(options: FetchBarsOptions): Promise<BarRow[]>;\n fetchOptionSnapshot(options: FetchSnapshotOptions): Promise<FetchSnapshotResult>;\n /** Best-effort bid/ask quotes keyed by \"YYYY-MM-DD HH:MM\" ET. Optional — not all providers support this. */\n fetchQuotes?(ticker: string, from: string, to: string): Promise<Map<string, MinuteQuote>>;\n /**\n * Stream every contract's minute quotes for one underlying on one date via\n * the provider's wildcard/bulk endpoint. Yields chunks of `BulkQuoteRow[]`\n * (typically ~50k rows each) so the ingestor can batch-write in bounded\n * chunks — materializing a full SPX day as individual yields would dominate\n * runtime in per-row await/yield overhead, and as a flat array would\n * overflow V8's default 4 GB heap.\n *\n * Capability-gated behind `capabilities().bulkByRoot` — providers that are\n * per-ticker-only (Massive, Polygon) do NOT implement this.\n */\n fetchBulkQuotes?(options: BulkQuotesOptions): AsyncIterable<BulkQuoteRow[]>;\n /**\n * Fetch daily open interest for every contract under an underlying across a\n * date range. Optional — providers that lack an open-interest endpoint do\n * not implement this. Capability-gated behind `capabilities().bulkByRoot`.\n */\n fetchOpenInterest?(options: BulkOpenInterestOptions): Promise<OpenInterestRow[]>;\n /** Historical option contract list from reference endpoint. Optional — not all providers support this. */\n fetchContractList?(options: FetchContractListOptions): Promise<FetchContractListResult>;\n /**\n * Download a flat file for a single date, returning the local file path.\n * Provider-specific: Massive uses S3/rclone, ThetaData uses HTTP flat files.\n * Returns null if flat files aren't supported or the date doesn't exist.\n */\n downloadFlatFile?(date: string, assetClass: string): Promise<string | null>;\n /**\n * Download a day of flat-file data, filter to specific tickers, and write to Parquet.\n * Provider-specific: Massive uses S3/rclone + DuckDB for filtering.\n * Returns row count and whether the file was skipped (already existed).\n */\n downloadBulkData?(options: BulkDownloadOptions): Promise<BulkDownloadResult>;\n}\n\n// ---------------------------------------------------------------------------\n// Provider Factory (lazy singleton with static imports)\n// ---------------------------------------------------------------------------\n\nlet _cached: MarketDataProvider | null = null;\n\n/**\n * Get the active market data provider.\n *\n * Reads MARKET_DATA_PROVIDER env var (default: \"massive\").\n * Returns a lazy singleton — cached after first call.\n */\nexport function getProvider(): MarketDataProvider {\n if (_cached) return _cached;\n const name = (process.env.MARKET_DATA_PROVIDER ?? \"massive\").toLowerCase();\n switch (name) {\n case \"massive\":\n _cached = new MassiveProvider();\n break;\n case \"thetadata\":\n _cached = new ThetaDataProvider();\n break;\n default:\n throw new Error(\n `Unknown MARKET_DATA_PROVIDER: \"${name}\". Supported: massive, thetadata`\n );\n }\n return _cached!;\n}\n\n/** Reset cached provider — for test isolation only. */\nexport function _resetProvider(): void {\n _cached = null;\n}\n"],"mappings":"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","names":["forward","iv","existsSync","credentials","credentials","optionalPositiveInteger","isFiniteNumber","isFiniteNumber","hasProviderFirstOrderGreeks","isFiniteNumber","splitTimestamp","status"]}