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
@@ -57,63 +57,72 @@ export interface MarketLookupKey {
57
57
  * `e`-prefixed alias {evix, evix9d, evix3m}.
58
58
  */
59
59
  interface VixFieldMapping {
60
- alias: string; // Column name in query output (e.g., "VIX_Close")
61
- tableAlias: string; // SQL table alias (e.g., "vix" for OHLCV, "evix" for enriched)
62
- sourceCol: string; // Source column (e.g., "close" in spot_daily, "ivr" in enriched)
63
- ticker: string; // Ticker to join on (e.g., "VIX")
64
- timing: 'open' | 'close';
60
+ alias: string; // Column name in query output (e.g., "VIX_Close")
61
+ tableAlias: string; // SQL table alias (e.g., "vix" for OHLCV, "evix" for enriched)
62
+ sourceCol: string; // Source column (e.g., "close" in spot_daily, "ivr" in enriched)
63
+ ticker: string; // Ticker to join on (e.g., "VIX")
64
+ timing: "open" | "close";
65
65
  }
66
66
 
67
67
  // OHLCV-sourced VIX columns — come from market.spot_daily, aliased as vix/vix9d/vix3m
68
68
  const VIX_OHLCV_MAPPINGS: VixFieldMapping[] = [
69
69
  // VIX
70
- { alias: "VIX_Open", tableAlias: "vix", sourceCol: "open", ticker: "VIX", timing: "open" },
71
- { alias: "VIX_Close", tableAlias: "vix", sourceCol: "close", ticker: "VIX", timing: "close" },
72
- { alias: "VIX_High", tableAlias: "vix", sourceCol: "high", ticker: "VIX", timing: "close" },
73
- { alias: "VIX_Low", tableAlias: "vix", sourceCol: "low", ticker: "VIX", timing: "close" },
70
+ { alias: "VIX_Open", tableAlias: "vix", sourceCol: "open", ticker: "VIX", timing: "open" },
71
+ { alias: "VIX_Close", tableAlias: "vix", sourceCol: "close", ticker: "VIX", timing: "close" },
72
+ { alias: "VIX_High", tableAlias: "vix", sourceCol: "high", ticker: "VIX", timing: "close" },
73
+ { alias: "VIX_Low", tableAlias: "vix", sourceCol: "low", ticker: "VIX", timing: "close" },
74
74
  // VIX9D
75
- { alias: "VIX9D_Open", tableAlias: "vix9d", sourceCol: "open", ticker: "VIX9D", timing: "open" },
76
- { alias: "VIX9D_Close", tableAlias: "vix9d", sourceCol: "close", ticker: "VIX9D", timing: "close" },
75
+ { alias: "VIX9D_Open", tableAlias: "vix9d", sourceCol: "open", ticker: "VIX9D", timing: "open" },
76
+ {
77
+ alias: "VIX9D_Close",
78
+ tableAlias: "vix9d",
79
+ sourceCol: "close",
80
+ ticker: "VIX9D",
81
+ timing: "close",
82
+ },
77
83
  // VIX3M
78
- { alias: "VIX3M_Open", tableAlias: "vix3m", sourceCol: "open", ticker: "VIX3M", timing: "open" },
79
- { alias: "VIX3M_Close", tableAlias: "vix3m", sourceCol: "close", ticker: "VIX3M", timing: "close" },
84
+ { alias: "VIX3M_Open", tableAlias: "vix3m", sourceCol: "open", ticker: "VIX3M", timing: "open" },
85
+ {
86
+ alias: "VIX3M_Close",
87
+ tableAlias: "vix3m",
88
+ sourceCol: "close",
89
+ ticker: "VIX3M",
90
+ timing: "close",
91
+ },
80
92
  ];
81
93
 
82
94
  // Enrichment-sourced VIX columns — come from market.enriched, aliased as evix/evix9d/evix3m
83
95
  const VIX_ENRICHED_MAPPINGS: VixFieldMapping[] = [
84
- { alias: "VIX_IVR", tableAlias: "evix", sourceCol: "ivr", ticker: "VIX", timing: "close" },
85
- { alias: "VIX_IVP", tableAlias: "evix", sourceCol: "ivp", ticker: "VIX", timing: "close" },
86
- { alias: "VIX9D_IVR", tableAlias: "evix9d", sourceCol: "ivr", ticker: "VIX9D", timing: "close" },
87
- { alias: "VIX9D_IVP", tableAlias: "evix9d", sourceCol: "ivp", ticker: "VIX9D", timing: "close" },
88
- { alias: "VIX3M_IVR", tableAlias: "evix3m", sourceCol: "ivr", ticker: "VIX3M", timing: "close" },
89
- { alias: "VIX3M_IVP", tableAlias: "evix3m", sourceCol: "ivp", ticker: "VIX3M", timing: "close" },
96
+ { alias: "VIX_IVR", tableAlias: "evix", sourceCol: "ivr", ticker: "VIX", timing: "close" },
97
+ { alias: "VIX_IVP", tableAlias: "evix", sourceCol: "ivp", ticker: "VIX", timing: "close" },
98
+ { alias: "VIX9D_IVR", tableAlias: "evix9d", sourceCol: "ivr", ticker: "VIX9D", timing: "close" },
99
+ { alias: "VIX9D_IVP", tableAlias: "evix9d", sourceCol: "ivp", ticker: "VIX9D", timing: "close" },
100
+ { alias: "VIX3M_IVR", tableAlias: "evix3m", sourceCol: "ivr", ticker: "VIX3M", timing: "close" },
101
+ { alias: "VIX3M_IVP", tableAlias: "evix3m", sourceCol: "ivp", ticker: "VIX3M", timing: "close" },
90
102
  ];
91
103
 
92
104
  // Union of all VIX mappings (order preserved: OHLCV first, then enrichment) — used for
93
105
  // SELECT column emission and open/close field-set derivation downstream.
94
- const VIX_ALL_MAPPINGS: VixFieldMapping[] = [
95
- ...VIX_OHLCV_MAPPINGS,
96
- ...VIX_ENRICHED_MAPPINGS,
97
- ];
106
+ const VIX_ALL_MAPPINGS: VixFieldMapping[] = [...VIX_OHLCV_MAPPINGS, ...VIX_ENRICHED_MAPPINGS];
98
107
 
99
108
  // Unique OHLCV table aliases needed for the JOIN clause (used by buildVixJoinClause)
100
- const VIX_TICKER_ALIASES = [...new Set(VIX_OHLCV_MAPPINGS.map(m => m.tableAlias))];
109
+ const VIX_TICKER_ALIASES = [...new Set(VIX_OHLCV_MAPPINGS.map((m) => m.tableAlias))];
101
110
  const VIX_TICKER_FOR_ALIAS: Record<string, string> = Object.fromEntries([
102
- ...VIX_OHLCV_MAPPINGS.map(m => [m.tableAlias, m.ticker] as const),
103
- ...VIX_ENRICHED_MAPPINGS.map(m => [m.tableAlias, m.ticker] as const),
111
+ ...VIX_OHLCV_MAPPINGS.map((m) => [m.tableAlias, m.ticker] as const),
112
+ ...VIX_ENRICHED_MAPPINGS.map((m) => [m.tableAlias, m.ticker] as const),
104
113
  ]);
105
114
 
106
115
  // Derived fields from date_context
107
116
  const DERIVED_OPEN_FIELDS: ReadonlySet<string> = new Set(
108
117
  Object.entries(derivedColumns)
109
- .filter(([, desc]) => desc.timing === 'open')
110
- .map(([name]) => name)
118
+ .filter(([, desc]) => desc.timing === "open")
119
+ .map(([name]) => name),
111
120
  );
112
121
 
113
122
  const DERIVED_CLOSE_FIELDS: ReadonlySet<string> = new Set(
114
123
  Object.entries(derivedColumns)
115
- .filter(([, desc]) => desc.timing === 'close')
116
- .map(([name]) => name)
124
+ .filter(([, desc]) => desc.timing === "close")
125
+ .map(([name]) => name),
117
126
  );
118
127
 
119
128
  // ============================================================================
@@ -128,8 +137,8 @@ const DERIVED_CLOSE_FIELDS: ReadonlySet<string> = new Set(
128
137
  */
129
138
  export const DAILY_OPEN_FIELDS: ReadonlySet<string> = new Set(
130
139
  Object.entries(dailyColumns)
131
- .filter(([, desc]) => desc.timing === 'open')
132
- .map(([name]) => name)
140
+ .filter(([, desc]) => desc.timing === "open")
141
+ .map(([name]) => name),
133
142
  );
134
143
 
135
144
  /**
@@ -138,8 +147,8 @@ export const DAILY_OPEN_FIELDS: ReadonlySet<string> = new Set(
138
147
  */
139
148
  export const DAILY_CLOSE_FIELDS: ReadonlySet<string> = new Set(
140
149
  Object.entries(dailyColumns)
141
- .filter(([, desc]) => desc.timing === 'close')
142
- .map(([name]) => name)
150
+ .filter(([, desc]) => desc.timing === "close")
151
+ .map(([name]) => name),
143
152
  );
144
153
 
145
154
  /**
@@ -147,15 +156,15 @@ export const DAILY_CLOSE_FIELDS: ReadonlySet<string> = new Set(
147
156
  */
148
157
  export const DAILY_STATIC_FIELDS: ReadonlySet<string> = new Set(
149
158
  Object.entries(dailyColumns)
150
- .filter(([, desc]) => desc.timing === 'static')
151
- .map(([name]) => name)
159
+ .filter(([, desc]) => desc.timing === "static")
160
+ .map(([name]) => name),
152
161
  );
153
162
 
154
163
  /**
155
164
  * Open-known fields from VIX tickers + enriched_context
156
165
  */
157
166
  export const CONTEXT_OPEN_FIELDS: ReadonlySet<string> = new Set([
158
- ...VIX_ALL_MAPPINGS.filter(m => m.timing === 'open').map(m => m.alias),
167
+ ...VIX_ALL_MAPPINGS.filter((m) => m.timing === "open").map((m) => m.alias),
159
168
  ...DERIVED_OPEN_FIELDS,
160
169
  ]);
161
170
 
@@ -163,7 +172,7 @@ export const CONTEXT_OPEN_FIELDS: ReadonlySet<string> = new Set([
163
172
  * Close-derived fields from VIX tickers + enriched_context
164
173
  */
165
174
  export const CONTEXT_CLOSE_FIELDS: ReadonlySet<string> = new Set([
166
- ...VIX_ALL_MAPPINGS.filter(m => m.timing === 'close').map(m => m.alias),
175
+ ...VIX_ALL_MAPPINGS.filter((m) => m.timing === "close").map((m) => m.alias),
167
176
  ...DERIVED_CLOSE_FIELDS,
168
177
  ]);
169
178
 
@@ -198,9 +207,7 @@ export const CLOSE_KNOWN_FIELDS: ReadonlySet<string> = new Set([
198
207
  * Only from market.enriched (context has no static fields).
199
208
  * Safe to use as same-day values in trade-entry queries.
200
209
  */
201
- export const STATIC_FIELDS: ReadonlySet<string> = new Set([
202
- ...DAILY_STATIC_FIELDS,
203
- ]);
210
+ export const STATIC_FIELDS: ReadonlySet<string> = new Set([...DAILY_STATIC_FIELDS]);
204
211
 
205
212
  // ============================================================================
206
213
  // Query Builders
@@ -221,12 +228,9 @@ export const STATIC_FIELDS: ReadonlySet<string> = new Set([
221
228
  * @param baseAlias alias of the main table the joins attach to (default 'd')
222
229
  * @returns SQL fragment string with \n + 6-space indent between JOINs
223
230
  */
224
- export function buildVixJoinClause(
225
- tickerAliases: string[],
226
- baseAlias: string = "d",
227
- ): string {
231
+ export function buildVixJoinClause(tickerAliases: string[], baseAlias: string = "d"): string {
228
232
  return tickerAliases
229
- .flatMap(alias => {
233
+ .flatMap((alias) => {
230
234
  const ticker = VIX_TICKER_FOR_ALIAS[alias];
231
235
  return [
232
236
  `LEFT JOIN market.spot_daily ${alias} ON ${alias}.date = ${baseAlias}.date AND ${alias}.ticker = '${ticker}'`,
@@ -239,14 +243,12 @@ export function buildVixJoinClause(
239
243
  // SELECT columns from VIX OHLCV + enrichment mappings, e.g. vix."close" AS "VIX_Close",
240
244
  // evix."ivr" AS "VIX_IVR", ...
241
245
  function buildVixSelectCols(): string {
242
- return VIX_ALL_MAPPINGS
243
- .map(m => `${m.tableAlias}."${m.sourceCol}" AS "${m.alias}"`)
244
- .join(", ");
246
+ return VIX_ALL_MAPPINGS.map((m) => `${m.tableAlias}."${m.sourceCol}" AS "${m.alias}"`).join(", ");
245
247
  }
246
248
 
247
249
  // SELECT columns from enriched_context: cd."Vol_Regime", ...
248
250
  function buildDerivedSelectCols(): string {
249
- return [...DERIVED_OPEN_FIELDS, ...DERIVED_CLOSE_FIELDS].map(f => `cd."${f}"`).join(", ");
251
+ return [...DERIVED_OPEN_FIELDS, ...DERIVED_CLOSE_FIELDS].map((f) => `cd."${f}"`).join(", ");
250
252
  }
251
253
 
252
254
  /**
@@ -280,19 +282,29 @@ function buildDerivedSelectCols(): string {
280
282
  * @returns Object with `sql` (the query string) and `params` (the parameter values)
281
283
  */
282
284
  export function buildLookaheadFreeQuery(tradeDates: string[]): { sql: string; params: string[] };
283
- export function buildLookaheadFreeQuery(tradeKeys: MarketLookupKey[]): { sql: string; params: string[] };
284
- export function buildLookaheadFreeQuery(
285
- tradeDatesOrKeys: string[] | MarketLookupKey[]
286
- ): { sql: string; params: string[] } {
285
+ export function buildLookaheadFreeQuery(tradeKeys: MarketLookupKey[]): {
286
+ sql: string;
287
+ params: string[];
288
+ };
289
+ export function buildLookaheadFreeQuery(tradeDatesOrKeys: string[] | MarketLookupKey[]): {
290
+ sql: string;
291
+ params: string[];
292
+ } {
287
293
  if (tradeDatesOrKeys.length === 0) {
288
294
  return { sql: `SELECT * FROM market.enriched WHERE 1=0`, params: [] };
289
295
  }
290
296
 
291
297
  // Build field lists for the joined CTE. OHLCV columns project from alias `s`
292
298
  // (market.spot_daily); enrichment columns project from alias `d` (market.enriched).
293
- const dailyOpenCols = [...DAILY_OPEN_FIELDS].map((f) => `${aliasForDailyCol(f)}."${f}"`).join(", ");
294
- const dailyStaticCols = [...DAILY_STATIC_FIELDS].map((f) => `${aliasForDailyCol(f)}."${f}"`).join(", ");
295
- const dailyCloseCols = [...DAILY_CLOSE_FIELDS].map((f) => `${aliasForDailyCol(f)}."${f}"`).join(", ");
299
+ const dailyOpenCols = [...DAILY_OPEN_FIELDS]
300
+ .map((f) => `${aliasForDailyCol(f)}."${f}"`)
301
+ .join(", ");
302
+ const dailyStaticCols = [...DAILY_STATIC_FIELDS]
303
+ .map((f) => `${aliasForDailyCol(f)}."${f}"`)
304
+ .join(", ");
305
+ const dailyCloseCols = [...DAILY_CLOSE_FIELDS]
306
+ .map((f) => `${aliasForDailyCol(f)}."${f}"`)
307
+ .join(", ");
296
308
  const vixSelectCols = buildVixSelectCols();
297
309
  const derivedSelectCols = buildDerivedSelectCols();
298
310
  const vixJoins = buildVixJoinClause(VIX_TICKER_ALIASES, "d");
@@ -301,22 +313,20 @@ export function buildLookaheadFreeQuery(
301
313
  const dailyLagCols = [...DAILY_CLOSE_FIELDS]
302
314
  .map((field) => `LAG("${field}") OVER (PARTITION BY ticker ORDER BY date) AS "prev_${field}"`)
303
315
  .join(",\n ");
304
- const vixLagCols = VIX_ALL_MAPPINGS
305
- .filter(m => m.timing === 'close')
306
- .map(m => `LAG("${m.alias}") OVER (PARTITION BY ticker ORDER BY date) AS "prev_${m.alias}"`)
316
+ const vixLagCols = VIX_ALL_MAPPINGS.filter((m) => m.timing === "close")
317
+ .map((m) => `LAG("${m.alias}") OVER (PARTITION BY ticker ORDER BY date) AS "prev_${m.alias}"`)
307
318
  .join(",\n ");
308
319
  const derivedLagCols = [...DERIVED_CLOSE_FIELDS]
309
- .map(f => `LAG("${f}") OVER (PARTITION BY ticker ORDER BY date) AS "prev_${f}"`)
320
+ .map((f) => `LAG("${f}") OVER (PARTITION BY ticker ORDER BY date) AS "prev_${f}"`)
310
321
  .join(",\n ");
311
322
 
312
323
  // Pass-through columns for the lagged CTE (unaliased, from joined CTE output)
313
324
  const dailyOpenPassthrough = [...DAILY_OPEN_FIELDS].map((f) => `"${f}"`).join(", ");
314
325
  const dailyStaticPassthrough = [...DAILY_STATIC_FIELDS].map((f) => `"${f}"`).join(", ");
315
- const vixOpenPassthrough = VIX_ALL_MAPPINGS
316
- .filter(m => m.timing === 'open')
317
- .map(m => `"${m.alias}"`)
326
+ const vixOpenPassthrough = VIX_ALL_MAPPINGS.filter((m) => m.timing === "open")
327
+ .map((m) => `"${m.alias}"`)
318
328
  .join(", ");
319
- const derivedOpenPassthrough = [...DERIVED_OPEN_FIELDS].map(f => `"${f}"`).join(", ");
329
+ const derivedOpenPassthrough = [...DERIVED_OPEN_FIELDS].map((f) => `"${f}"`).join(", ");
320
330
 
321
331
  // Legacy path for existing date-only callers (single ticker = DEFAULT_MARKET_TICKER)
322
332
  if (typeof tradeDatesOrKeys[0] === "string") {
@@ -423,40 +433,43 @@ export function buildLookaheadFreeQuery(
423
433
  */
424
434
  export function buildOutcomeQuery(tradeDates: string[]): { sql: string; params: string[] };
425
435
  export function buildOutcomeQuery(tradeKeys: MarketLookupKey[]): { sql: string; params: string[] };
426
- export function buildOutcomeQuery(
427
- tradeDatesOrKeys: string[] | MarketLookupKey[]
428
- ): { sql: string; params: string[] } {
436
+ export function buildOutcomeQuery(tradeDatesOrKeys: string[] | MarketLookupKey[]): {
437
+ sql: string;
438
+ params: string[];
439
+ } {
429
440
  if (tradeDatesOrKeys.length === 0) {
430
441
  return { sql: `SELECT * FROM market.enriched WHERE 1=0`, params: [] };
431
442
  }
432
443
 
433
- const vixCloseCols = VIX_ALL_MAPPINGS
434
- .filter(m => m.timing === 'close')
435
- .map(m => `${m.tableAlias}."${m.sourceCol}" AS "${m.alias}"`)
444
+ const vixCloseCols = VIX_ALL_MAPPINGS.filter((m) => m.timing === "close")
445
+ .map((m) => `${m.tableAlias}."${m.sourceCol}" AS "${m.alias}"`)
436
446
  .join(", ");
437
- const derivedCloseCols = [...DERIVED_CLOSE_FIELDS].map(f => `cd."${f}"`).join(", ");
447
+ const derivedCloseCols = [...DERIVED_CLOSE_FIELDS].map((f) => `cd."${f}"`).join(", ");
438
448
 
439
449
  if (typeof tradeDatesOrKeys[0] === "string") {
440
450
  return buildOutcomeQueryForDates(tradeDatesOrKeys as string[], vixCloseCols, derivedCloseCols);
441
451
  }
442
452
 
443
- return buildOutcomeQueryForKeys(tradeDatesOrKeys as MarketLookupKey[], vixCloseCols, derivedCloseCols);
453
+ return buildOutcomeQueryForKeys(
454
+ tradeDatesOrKeys as MarketLookupKey[],
455
+ vixCloseCols,
456
+ derivedCloseCols,
457
+ );
444
458
  }
445
459
 
446
460
  // Emit OHLCV-aware projection for the target-ticker close columns. Columns in
447
461
  // OHLCV_COLS come from the spot_daily alias `sAlias`; other enrichment-close
448
462
  // columns come from the enriched alias `eAlias`.
449
- function buildTargetCloseCols(
450
- eAlias: string,
451
- sAlias: string,
452
- ): string {
463
+ function buildTargetCloseCols(eAlias: string, sAlias: string): string {
453
464
  return [...DAILY_CLOSE_FIELDS]
454
465
  .map((f) => `${OHLCV_COLS.has(f) ? sAlias : eAlias}."${f}"`)
455
466
  .join(", ");
456
467
  }
457
468
 
458
469
  function buildOutcomeQueryForDates(
459
- tradeDates: string[], vixCloseCols: string, derivedCloseCols: string
470
+ tradeDates: string[],
471
+ vixCloseCols: string,
472
+ derivedCloseCols: string,
460
473
  ): { sql: string; params: string[] } {
461
474
  const eAlias = "d";
462
475
  const sAlias = "s";
@@ -473,7 +486,9 @@ function buildOutcomeQueryForDates(
473
486
  }
474
487
 
475
488
  function buildOutcomeQueryForKeys(
476
- tradeKeys: MarketLookupKey[], vixCloseCols: string, derivedCloseCols: string
489
+ tradeKeys: MarketLookupKey[],
490
+ vixCloseCols: string,
491
+ derivedCloseCols: string,
477
492
  ): { sql: string; params: string[] } {
478
493
  const eAlias = "m";
479
494
  const sAlias = "ms";
@@ -28,11 +28,18 @@ export interface FilterPredicate {
28
28
  * Day-of-week name to number mapping (market data uses 1=Mon to 5=Fri).
29
29
  */
30
30
  const DAY_NAME_TO_NUM: Record<string, number> = {
31
- monday: 1, mon: 1,
32
- tuesday: 2, tue: 2, tues: 2,
33
- wednesday: 3, wed: 3,
34
- thursday: 4, thu: 4, thurs: 4,
35
- friday: 5, fri: 5,
31
+ monday: 1,
32
+ mon: 1,
33
+ tuesday: 2,
34
+ tue: 2,
35
+ tues: 2,
36
+ wednesday: 3,
37
+ wed: 3,
38
+ thursday: 4,
39
+ thu: 4,
40
+ thurs: 4,
41
+ friday: 5,
42
+ fri: 5,
36
43
  };
37
44
 
38
45
  /**
@@ -80,10 +87,7 @@ function isCrossFieldRef(value: unknown): value is string {
80
87
  * if the bare field name (without prev_ prefix) is close-derived, try
81
88
  * the prev_ prefixed version.
82
89
  */
83
- function resolveFieldRef(
84
- refName: string,
85
- market: Record<string, unknown>
86
- ): number {
90
+ function resolveFieldRef(refName: string, market: Record<string, unknown>): number {
87
91
  // Direct lookup first (handles cases like "prev_VIX_Close" spelled out)
88
92
  if (refName in market) {
89
93
  return getNum(market, refName);