gloomberb 0.18.2 → 0.18.4

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 (954) hide show
  1. package/README.md +8 -8
  2. package/README.zh-CN.md +11 -11
  3. package/bin/{gloomberb → gloom} +3 -1
  4. package/package.json +6 -2
  5. package/patches/electrobun@1.18.1.patch +106 -5
  6. package/src/account/checkout-handoff.tsx +225 -0
  7. package/src/account/device-signin-dialog.tsx +2 -2
  8. package/src/account/device-signin.ts +2 -2
  9. package/src/account/upgrade-dialog.tsx +1 -1
  10. package/src/api-client/askg.ts +2 -2
  11. package/src/api-client/auth.ts +2 -2
  12. package/src/api-client/central-bank-rates.ts +6 -0
  13. package/src/api-client/collections.ts +5 -1
  14. package/src/api-client/cot.ts +2 -0
  15. package/src/api-client/crypto-etf-flows.ts +37 -0
  16. package/src/api-client/crypto-markets.ts +60 -0
  17. package/src/api-client/data.ts +99 -5
  18. package/src/api-client/doe.ts +15 -0
  19. package/src/api-client/equity-screener.ts +28 -0
  20. package/src/api-client/exchange-announcements.ts +38 -0
  21. package/src/api-client/fund-facts.ts +39 -0
  22. package/src/api-client/futures-curve.ts +9 -1
  23. package/src/api-client/hiring.ts +301 -0
  24. package/src/api-client/index.ts +24 -5
  25. package/src/api-client/market-discovery.ts +14 -0
  26. package/src/api-client/members.ts +6 -0
  27. package/src/api-client/mna.ts +6 -0
  28. package/src/api-client/paths.ts +18 -1
  29. package/src/api-client/request.ts +26 -7
  30. package/src/api-client/short-side-publications.ts +37 -0
  31. package/src/api-client/socket.ts +64 -4
  32. package/src/api-client/swap-curve.ts +35 -0
  33. package/src/api-client/telemetry.ts +17 -0
  34. package/src/api-client/themes.ts +7 -1
  35. package/src/api-client/types.ts +90 -2
  36. package/src/app/global-shortcuts.ts +1 -16
  37. package/src/app/pane-runtime/plugin-bindings.ts +9 -2
  38. package/src/app/runtime/desktop-deeplink.ts +5 -5
  39. package/src/app/runtime/plugin-bindings.ts +2 -2
  40. package/src/app/runtime/startup.ts +13 -0
  41. package/src/app/runtime/update.ts +28 -8
  42. package/src/app/star-prompt/status-line.tsx +2 -2
  43. package/src/architecture/core-builtin-allowlist.json +5 -2
  44. package/src/architecture/pane-tabs-allowlist.json +65 -0
  45. package/src/architecture/ui-literals-allowlist.json +3 -3
  46. package/src/architecture/ui-tokens-allowlist.json +1 -1
  47. package/src/brokers/broker-portfolio-sync.ts +37 -0
  48. package/src/brokers/directory.ts +11 -0
  49. package/src/brokers/logos.ts +3 -1
  50. package/src/brokers/signed-in/adapter.ts +304 -26
  51. package/src/brokers/signed-in/client.ts +14 -2
  52. package/src/brokers/signed-in/connect.ts +10 -2
  53. package/src/brokers/sync-broker-instance.ts +9 -1
  54. package/src/capabilities/chart-series.ts +22 -6
  55. package/src/cli/bank-section.ts +1 -1
  56. package/src/cli/base-converter.ts +23 -14
  57. package/src/cli/central-bank-events.ts +1 -1
  58. package/src/cli/command-options.ts +59 -4
  59. package/src/cli/commands/api.ts +9 -6
  60. package/src/cli/commands/broker.ts +2 -2
  61. package/src/cli/commands/command-utils.ts +2 -2
  62. package/src/cli/commands/crypto-hints.ts +7 -20
  63. package/src/cli/commands/fred-series.ts +4 -2
  64. package/src/cli/commands/keybindings.ts +2 -2
  65. package/src/cli/commands/market.ts +1189 -296
  66. package/src/cli/commands/news-hints.ts +2 -2
  67. package/src/cli/commands/news-search.ts +59 -6
  68. package/src/cli/commands/options-leaps.ts +41 -26
  69. package/src/cli/commands/overview.ts +121 -48
  70. package/src/cli/commands/plugins.ts +9 -9
  71. package/src/cli/commands/remote.ts +13 -10
  72. package/src/cli/commands/search.ts +64 -44
  73. package/src/cli/commands/system.ts +27 -19
  74. package/src/cli/commands/themes.ts +1 -1
  75. package/src/cli/commands/ticker.ts +272 -70
  76. package/src/cli/context.ts +3 -2
  77. package/src/cli/desktop-pane-shot-view.ts +2 -2
  78. package/src/cli/desktop-pane-shot.ts +1 -1
  79. package/src/cli/earnings-calendar.ts +4 -4
  80. package/src/cli/entry.ts +18 -1
  81. package/src/cli/errors.ts +20 -2
  82. package/src/cli/exit-codes.ts +1 -1
  83. package/src/cli/export-source.ts +10 -4
  84. package/src/cli/freshness.ts +2 -8
  85. package/src/cli/fx-forward.ts +130 -0
  86. package/src/cli/fx-pair.ts +10 -9
  87. package/src/cli/glossary.ts +64 -20
  88. package/src/cli/help.ts +20 -14
  89. package/src/cli/history-export.ts +126 -0
  90. package/src/cli/history-rows.ts +196 -43
  91. package/src/cli/index-roots.ts +5 -45
  92. package/src/cli/index.ts +32 -18
  93. package/src/cli/issuer-membership.ts +103 -0
  94. package/src/cli/known-gaps.ts +118 -25
  95. package/src/cli/listing-arg.ts +315 -43
  96. package/src/cli/name-entries.ts +73 -22
  97. package/src/cli/native-smoke.ts +2 -0
  98. package/src/cli/not-a-ticker.ts +19 -9
  99. package/src/cli/opentui-libc.ts +5 -0
  100. package/src/cli/options.ts +12 -0
  101. package/src/cli/pane-functions/capabilities.ts +77 -20
  102. package/src/cli/pane-functions/catalog.ts +40 -23
  103. package/src/cli/pane-functions/discovery.ts +1 -1
  104. package/src/cli/pane-functions/dom.ts +12 -8
  105. package/src/cli/pane-functions/financial-ratio-shot.ts +2 -2
  106. package/src/cli/pane-functions/freshness.ts +174 -23
  107. package/src/cli/pane-functions/function-help.ts +66 -27
  108. package/src/cli/pane-functions/headless.ts +48 -16
  109. package/src/cli/pane-functions/index.ts +82 -21
  110. package/src/cli/pane-functions/options.ts +22 -2
  111. package/src/cli/pane-functions/report-notices.ts +12 -4
  112. package/src/cli/pane-functions/report.ts +5 -5
  113. package/src/cli/pane-functions/resolver.ts +65 -14
  114. package/src/cli/pane-functions/screenshot-assessment.ts +322 -0
  115. package/src/cli/pane-functions/screenshot-bridge.ts +152 -0
  116. package/src/cli/pane-functions/screenshot-chart-evidence.ts +396 -0
  117. package/src/cli/pane-functions/screenshot-data-evidence.ts +383 -0
  118. package/src/cli/pane-functions/screenshot-evidence.ts +1 -1
  119. package/src/cli/pane-functions/screenshot-payload.ts +453 -0
  120. package/src/cli/pane-functions/screenshot-render.ts +316 -0
  121. package/src/cli/pane-functions/screenshot-types.ts +162 -0
  122. package/src/cli/pane-functions/shot-options.ts +8 -3
  123. package/src/cli/peso-dollar-rates.ts +79 -0
  124. package/src/cli/quote-answer.ts +38 -3
  125. package/src/cli/report-tables.ts +190 -27
  126. package/src/cli/restore-plugins.ts +29 -14
  127. package/src/cli/result.ts +122 -25
  128. package/src/cli/series-search.ts +5 -5
  129. package/src/cli/statement-filings.ts +19 -0
  130. package/src/cli/suffixed-listing-rows.ts +49 -0
  131. package/src/cli/symbol-args.ts +50 -15
  132. package/src/cli/symbol-cells.ts +120 -0
  133. package/src/cli/symbol-list.ts +226 -60
  134. package/src/cli/symbol-rows.ts +131 -25
  135. package/src/cli/ticker-resolution.ts +108 -11
  136. package/src/cli/treasury-yields.ts +5 -5
  137. package/src/cli/types.ts +2 -0
  138. package/src/cli/uncovered-instrument.ts +3 -3
  139. package/src/cli/unknown-command.ts +6 -6
  140. package/src/components/chart/composite/chart-layout.ts +131 -0
  141. package/src/components/chart/composite/composite-chart.tsx +387 -21
  142. package/src/components/chart/composite/drawing-store.ts +26 -6
  143. package/src/components/chart/composite/interactions.ts +9 -3
  144. package/src/components/chart/composite/legend.tsx +75 -3
  145. package/src/components/chart/composite/levels.ts +5 -0
  146. package/src/components/chart/composite/panel-gestures.ts +41 -0
  147. package/src/components/chart/composite/panel-labels.ts +2 -1
  148. package/src/components/chart/composite/panel-surface.tsx +316 -11
  149. package/src/components/chart/composite/price-axis-labels.tsx +27 -3
  150. package/src/components/chart/composite/rasterizer.ts +44 -19
  151. package/src/components/chart/composite/scene.ts +16 -4
  152. package/src/components/chart/composite/text-renderer.ts +48 -21
  153. package/src/components/chart/composite/toolbar.tsx +52 -5
  154. package/src/components/chart/composite/types.ts +19 -0
  155. package/src/components/chart/composite/use-composite-chart-keyboard.ts +120 -13
  156. package/src/components/chart/composite/use-composite-value-scales.ts +44 -0
  157. package/src/components/chart/composite/use-composite-viewport.ts +12 -3
  158. package/src/components/chart/composite/value-scale.ts +149 -0
  159. package/src/components/chart/composite/volume-profile-paint.ts +6 -3
  160. package/src/components/chart/core/pointer.ts +2 -0
  161. package/src/components/chart-table/index.ts +2 -0
  162. package/src/components/chart-table/read.tsx +74 -0
  163. package/src/components/command-bar/commands/collection-list.ts +41 -19
  164. package/src/components/command-bar/commands/collection.ts +9 -3
  165. package/src/components/command-bar/commands/direct/index.ts +1 -1
  166. package/src/components/command-bar/commands/direct/runtime.ts +3 -2
  167. package/src/components/command-bar/pane-templates/items.ts +59 -6
  168. package/src/components/command-bar/pane-templates/workflow.ts +10 -1
  169. package/src/components/command-bar/routes/root/command-items.ts +32 -6
  170. package/src/components/command-bar/routes/root/plugin-install.ts +1 -1
  171. package/src/components/command-bar/routes/root/provider-search.ts +42 -11
  172. package/src/components/command-bar/routes/root/results.ts +18 -4
  173. package/src/components/command-bar/routes/root/runtime.ts +15 -3
  174. package/src/components/command-bar/routes/root/search-providers.ts +25 -2
  175. package/src/components/command-bar/routes/root/selection.ts +6 -1
  176. package/src/components/command-bar/routes/root/shortcut-feedback.ts +4 -1
  177. package/src/components/command-bar/routes/root/shortcuts.ts +30 -3
  178. package/src/components/command-bar/routes/ticker-search/results.ts +73 -4
  179. package/src/components/command-bar/selection-runtime.ts +50 -10
  180. package/src/components/command-bar/surface/index.tsx +24 -2
  181. package/src/components/command-bar/view-model.ts +7 -0
  182. package/src/components/command-bar/workflow/broker.ts +2 -2
  183. package/src/components/command-bar/workflow/collection-actions.ts +46 -7
  184. package/src/components/command-bar/workflow/collection-ticker.ts +32 -4
  185. package/src/components/command-bar/workflow/fields.ts +8 -2
  186. package/src/components/command-bar/workflow/ops.ts +18 -4
  187. package/src/components/command-bar/workflow/portfolio-position.ts +53 -4
  188. package/src/components/command-bar/workflow/submit.ts +3 -2
  189. package/src/components/command-bar/workflow/tickers.ts +5 -1
  190. package/src/components/company-logo.tsx +39 -0
  191. package/src/components/data-table/sections.ts +4 -2
  192. package/src/components/data-table/view.tsx +23 -3
  193. package/src/components/form-modal/confirm.tsx +2 -1
  194. package/src/components/form-modal/request.ts +5 -0
  195. package/src/components/form-modal/routes.ts +4 -1
  196. package/src/components/index.ts +13 -6
  197. package/src/components/layout/detached-pane-shell.tsx +1 -0
  198. package/src/components/layout/floating-pane.tsx +1 -0
  199. package/src/components/layout/header.tsx +234 -60
  200. package/src/components/layout/market-summary.ts +9 -6
  201. package/src/components/layout/pane/capture-status.ts +1 -1
  202. package/src/components/layout/pane/footer/model.ts +11 -5
  203. package/src/components/layout/pane/header.tsx +10 -3
  204. package/src/components/layout/pane/index.tsx +1 -0
  205. package/src/components/layout/pane/pane-tabs.tsx +9 -1
  206. package/src/components/layout/shell/chrome.ts +19 -6
  207. package/src/components/layout/shell/index.tsx +2 -1
  208. package/src/components/layout/shell/pane/layers.tsx +19 -1
  209. package/src/components/layout/status-bar.tsx +2 -2
  210. package/src/components/market-board/index.tsx +11 -3
  211. package/src/components/onboarding/onboarding-wizard.tsx +1 -0
  212. package/src/components/onboarding/portfolio-step/broker-setup-panel.tsx +2 -2
  213. package/src/components/onboarding/wizard-broker-sync.ts +4 -1
  214. package/src/components/pane-settings-dialog/desktop.tsx +20 -7
  215. package/src/components/pane-settings-dialog/tui.tsx +17 -9
  216. package/src/components/pane-settings-dialog/value.ts +8 -1
  217. package/src/components/pane-settings-dialog.tsx +44 -13
  218. package/src/components/sign-in-code-panel.tsx +27 -19
  219. package/src/components/ui/column-grid.tsx +48 -4
  220. package/src/components/ui/country-flag-art.tsx +180 -0
  221. package/src/components/ui/country-flag.tsx +118 -12
  222. package/src/components/ui/data-table/opentui/index.tsx +61 -2
  223. package/src/components/ui/data-table/opentui/model.ts +109 -2
  224. package/src/components/ui/data-table/types.ts +1 -1
  225. package/src/components/ui/display.tsx +5 -1
  226. package/src/components/ui/index.ts +3 -1
  227. package/src/components/ui/logo-mark.tsx +11 -2
  228. package/src/components/ui/query-bar.tsx +1 -1
  229. package/src/components/ui/row-notes.ts +79 -0
  230. package/src/components/ui/stat-grid.tsx +28 -3
  231. package/src/components/ui/status.tsx +3 -1
  232. package/src/core/app-services.ts +4 -0
  233. package/src/core/state/app/layout.ts +4 -4
  234. package/src/data/cached-query.ts +8 -1
  235. package/src/data/config/chart-settings.ts +3 -3
  236. package/src/data/config/home.ts +10 -2
  237. package/src/data/config/layout.ts +4 -1
  238. package/src/data/config/store/node.ts +4 -0
  239. package/src/data/config/store/normalize.ts +13 -3
  240. package/src/data/config/store/portfolio-as-of-column.ts +2 -2
  241. package/src/data/json-storage.ts +2 -0
  242. package/src/data/saved-copies.ts +84 -0
  243. package/src/docs/snapshot.json +65 -32
  244. package/src/i18n/es.ts +51 -12
  245. package/src/i18n/ja.ts +51 -12
  246. package/src/i18n/ko.ts +51 -12
  247. package/src/i18n/zh-cn.ts +51 -12
  248. package/src/i18n/zh-tw.ts +51 -12
  249. package/src/layout/desks.ts +1 -1
  250. package/src/layout/launch-layout.ts +1 -1
  251. package/src/layout/pane-manager/floating-actions.ts +5 -3
  252. package/src/layout/pane-manager/floating.ts +43 -1
  253. package/src/layout/pane-manager/index.ts +2 -0
  254. package/src/layout/selected-ticker.ts +74 -0
  255. package/src/market-data/depositary-pair.ts +251 -0
  256. package/src/market-data/futures-board.ts +1 -1
  257. package/src/market-data/futures-contract.ts +124 -40
  258. package/src/market-data/fx-closes.ts +17 -2
  259. package/src/market-data/hooks.tsx +19 -11
  260. package/src/market-data/market/change-basis.ts +49 -7
  261. package/src/market-data/market/freshness.ts +34 -5
  262. package/src/market-data/market/period-return.ts +163 -0
  263. package/src/market-data/market/trading-sessions.ts +13 -0
  264. package/src/market-data/market/year-to-date.ts +8 -13
  265. package/src/market-data/performance.ts +20 -14
  266. package/src/market-data/perpetual-premium.ts +32 -0
  267. package/src/market-data/published-apac-sessions.ts +2 -1
  268. package/src/market-data/published-futures-sessions.ts +69 -0
  269. package/src/market-data/quotes/contributions.ts +5 -1
  270. package/src/market-data/quotes/freshness.ts +42 -0
  271. package/src/market-data/quotes/intraday-bar.ts +37 -0
  272. package/src/market-data/quotes/regular-session-valuation.ts +13 -8
  273. package/src/market-data/quotes/resolution.ts +4 -2
  274. package/src/market-data/tax-equivalent.ts +1 -1
  275. package/src/market-data/ticker-price-returns.ts +3 -1
  276. package/src/news/aggregator.ts +5 -1
  277. package/src/news/news-model.ts +4 -0
  278. package/src/news/types.ts +11 -0
  279. package/src/notifications/app-notifier.ts +1 -1
  280. package/src/plugins/auto-update.ts +2 -2
  281. package/src/plugins/builtin/account-management/index.tsx +1 -0
  282. package/src/plugins/builtin/account-management/pane.tsx +9 -8
  283. package/src/plugins/builtin/alerts/alert-engine.ts +30 -18
  284. package/src/plugins/builtin/alerts/calendar-events.ts +378 -0
  285. package/src/plugins/builtin/alerts/cli.ts +485 -76
  286. package/src/plugins/builtin/alerts/command.ts +5 -10
  287. package/src/plugins/builtin/alerts/event-rows.ts +9 -5
  288. package/src/plugins/builtin/alerts/events-pane.tsx +71 -56
  289. package/src/plugins/builtin/alerts/events.ts +108 -5
  290. package/src/plugins/builtin/alerts/fired-log.ts +78 -0
  291. package/src/plugins/builtin/alerts/format.ts +2 -1
  292. package/src/plugins/builtin/alerts/headless.ts +100 -39
  293. package/src/plugins/builtin/alerts/history-pane.tsx +105 -62
  294. package/src/plugins/builtin/alerts/history-rows.ts +89 -0
  295. package/src/plugins/builtin/alerts/index.tsx +45 -18
  296. package/src/plugins/builtin/alerts/iv-level.ts +365 -0
  297. package/src/plugins/builtin/alerts/levels.ts +3 -3
  298. package/src/plugins/builtin/alerts/pane.tsx +97 -29
  299. package/src/plugins/builtin/alerts/price.ts +35 -0
  300. package/src/plugins/builtin/alerts/quotes.ts +24 -0
  301. package/src/plugins/builtin/alerts/research-builder.ts +84 -11
  302. package/src/plugins/builtin/alerts/research-rules.ts +77 -3
  303. package/src/plugins/builtin/alerts/scheduled-check.ts +206 -32
  304. package/src/plugins/builtin/alerts/scheduled-sources.ts +26 -3
  305. package/src/plugins/builtin/alerts/scheduled.ts +188 -29
  306. package/src/plugins/builtin/alerts/storage.ts +13 -10
  307. package/src/plugins/builtin/alerts/targets.ts +12 -3
  308. package/src/plugins/builtin/analytics/index.tsx +8 -2
  309. package/src/plugins/builtin/analytics/metrics.ts +1 -1
  310. package/src/plugins/builtin/analytics/risk-book.ts +215 -0
  311. package/src/plugins/builtin/analytics/risk-client.ts +13 -6
  312. package/src/plugins/builtin/analytics/risk-headless.ts +55 -21
  313. package/src/plugins/builtin/analytics/risk-math.ts +6 -3
  314. package/src/plugins/builtin/analytics/risk-model.ts +297 -104
  315. package/src/plugins/builtin/analytics/risk-options.ts +17 -2
  316. package/src/plugins/builtin/analytics/risk-pane.tsx +107 -43
  317. package/src/plugins/builtin/attention/pane.tsx +22 -16
  318. package/src/plugins/builtin/awards/headless.ts +7 -3
  319. package/src/plugins/builtin/awards/model.ts +18 -0
  320. package/src/plugins/builtin/awards/pane.tsx +12 -9
  321. package/src/plugins/builtin/backtest/export.ts +1 -1
  322. package/src/plugins/builtin/backtest/headless.ts +3 -3
  323. package/src/plugins/builtin/backtest/rules.ts +41 -5
  324. package/src/plugins/builtin/broker-manager/add-flow.tsx +12 -7
  325. package/src/plugins/builtin/broker-manager/detail.tsx +47 -19
  326. package/src/plugins/builtin/broker-manager/footer.ts +27 -11
  327. package/src/plugins/builtin/broker-manager/index.tsx +21 -12
  328. package/src/plugins/builtin/broker-manager/keyboard.ts +1 -1
  329. package/src/plugins/builtin/broker-manager/model.ts +12 -2
  330. package/src/plugins/builtin/broker-manager/pane-actions.tsx +183 -57
  331. package/src/plugins/builtin/broker-manager/table.ts +28 -12
  332. package/src/plugins/builtin/broker-trading/account-picker.tsx +2 -1
  333. package/src/plugins/builtin/broker-trading/chart-levels.ts +82 -13
  334. package/src/plugins/builtin/broker-trading/controller.ts +45 -13
  335. package/src/plugins/builtin/broker-trading/dock.tsx +24 -4
  336. package/src/plugins/builtin/broker-trading/headless.ts +2 -1
  337. package/src/plugins/builtin/broker-trading/index.tsx +7 -1
  338. package/src/plugins/builtin/broker-trading/linked-orders.ts +148 -0
  339. package/src/plugins/builtin/broker-trading/order-feed.ts +75 -7
  340. package/src/plugins/builtin/broker-trading/orders.tsx +109 -31
  341. package/src/plugins/builtin/broker-trading/overview-orders.tsx +9 -3
  342. package/src/plugins/builtin/broker-trading/pane-model.ts +30 -2
  343. package/src/plugins/builtin/broker-trading/pane.tsx +115 -26
  344. package/src/plugins/builtin/broker-trading/ticket-parts.tsx +36 -7
  345. package/src/plugins/builtin/broker-trading/ticket.tsx +122 -36
  346. package/src/plugins/builtin/buildout/cells.tsx +4 -0
  347. package/src/plugins/builtin/buildout/detail/index.tsx +5 -1
  348. package/src/plugins/builtin/buildout/detail/ui.tsx +7 -4
  349. package/src/plugins/builtin/buildout/pane/index.tsx +34 -18
  350. package/src/plugins/builtin/buildout/pane/status.tsx +0 -4
  351. package/src/plugins/builtin/builtin-plugin-meta.ts +1 -1
  352. package/src/plugins/builtin/catalysts/client.ts +2 -2
  353. package/src/plugins/builtin/catalysts/detail.tsx +3 -2
  354. package/src/plugins/builtin/catalysts/index.tsx +1 -1
  355. package/src/plugins/builtin/catalysts/model.ts +49 -4
  356. package/src/plugins/builtin/catalysts/pane.tsx +9 -11
  357. package/src/plugins/builtin/central-bank-rates/client.ts +5 -0
  358. package/src/plugins/builtin/central-bank-rates/headless.ts +36 -10
  359. package/src/plugins/builtin/central-bank-rates/model.ts +33 -8
  360. package/src/plugins/builtin/changelog/index.tsx +1 -0
  361. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +1 -0
  362. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +2 -1
  363. package/src/plugins/builtin/chart-composer/chart-spec.ts +7 -0
  364. package/src/plugins/builtin/chart-composer/cli-options.ts +2 -5
  365. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +2 -1
  366. package/src/plugins/builtin/chart-composer/editor/controller.ts +2 -0
  367. package/src/plugins/builtin/chart-composer/editor.tsx +4 -1
  368. package/src/plugins/builtin/chart-composer/headless-schema.ts +28 -26
  369. package/src/plugins/builtin/chart-composer/headless.ts +253 -35
  370. package/src/plugins/builtin/chart-composer/index.tsx +12 -2
  371. package/src/plugins/builtin/chart-composer/leverage-overlay.ts +142 -0
  372. package/src/plugins/builtin/chart-composer/pane.tsx +128 -28
  373. package/src/plugins/builtin/chart-composer/series-catalog.ts +1 -0
  374. package/src/plugins/builtin/chart-composer/series-expression.ts +65 -6
  375. package/src/plugins/builtin/chart-composer/session-history.ts +15 -21
  376. package/src/plugins/builtin/chart-composer/session-range.ts +4 -2
  377. package/src/plugins/builtin/chart-composer/settings.ts +31 -19
  378. package/src/plugins/builtin/chart-composer/use-series-catalog.ts +5 -6
  379. package/src/plugins/builtin/chart-composer/viewport-labels.ts +18 -8
  380. package/src/plugins/builtin/chat/attachments/model.ts +3 -1
  381. package/src/plugins/builtin/chat/content/index.tsx +1 -1
  382. package/src/plugins/builtin/chat/pane-links/open.ts +1 -1
  383. package/src/plugins/builtin/chat/people.ts +1 -1
  384. package/src/plugins/builtin/clinical-trials/client.ts +5 -2
  385. package/src/plugins/builtin/clinical-trials/model.ts +13 -4
  386. package/src/plugins/builtin/clinical-trials/pane.tsx +32 -12
  387. package/src/plugins/builtin/clinical-trials/ticker-sponsor.ts +17 -0
  388. package/src/plugins/builtin/cloud/askg/controller.ts +1 -1
  389. package/src/plugins/builtin/cloud/askg/lock-note.ts +1 -1
  390. package/src/plugins/builtin/cloud/askg/tool-display.ts +1 -1
  391. package/src/plugins/builtin/cloud/auth-commands.ts +3 -3
  392. package/src/plugins/builtin/cloud/team/pane-sections.tsx +105 -47
  393. package/src/plugins/builtin/cloud/team/pane-ui.tsx +42 -4
  394. package/src/plugins/builtin/cloud/team/pane.tsx +204 -64
  395. package/src/plugins/builtin/cloud/thesis/store.ts +45 -22
  396. package/src/plugins/builtin/cloud-tweets/registration.ts +1 -0
  397. package/src/plugins/builtin/commodities-energy/index.tsx +29 -2
  398. package/src/plugins/builtin/commodities-energy/view-state.ts +2 -0
  399. package/src/plugins/builtin/commodity-balances/pane.tsx +14 -8
  400. package/src/plugins/builtin/company-attention/app-rank.tsx +11 -10
  401. package/src/plugins/builtin/company-attention/building-model.ts +222 -0
  402. package/src/plugins/builtin/company-attention/building.tsx +172 -0
  403. package/src/plugins/builtin/company-attention/client.ts +117 -1
  404. package/src/plugins/builtin/company-attention/evidence.ts +16 -3
  405. package/src/plugins/builtin/company-attention/headless.ts +101 -5
  406. package/src/plugins/builtin/company-attention/index.tsx +6 -3
  407. package/src/plugins/builtin/company-attention/model.ts +33 -7
  408. package/src/plugins/builtin/company-attention/moves-model.ts +253 -0
  409. package/src/plugins/builtin/company-attention/moves.tsx +159 -0
  410. package/src/plugins/builtin/company-attention/pane.tsx +89 -31
  411. package/src/plugins/builtin/company-attention/signals-model.ts +229 -0
  412. package/src/plugins/builtin/company-attention/signals.tsx +160 -0
  413. package/src/plugins/builtin/company-kpis/headless.ts +3 -2
  414. package/src/plugins/builtin/company-kpis/model.ts +2 -2
  415. package/src/plugins/builtin/company-kpis/pane.tsx +5 -4
  416. package/src/plugins/builtin/composite-plugins.ts +2 -1
  417. package/src/plugins/builtin/congress-trades/headless.ts +1 -1
  418. package/src/plugins/builtin/connections/index.ts +1 -0
  419. package/src/plugins/builtin/correlation/headless-schema.ts +3 -2
  420. package/src/plugins/builtin/correlation/headless.ts +7 -4
  421. package/src/plugins/builtin/correlation/relationship/model.ts +1 -0
  422. package/src/plugins/builtin/correlation/settings.ts +1 -0
  423. package/src/plugins/builtin/cot/headless.ts +28 -6
  424. package/src/plugins/builtin/cot/model.ts +12 -0
  425. package/src/plugins/builtin/cot/pane.tsx +7 -5
  426. package/src/plugins/builtin/cpi/headless.ts +5 -1
  427. package/src/plugins/builtin/cpi/pane.tsx +11 -9
  428. package/src/plugins/builtin/credit-boards/model.ts +2 -0
  429. package/src/plugins/builtin/credit-documents/headless.ts +1 -1
  430. package/src/plugins/builtin/credit-documents/pane.tsx +8 -7
  431. package/src/plugins/builtin/crypto-board/client.ts +86 -0
  432. package/src/plugins/builtin/crypto-board/defi-view.tsx +218 -0
  433. package/src/plugins/builtin/crypto-board/defi.ts +239 -0
  434. package/src/plugins/builtin/crypto-board/headless.ts +117 -6
  435. package/src/plugins/builtin/crypto-board/index.tsx +8 -3
  436. package/src/plugins/builtin/crypto-board/model.ts +40 -8
  437. package/src/plugins/builtin/crypto-board/pane.tsx +55 -21
  438. package/src/plugins/builtin/crypto-board/series.ts +19 -1
  439. package/src/plugins/builtin/crypto-etf-flows/client.ts +60 -0
  440. package/src/plugins/builtin/crypto-etf-flows/headless.ts +132 -0
  441. package/src/plugins/builtin/crypto-etf-flows/index.tsx +44 -0
  442. package/src/plugins/builtin/crypto-etf-flows/model.ts +121 -0
  443. package/src/plugins/builtin/crypto-etf-flows/pane.tsx +193 -0
  444. package/src/plugins/builtin/debt-maturities/pane.tsx +4 -3
  445. package/src/plugins/builtin/debug/index.tsx +1 -0
  446. package/src/plugins/builtin/dividend-yield/index.tsx +1 -1
  447. package/src/plugins/builtin/docs/index.tsx +1 -1
  448. package/src/plugins/builtin/docs/pane.tsx +2 -2
  449. package/src/plugins/builtin/docs/targets.ts +1 -1
  450. package/src/plugins/builtin/doe/client.ts +5 -1
  451. package/src/plugins/builtin/doe/headless.ts +12 -6
  452. package/src/plugins/builtin/doe/model.ts +43 -6
  453. package/src/plugins/builtin/doe/pane.tsx +19 -12
  454. package/src/plugins/builtin/earnings/board-model.ts +13 -6
  455. package/src/plugins/builtin/earnings/board-table.ts +4 -1
  456. package/src/plugins/builtin/earnings/board.tsx +253 -50
  457. package/src/plugins/builtin/earnings/calendar-model.ts +188 -0
  458. package/src/plugins/builtin/earnings/calendar.tsx +338 -0
  459. package/src/plugins/builtin/earnings/client.ts +4 -3
  460. package/src/plugins/builtin/earnings/headless.ts +53 -15
  461. package/src/plugins/builtin/earnings/history-model.ts +53 -36
  462. package/src/plugins/builtin/earnings/index.tsx +15 -22
  463. package/src/plugins/builtin/earnings/model.ts +17 -12
  464. package/src/plugins/builtin/earnings/scope.ts +89 -0
  465. package/src/plugins/builtin/earnings-calls/calendar.tsx +310 -0
  466. package/src/plugins/builtin/earnings-calls/data.ts +146 -2
  467. package/src/plugins/builtin/earnings-calls/headless.ts +151 -9
  468. package/src/plugins/builtin/earnings-calls/index.tsx +3 -3
  469. package/src/plugins/builtin/earnings-calls/lock-note.ts +1 -1
  470. package/src/plugins/builtin/earnings-calls/pane.tsx +149 -31
  471. package/src/plugins/builtin/earnings-calls/upcoming.ts +195 -0
  472. package/src/plugins/builtin/earnings-ripple/pane.tsx +10 -5
  473. package/src/plugins/builtin/econ/calendar-model.ts +132 -20
  474. package/src/plugins/builtin/econ/detail-view.tsx +48 -10
  475. package/src/plugins/builtin/econ/fred-catalog.ts +23 -6
  476. package/src/plugins/builtin/econ/fred-series-map.ts +4 -0
  477. package/src/plugins/builtin/econ/index.tsx +112 -25
  478. package/src/plugins/builtin/econ/print-watch.ts +2 -1
  479. package/src/plugins/builtin/econ/types.ts +32 -1
  480. package/src/plugins/builtin/econ-statistics/client.ts +16 -3
  481. package/src/plugins/builtin/econ-statistics/defs.ts +4 -0
  482. package/src/plugins/builtin/econ-statistics/detail.tsx +2 -2
  483. package/src/plugins/builtin/econ-statistics/headless.ts +13 -2
  484. package/src/plugins/builtin/econ-statistics/index.tsx +3 -3
  485. package/src/plugins/builtin/econ-statistics/pane.tsx +2 -1
  486. package/src/plugins/builtin/econ-statistics/stats.ts +103 -0
  487. package/src/plugins/builtin/econ-statistics/view.ts +16 -1
  488. package/src/plugins/builtin/equity-screener/client.ts +21 -3
  489. package/src/plugins/builtin/equity-screener/headless.ts +77 -5
  490. package/src/plugins/builtin/equity-screener/live.ts +1 -1
  491. package/src/plugins/builtin/equity-screener/model.ts +34 -0
  492. package/src/plugins/builtin/equity-screener/pane.tsx +148 -106
  493. package/src/plugins/builtin/equity-screener/screen-check.ts +90 -0
  494. package/src/plugins/builtin/equity-screener/ticker-check.tsx +148 -0
  495. package/src/plugins/builtin/estimate-revisions/headless.ts +3 -1
  496. package/src/plugins/builtin/estimate-revisions/lock-note.ts +3 -3
  497. package/src/plugins/builtin/estimate-revisions/model.ts +8 -10
  498. package/src/plugins/builtin/exposure/headless.ts +51 -6
  499. package/src/plugins/builtin/exposure/index.tsx +28 -2
  500. package/src/plugins/builtin/exposure/model.ts +7 -0
  501. package/src/plugins/builtin/exposure/pane.tsx +16 -10
  502. package/src/plugins/builtin/fear-greed/index.tsx +1 -1
  503. package/src/plugins/builtin/filing-events/index.tsx +1 -1
  504. package/src/plugins/builtin/futures/model.ts +10 -9
  505. package/src/plugins/builtin/futures/returns.ts +8 -36
  506. package/src/plugins/builtin/futures/table.tsx +1 -1
  507. package/src/plugins/builtin/futures-curve/client.ts +40 -9
  508. package/src/plugins/builtin/futures-curve/headless.ts +39 -17
  509. package/src/plugins/builtin/futures-curve/model.ts +258 -69
  510. package/src/plugins/builtin/futures-curve/pane.tsx +46 -17
  511. package/src/plugins/builtin/fx-matrix/client.ts +15 -8
  512. package/src/plugins/builtin/fx-matrix/headless.ts +32 -14
  513. package/src/plugins/builtin/fx-matrix/index.tsx +13 -11
  514. package/src/plugins/builtin/fx-matrix/live-legs.ts +22 -0
  515. package/src/plugins/builtin/fx-matrix/settings.ts +2 -1
  516. package/src/plugins/builtin/gpu/board.tsx +4 -1
  517. package/src/plugins/builtin/gpu/changes.tsx +10 -10
  518. package/src/plugins/builtin/gpu/equities.tsx +4 -1
  519. package/src/plugins/builtin/gpu/headless.ts +9 -4
  520. package/src/plugins/builtin/gpu/history.tsx +4 -2
  521. package/src/plugins/builtin/gpu/pane.tsx +5 -3
  522. package/src/plugins/builtin/help/index.tsx +13 -3
  523. package/src/plugins/builtin/holders/beneficial-model.ts +8 -11
  524. package/src/plugins/builtin/holders/beneficial-report.ts +6 -5
  525. package/src/plugins/builtin/holders/beneficial-view.tsx +7 -3
  526. package/src/plugins/builtin/holders/client.ts +15 -2
  527. package/src/plugins/builtin/holders/format.ts +28 -17
  528. package/src/plugins/builtin/holders/headless.ts +48 -8
  529. package/src/plugins/builtin/holders/index-holders.ts +264 -0
  530. package/src/plugins/builtin/holders/pane.tsx +79 -15
  531. package/src/plugins/builtin/holders/report-rows.ts +35 -7
  532. package/src/plugins/builtin/holders/table-model.ts +2 -1
  533. package/src/plugins/builtin/holders/thirteenf-match.ts +3 -1
  534. package/src/plugins/builtin/holders/treemap.tsx +2 -2
  535. package/src/plugins/builtin/insider/base-values.ts +11 -7
  536. package/src/plugins/builtin/insider/client.ts +3 -0
  537. package/src/plugins/builtin/insider/headless.ts +20 -7
  538. package/src/plugins/builtin/insider/index.tsx +17 -8
  539. package/src/plugins/builtin/insider/issuer.ts +34 -4
  540. package/src/plugins/builtin/insider/signals-client.ts +3 -3
  541. package/src/plugins/builtin/insider/signals.tsx +1 -1
  542. package/src/plugins/builtin/insider/table-model.ts +35 -13
  543. package/src/plugins/builtin/insider/table.tsx +5 -2
  544. package/src/plugins/builtin/ipo-calendar/pane.tsx +7 -4
  545. package/src/plugins/builtin/iv-history/client.ts +20 -0
  546. package/src/plugins/builtin/iv-history/events.ts +145 -0
  547. package/src/plugins/builtin/iv-history/format.ts +3 -0
  548. package/src/plugins/builtin/iv-history/headless.ts +91 -7
  549. package/src/plugins/builtin/iv-history/index.tsx +1 -1
  550. package/src/plugins/builtin/iv-history/model.ts +13 -4
  551. package/src/plugins/builtin/iv-history/series.ts +3 -1
  552. package/src/plugins/builtin/jobs/lock-note.ts +1 -1
  553. package/src/plugins/builtin/jobs/model.ts +4 -15
  554. package/src/plugins/builtin/jobs/pane.tsx +7 -5
  555. package/src/plugins/builtin/jobs/share-bars.tsx +11 -5
  556. package/src/plugins/builtin/jodi/pane.tsx +14 -8
  557. package/src/plugins/builtin/layout-manager/index.tsx +1 -0
  558. package/src/plugins/builtin/macro-day/headless.ts +20 -7
  559. package/src/plugins/builtin/macro-day/index.tsx +3 -2
  560. package/src/plugins/builtin/macro-day/model.ts +29 -8
  561. package/src/plugins/builtin/macro-day/pane.tsx +46 -10
  562. package/src/plugins/builtin/macro-day/releases.ts +55 -13
  563. package/src/plugins/builtin/market-heatmap/data.ts +9 -2
  564. package/src/plugins/builtin/market-heatmap/evidence.ts +1 -1
  565. package/src/plugins/builtin/market-heatmap/headless.ts +9 -6
  566. package/src/plugins/builtin/market-heatmap/index.tsx +3 -3
  567. package/src/plugins/builtin/market-heatmap/model.ts +10 -7
  568. package/src/plugins/builtin/market-movers/client.ts +36 -21
  569. package/src/plugins/builtin/market-movers/headless.ts +8 -2
  570. package/src/plugins/builtin/market-movers/index.tsx +16 -10
  571. package/src/plugins/builtin/market-movers/screener.ts +33 -11
  572. package/src/plugins/builtin/market-movers/session-body.tsx +4 -2
  573. package/src/plugins/builtin/market-movers/session-table.ts +4 -2
  574. package/src/plugins/builtin/market-movers/table.ts +4 -1
  575. package/src/plugins/builtin/market-valuation/headless.ts +2 -0
  576. package/src/plugins/builtin/market-valuation/view.ts +5 -0
  577. package/src/plugins/builtin/members/headless.ts +6 -5
  578. package/src/plugins/builtin/members/pane.tsx +11 -4
  579. package/src/plugins/builtin/mna/client.ts +1 -0
  580. package/src/plugins/builtin/mna/detail.tsx +20 -32
  581. package/src/plugins/builtin/mna/distress/detail.tsx +16 -4
  582. package/src/plugins/builtin/mna/distress/model.ts +3 -2
  583. package/src/plugins/builtin/mna/distress/pane.tsx +7 -4
  584. package/src/plugins/builtin/mna/headless.ts +6 -13
  585. package/src/plugins/builtin/mna/model.ts +93 -15
  586. package/src/plugins/builtin/mna/pane.tsx +5 -4
  587. package/src/plugins/builtin/news/headless.ts +12 -6
  588. package/src/plugins/builtin/news/index.tsx +10 -1
  589. package/src/plugins/builtin/news/wire/index.tsx +3 -2
  590. package/src/plugins/builtin/news/wire/news/command-bar-search.ts +26 -10
  591. package/src/plugins/builtin/news/wire/news/query-presets.ts +6 -2
  592. package/src/plugins/builtin/news/wire/rss/cli.ts +3 -3
  593. package/src/plugins/builtin/notes/cli.ts +50 -15
  594. package/src/plugins/builtin/notes/export.ts +17 -6
  595. package/src/plugins/builtin/notes/files.ts +16 -5
  596. package/src/plugins/builtin/openfda/pane.tsx +1 -1
  597. package/src/plugins/builtin/options/carry.ts +2 -2
  598. package/src/plugins/builtin/options/enrichment-model.ts +10 -9
  599. package/src/plugins/builtin/options/index.tsx +1 -1
  600. package/src/plugins/builtin/options/model-spot.ts +70 -4
  601. package/src/plugins/builtin/options/view.tsx +51 -23
  602. package/src/plugins/builtin/options-calculator/headless.ts +46 -7
  603. package/src/plugins/builtin/options-calculator/pane.tsx +3 -2
  604. package/src/plugins/builtin/options-positioning/headless.ts +11 -3
  605. package/src/plugins/builtin/options-positioning/model.ts +24 -0
  606. package/src/plugins/builtin/options-positioning/pane.tsx +10 -12
  607. package/src/plugins/builtin/options-scenario/client.ts +142 -29
  608. package/src/plugins/builtin/options-scenario/collar.ts +8 -6
  609. package/src/plugins/builtin/options-scenario/csp-screen-headless.ts +127 -0
  610. package/src/plugins/builtin/options-scenario/csp-screen-pane.tsx +165 -0
  611. package/src/plugins/builtin/options-scenario/csp-screen.ts +258 -0
  612. package/src/plugins/builtin/options-scenario/csp.ts +101 -21
  613. package/src/plugins/builtin/options-scenario/headless.ts +49 -21
  614. package/src/plugins/builtin/options-scenario/hedge.ts +20 -14
  615. package/src/plugins/builtin/options-scenario/index.tsx +28 -3
  616. package/src/plugins/builtin/options-scenario/model.ts +13 -0
  617. package/src/plugins/builtin/options-scenario/pane.tsx +22 -10
  618. package/src/plugins/builtin/perps/equity-row.tsx +11 -3
  619. package/src/plugins/builtin/perps/freshness.ts +8 -5
  620. package/src/plugins/builtin/perps/headless.ts +3 -1
  621. package/src/plugins/builtin/perps/list-perpetuals.ts +25 -4
  622. package/src/plugins/builtin/perps/live-rows.ts +161 -0
  623. package/src/plugins/builtin/perps/markets-section.tsx +154 -0
  624. package/src/plugins/builtin/perps/pane.tsx +36 -17
  625. package/src/plugins/builtin/perps/venue-markets.ts +96 -0
  626. package/src/plugins/builtin/plugin-marketplace/index.tsx +2 -1
  627. package/src/plugins/builtin/plugin-marketplace/pane.tsx +145 -60
  628. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +78 -27
  629. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +158 -141
  630. package/src/plugins/builtin/portfolio-list/cli/render.ts +49 -20
  631. package/src/plugins/builtin/portfolio-list/cli/shared.ts +3 -3
  632. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +29 -24
  633. package/src/plugins/builtin/portfolio-list/headless.ts +6 -3
  634. package/src/plugins/builtin/portfolio-list/income.ts +13 -2
  635. package/src/plugins/builtin/portfolio-list/index.tsx +9 -2
  636. package/src/plugins/builtin/portfolio-list/pane/index.tsx +21 -8
  637. package/src/plugins/builtin/portfolio-list/pane/purchase-date-fx.ts +46 -0
  638. package/src/plugins/builtin/portfolio-list/summary/live-accounts.ts +16 -9
  639. package/src/plugins/builtin/portfolio-list/summary/totals.ts +2 -15
  640. package/src/plugins/builtin/power/client.ts +6 -3
  641. package/src/plugins/builtin/power/evidence.ts +22 -7
  642. package/src/plugins/builtin/power/gas.tsx +5 -1
  643. package/src/plugins/builtin/power/pane.tsx +44 -32
  644. package/src/plugins/builtin/power/prices.tsx +10 -3
  645. package/src/plugins/builtin/research/analyst-headless.ts +25 -8
  646. package/src/plugins/builtin/research/analyst-model.ts +68 -3
  647. package/src/plugins/builtin/research/corporate-actions-pane.tsx +63 -14
  648. package/src/plugins/builtin/research/event-model.ts +3 -1
  649. package/src/plugins/builtin/research/event-sources.ts +12 -4
  650. package/src/plugins/builtin/research/index.tsx +2 -1
  651. package/src/plugins/builtin/research/relative-valuation-basis.ts +58 -0
  652. package/src/plugins/builtin/research/relative-valuation-columns.ts +31 -2
  653. package/src/plugins/builtin/research/relative-valuation-currency.ts +12 -5
  654. package/src/plugins/builtin/research/relative-valuation-headless.ts +84 -26
  655. package/src/plugins/builtin/research/relative-valuation-model.ts +88 -19
  656. package/src/plugins/builtin/research/relative-valuation-pane.tsx +76 -9
  657. package/src/plugins/builtin/research/relative-valuation-peers.ts +1 -1
  658. package/src/plugins/builtin/reverse-dcf/client.ts +2 -1
  659. package/src/plugins/builtin/reverse-dcf/model.ts +10 -5
  660. package/src/plugins/builtin/risk-factors/index.tsx +2 -2
  661. package/src/plugins/builtin/scanner/lock-note.ts +1 -1
  662. package/src/plugins/builtin/seasonality/client.ts +2 -1
  663. package/src/plugins/builtin/sec/forms.ts +13 -0
  664. package/src/plugins/builtin/sec/fund-abroad.ts +32 -0
  665. package/src/plugins/builtin/sec/fund-facts.ts +68 -8
  666. package/src/plugins/builtin/sec/headless.ts +85 -8
  667. package/src/plugins/builtin/sec/index.tsx +58 -12
  668. package/src/plugins/builtin/sectors/client.ts +6 -4
  669. package/src/plugins/builtin/sectors/sector-model.ts +11 -15
  670. package/src/plugins/builtin/series-inventory.ts +2 -0
  671. package/src/plugins/builtin/shared/broker-reconnect.ts +107 -22
  672. package/src/plugins/builtin/shared/cloud-resource.ts +15 -2
  673. package/src/plugins/builtin/shared/cloud-upgrade.ts +34 -6
  674. package/src/plugins/builtin/shared/earnings-calendar.ts +375 -0
  675. package/src/plugins/builtin/{earnings/estimate-basis.ts → shared/earnings-estimate-basis.ts} +1 -1
  676. package/src/plugins/builtin/shared/earnings-report.ts +3 -3
  677. package/src/plugins/builtin/shared/fx-rate-freshness.ts +23 -1
  678. package/src/plugins/builtin/shared/job-posting.ts +129 -0
  679. package/src/plugins/builtin/shared/pro-lock-note.ts +3 -3
  680. package/src/plugins/builtin/shared/report-freshness.ts +3 -0
  681. package/src/plugins/builtin/shared/research-trading.tsx +23 -0
  682. package/src/plugins/builtin/shared/series-cache.ts +2 -0
  683. package/src/plugins/builtin/shared/series-list-detail.tsx +3 -1
  684. package/src/plugins/builtin/shared/ticker-surface.ts +2 -1
  685. package/src/plugins/builtin/shared/volatility/options.ts +2 -1
  686. package/src/plugins/builtin/short-interest/client.ts +2 -0
  687. package/src/plugins/builtin/short-interest/headless.ts +41 -12
  688. package/src/plugins/builtin/short-interest/index.tsx +23 -1
  689. package/src/plugins/builtin/short-interest/model.ts +70 -19
  690. package/src/plugins/builtin/short-interest/pane.tsx +19 -2
  691. package/src/plugins/builtin/short-interest/publications-client.ts +82 -0
  692. package/src/plugins/builtin/short-interest/publications-headless.ts +29 -0
  693. package/src/plugins/builtin/short-interest/publications-model.ts +50 -0
  694. package/src/plugins/builtin/short-interest/publications-pane.tsx +66 -0
  695. package/src/plugins/builtin/short-interest/schedule.ts +35 -2
  696. package/src/plugins/builtin/short-interest/surface.tsx +11 -4
  697. package/src/plugins/builtin/short-interest/types.ts +9 -0
  698. package/src/plugins/builtin/short-interest/watch-client.ts +14 -8
  699. package/src/plugins/builtin/short-interest/watch-model.ts +12 -25
  700. package/src/plugins/builtin/short-interest/watch-pane.tsx +5 -1
  701. package/src/plugins/builtin/social-mentions/client.ts +2 -1
  702. package/src/plugins/builtin/supply-chain/flow.tsx +33 -9
  703. package/src/plugins/builtin/supply-chain/model.ts +51 -3
  704. package/src/plugins/builtin/supply-chain/pane.tsx +78 -39
  705. package/src/plugins/builtin/supply-chain/row-evidence.tsx +1 -1
  706. package/src/plugins/builtin/themes/headless.ts +8 -5
  707. package/src/plugins/builtin/themes/model.ts +14 -4
  708. package/src/plugins/builtin/themes/pane.tsx +24 -5
  709. package/src/plugins/builtin/thirteenf/headless.ts +5 -5
  710. package/src/plugins/builtin/thirteenf/signals.ts +3 -1
  711. package/src/plugins/builtin/ticker-detail/adr-pair/headless.ts +123 -0
  712. package/src/plugins/builtin/ticker-detail/adr-pair/model.ts +132 -0
  713. package/src/plugins/builtin/ticker-detail/adr-pair/tab.tsx +87 -0
  714. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +40 -26
  715. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +8 -4
  716. package/src/plugins/builtin/ticker-detail/data-panes/returns-history.ts +67 -3
  717. package/src/plugins/builtin/ticker-detail/data-panes/returns-model.ts +112 -5
  718. package/src/plugins/builtin/ticker-detail/data-panes/returns-pane.tsx +17 -2
  719. package/src/plugins/builtin/ticker-detail/financials/aggregation.ts +21 -7
  720. package/src/plugins/builtin/ticker-detail/financials/model.ts +36 -1
  721. package/src/plugins/builtin/ticker-detail/financials/offerings.ts +56 -0
  722. package/src/plugins/builtin/ticker-detail/financials/ratios.ts +62 -13
  723. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +30 -4
  724. package/src/plugins/builtin/ticker-detail/headless-schema.ts +14 -2
  725. package/src/plugins/builtin/ticker-detail/headless.ts +148 -35
  726. package/src/plugins/builtin/ticker-detail/index.tsx +37 -5
  727. package/src/plugins/builtin/ticker-detail/overview/model.ts +65 -10
  728. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +9 -1
  729. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +68 -11
  730. package/src/plugins/builtin/ticker-detail/pane.tsx +11 -0
  731. package/src/plugins/builtin/ticker-detail/quote-footer.ts +8 -3
  732. package/src/plugins/builtin/ticker-detail/research-tabs.ts +11 -0
  733. package/src/plugins/builtin/vol-surface/client.ts +28 -7
  734. package/src/plugins/builtin/vol-surface/headless.ts +43 -15
  735. package/src/plugins/builtin/vol-surface/model.ts +34 -12
  736. package/src/plugins/builtin/vol-surface/pane.tsx +33 -13
  737. package/src/plugins/builtin/vol-surface/stored.ts +34 -3
  738. package/src/plugins/builtin/vol-surface/tables.ts +14 -0
  739. package/src/plugins/builtin/volatility/model.ts +5 -10
  740. package/src/plugins/builtin/world-venue-map/basemap-layer.tsx +4 -3
  741. package/src/plugins/builtin/world-venue-map/basemap.ts +3 -1
  742. package/src/plugins/builtin/world-venue-map/chokepoint-chart.ts +40 -0
  743. package/src/plugins/builtin/world-venue-map/evidence.ts +1 -1
  744. package/src/plugins/builtin/world-venue-map/geo-series.ts +90 -11
  745. package/src/plugins/builtin/world-venue-map/headless.ts +1 -1
  746. package/src/plugins/builtin/world-venue-map/index.ts +3 -26
  747. package/src/plugins/builtin/world-venue-map/layers.ts +1 -1
  748. package/src/plugins/builtin/world-venue-map/map.tsx +2 -1
  749. package/src/plugins/builtin/world-venue-map/pane.tsx +4 -2
  750. package/src/plugins/builtin/world-venue-map/venue-header.tsx +15 -4
  751. package/src/plugins/builtin/yield-curve/client.ts +25 -0
  752. package/src/plugins/builtin/yield-curve/curves.ts +7 -4
  753. package/src/plugins/builtin/yield-curve/headless.ts +38 -4
  754. package/src/plugins/builtin/yield-curve/history.ts +4 -3
  755. package/src/plugins/builtin/yield-curve/index.tsx +12 -6
  756. package/src/plugins/builtin/yield-curve/swaps-model.ts +93 -0
  757. package/src/plugins/builtin/yield-curve/swaps.tsx +99 -0
  758. package/src/plugins/bundle.ts +1 -1
  759. package/src/plugins/catalog-browser.ts +2 -1
  760. package/src/plugins/compat.ts +3 -3
  761. package/src/plugins/dependencies.ts +75 -14
  762. package/src/plugins/extracted-plugins.ts +132 -34
  763. package/src/plugins/host-link.ts +149 -34
  764. package/src/plugins/installer.ts +35 -10
  765. package/src/plugins/loader.ts +206 -38
  766. package/src/plugins/manager-node.ts +2 -2
  767. package/src/plugins/marketplace/deactivation.ts +22 -0
  768. package/src/plugins/marketplace/model.ts +2 -2
  769. package/src/plugins/marketplace/packs.ts +1 -1
  770. package/src/plugins/ownership.ts +1 -1
  771. package/src/plugins/peer-retry.ts +155 -0
  772. package/src/plugins/registry/contributions.ts +3 -1
  773. package/src/plugins/registry/index.ts +4 -3
  774. package/src/plugins/registry/plugin-state.ts +3 -0
  775. package/src/plugins/seed-notice.ts +20 -0
  776. package/src/plugins/shortcut-argument.ts +39 -0
  777. package/src/portfolio/allocation.ts +1 -1
  778. package/src/portfolio/collection-name.ts +31 -0
  779. package/src/portfolio/column-values.ts +10 -8
  780. package/src/portfolio/cost-fx.ts +296 -19
  781. package/src/portfolio/manual-lots.ts +75 -0
  782. package/src/portfolio/mutations.ts +60 -22
  783. package/src/portfolio/suffixed-listings.ts +209 -0
  784. package/src/portfolio/totals-currency.ts +24 -0
  785. package/src/public/__snapshots__/public-api.test.ts.snap +14 -0
  786. package/src/public/time-series.ts +11 -8
  787. package/src/remote/schema.ts +1 -1
  788. package/src/renderers/browser/config-host.ts +3 -0
  789. package/src/renderers/browser/main.tsx +23 -3
  790. package/src/renderers/dom/boot-frame-page.ts +187 -0
  791. package/src/renderers/dom/boot-frame.ts +237 -0
  792. package/src/renderers/dom/build-assets.ts +46 -8
  793. package/src/renderers/dom/desktop/controls.tsx +1 -1
  794. package/src/renderers/dom/desktop/query-bar.tsx +2 -0
  795. package/src/renderers/dom/dom-ui-host.tsx +4 -29
  796. package/src/renderers/dom/host/ascii-text.ts +16 -2
  797. package/src/renderers/dom/host/box.tsx +43 -2
  798. package/src/renderers/dom/host/chart-surface.tsx +2 -0
  799. package/src/renderers/dom/host/hls.chunk.ts +3 -0
  800. package/src/renderers/dom/host/image-surface.tsx +49 -0
  801. package/src/renderers/dom/host/media-surface.tsx +24 -18
  802. package/src/renderers/dom/host/mouse.ts +30 -0
  803. package/src/renderers/dom/host/size-observer.ts +1 -1
  804. package/src/renderers/dom/host/style.ts +1 -1
  805. package/src/renderers/dom/host/tabs.tsx +16 -5
  806. package/src/renderers/dom/host/top-surface.ts +127 -0
  807. package/src/renderers/dom/styles.css +115 -0
  808. package/src/renderers/dom/test-utils.tsx +2 -1
  809. package/src/renderers/electrobun/bun/application-menu/index.ts +3 -3
  810. package/src/renderers/electrobun/bun/core-capabilities.ts +9 -1
  811. package/src/renderers/electrobun/bun/desktop/backend-requests.ts +3 -0
  812. package/src/renderers/electrobun/bun/desktop/backend.ts +56 -3
  813. package/src/renderers/electrobun/bun/desktop/detached-windows.ts +1 -1
  814. package/src/renderers/electrobun/bun/desktop/host-requests.ts +9 -3
  815. package/src/renderers/electrobun/bun/desktop/initialization.ts +81 -18
  816. package/src/renderers/electrobun/bun/desktop/update.ts +210 -30
  817. package/src/renderers/electrobun/bun/external-plugins.ts +29 -7
  818. package/src/renderers/electrobun/bun/index.ts +11 -1
  819. package/src/renderers/electrobun/bun/window/boot-frame.ts +67 -0
  820. package/src/renderers/electrobun/bun/window/create.ts +4 -1
  821. package/src/renderers/electrobun/shared/boot-frame.ts +7 -0
  822. package/src/renderers/electrobun/shared/protocol.ts +6 -1
  823. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +1 -1
  824. package/src/renderers/electrobun/view/config-host.ts +3 -0
  825. package/src/renderers/electrobun/view/fatal-screen.tsx +1 -1
  826. package/src/renderers/electrobun/view/main.tsx +30 -4
  827. package/src/renderers/electrobun/view/news-source.ts +9 -7
  828. package/src/renderers/electrobun/view/remote/asset-data-client.ts +9 -2
  829. package/src/renderers/electrobun/view/ui-host.tsx +1 -1
  830. package/src/renderers/opentui/browser-open.ts +88 -0
  831. package/src/renderers/opentui/host.tsx +5 -14
  832. package/src/renderers/opentui/image/loader.ts +3 -2
  833. package/src/renderers/opentui/native-smoke.ts +10 -1
  834. package/src/renderers/opentui/pane-image/index.ts +2 -1
  835. package/src/renderers/opentui/render-lib.ts +253 -0
  836. package/src/renderers/opentui/render-timing-smoke.ts +1 -1
  837. package/src/renderers/opentui/start.tsx +8 -1
  838. package/src/renderers/share/layout-view.tsx +2 -2
  839. package/src/renderers/share/main.tsx +4 -4
  840. package/src/renderers/share/view.tsx +1 -1
  841. package/src/series/resolve.ts +22 -6
  842. package/src/series/standalone.ts +30 -2
  843. package/src/series/types.ts +8 -1
  844. package/src/shares/api.ts +4 -1
  845. package/src/shares/pane.ts +1 -1
  846. package/src/sources/gloomberb-cloud/fred-series.ts +46 -1
  847. package/src/sources/gloomberb-cloud/index.ts +39 -16
  848. package/src/sources/gloomberb-cloud/news.ts +39 -0
  849. package/src/sources/gloomberb-cloud/normalizers.ts +14 -1
  850. package/src/sources/gloomberb-cloud/perpetuals.ts +49 -1
  851. package/src/sources/listing-symbols.ts +37 -0
  852. package/src/sources/provider-errors.ts +16 -2
  853. package/src/sources/provider-router/financial-routes.ts +21 -3
  854. package/src/sources/provider-router/financials.ts +15 -2
  855. package/src/sources/provider-router/history.ts +30 -8
  856. package/src/sources/provider-router/index.ts +16 -0
  857. package/src/sources/provider-router/primary.ts +1 -1
  858. package/src/state/app/bootstrap.ts +23 -0
  859. package/src/state/hooks/inline-tickers.ts +30 -5
  860. package/src/sync/controller.ts +1 -1
  861. package/src/sync/core-contributors.ts +46 -14
  862. package/src/team/collections-sync.ts +2 -1
  863. package/src/team/collections.ts +178 -17
  864. package/src/telemetry/crash-reports.ts +21 -4
  865. package/src/telemetry/update-failures-node.ts +59 -0
  866. package/src/telemetry/update-failures.ts +307 -0
  867. package/src/test-support/builtin-panes.ts +1 -1
  868. package/src/theme/colors.ts +3 -30
  869. package/src/theme/ui-tokens.ts +37 -1
  870. package/src/tickers/company-name-listing.ts +215 -36
  871. package/src/tickers/company-name.ts +43 -0
  872. package/src/tickers/index-roots.ts +47 -0
  873. package/src/tickers/instrument-label.ts +5 -1
  874. package/src/tickers/listing-fate.ts +30 -0
  875. package/src/tickers/metadata.ts +10 -0
  876. package/src/tickers/perpetual-listing.ts +5 -2
  877. package/src/tickers/search/home-listing.ts +75 -0
  878. package/src/tickers/search/index.ts +76 -27
  879. package/src/tickers/search/ranking.ts +54 -4
  880. package/src/tickers/search/upsert.ts +29 -0
  881. package/src/tickers/terminal-codes.ts +416 -40
  882. package/src/time-series/bar-aggregation.ts +243 -0
  883. package/src/time-series/base-series.ts +307 -0
  884. package/src/time-series/chart-bounds.ts +349 -0
  885. package/src/time-series/chart-seed.ts +142 -0
  886. package/src/time-series/economic.ts +5 -0
  887. package/src/time-series/fundamentals.ts +18 -3
  888. package/src/time-series/history-acquisition.ts +499 -0
  889. package/src/time-series/leverage.ts +100 -0
  890. package/src/time-series/market-resolution.ts +4 -2
  891. package/src/time-series/market.ts +2 -1
  892. package/src/time-series/price-comparison.ts +175 -30
  893. package/src/time-series/range.ts +9 -1
  894. package/src/time-series/resolution.ts +174 -16
  895. package/src/time-series/resolve-context.ts +157 -0
  896. package/src/time-series/resolve.ts +126 -1577
  897. package/src/time-series/series-name.ts +38 -0
  898. package/src/time-series/series-presentation.ts +208 -0
  899. package/src/time-series/spec.ts +11 -6
  900. package/src/time-series/studies.ts +109 -12
  901. package/src/time-series/tail-reconcile.ts +121 -0
  902. package/src/time-series/types.ts +29 -2
  903. package/src/time-series/use-chart-resolution.ts +4 -5
  904. package/src/types/broker.ts +10 -0
  905. package/src/types/config.ts +14 -0
  906. package/src/types/data-provider.ts +20 -0
  907. package/src/types/exchange-rate.ts +6 -0
  908. package/src/types/financials.ts +104 -7
  909. package/src/types/headless.ts +83 -6
  910. package/src/types/instrument.ts +3 -0
  911. package/src/types/issuer-listings.ts +28 -0
  912. package/src/types/plugin.ts +65 -8
  913. package/src/types/price-history.ts +2 -0
  914. package/src/types/ticker.ts +13 -0
  915. package/src/types/trading.ts +59 -1
  916. package/src/ui/ascii-font.ts +13 -1
  917. package/src/ui/host.tsx +6 -1
  918. package/src/updater/command-names.ts +175 -0
  919. package/src/updater/failure.ts +163 -0
  920. package/src/updater/index.ts +97 -28
  921. package/src/utils/calendar-date.ts +32 -15
  922. package/src/utils/cash-runway.ts +241 -0
  923. package/src/utils/central-banks.ts +42 -0
  924. package/src/utils/cli-output.ts +259 -80
  925. package/src/utils/contract-month.ts +16 -0
  926. package/src/utils/crypto-pair.ts +61 -3
  927. package/src/utils/currency-pair.ts +26 -0
  928. package/src/utils/currency-units.ts +29 -0
  929. package/src/utils/datetime-format.ts +10 -0
  930. package/src/utils/debug-log.ts +1 -1
  931. package/src/utils/decimal-comma.ts +39 -6
  932. package/src/utils/exchange-announcements.ts +71 -0
  933. package/src/utils/exchange-rate-snapshot.ts +10 -0
  934. package/src/utils/financial-statements.ts +83 -4
  935. package/src/utils/format.ts +34 -16
  936. package/src/utils/fundamentals.ts +150 -34
  937. package/src/utils/fx-market-hours.ts +10 -1
  938. package/src/utils/latest-financial-period.ts +8 -0
  939. package/src/utils/linux-libc.ts +54 -0
  940. package/src/utils/market-capitalization.ts +111 -15
  941. package/src/utils/max-drawdown.ts +64 -0
  942. package/src/utils/network-failure.ts +83 -0
  943. package/src/utils/option-expiry.ts +139 -7
  944. package/src/utils/price-earnings.ts +11 -5
  945. package/src/utils/price-history.ts +18 -8
  946. package/src/utils/price-window.ts +131 -0
  947. package/src/utils/release-date.ts +47 -0
  948. package/src/utils/sec.ts +71 -0
  949. package/src/utils/throttled-fetch.ts +11 -4
  950. package/src/utils/trailing-eps.ts +67 -0
  951. package/src/utils/typed-text.ts +21 -0
  952. package/src/utils/utc-time.ts +24 -1
  953. package/src/version.ts +6 -0
  954. package/src/cli/pane-functions/screenshot.ts +0 -2122
@@ -5,7 +5,7 @@ import { canonicalExchange } from "../../utils/exchanges";
5
5
  import { isFiniteNumber } from "../../utils/guards";
6
6
  import { formatUtcDayTime } from "../../utils/utc-time";
7
7
  import { zonedDateKey } from "../../utils/zoned-date-time";
8
- import { futuresChangeBasis, isFuturesInstrument } from "../futures-contract";
8
+ import { futuresChangeBasis, futuresSettleText, isFuturesInstrument } from "../futures-contract";
9
9
  import { quoteTradingDay } from "../quotes/day-range";
10
10
  import { previousPublishedSession } from "./freshness";
11
11
  import { getActiveQuoteDisplay, getRegularSessionDisplay, regularSessionDisplayDate } from "./status";
@@ -65,6 +65,30 @@ function quoteVenue(quote: Quote): string {
65
65
  return canonicalExchange(quote.listingExchangeName || quote.exchangeName);
66
66
  }
67
67
 
68
+ /**
69
+ * The venue whose calendar an index's sessions follow, where its quote names
70
+ * the index's publisher or feed instead of a venue: the Hang Seng family's
71
+ * HKSE trades HKEX's days, the Nikkei 225's OSAKA JPX's, and the US
72
+ * publishers' the US equity calendar. An index quoted under a venue (KRX, NSE,
73
+ * SSE) is that venue's already.
74
+ */
75
+ const INDEX_CALENDAR_VENUES: Readonly<Record<string, string>> = {
76
+ HKSE: "HKEX",
77
+ OSAKA: "JPX",
78
+ SNP: "NYSE",
79
+ DJI: "NYSE",
80
+ "NASDAQ GIDS": "NASDAQ",
81
+ "CBOE INDICES": "CBOE",
82
+ "CHICAGO OPTIONS": "CBOE",
83
+ };
84
+
85
+ /** The venue whose published calendar dates the quote's sessions. */
86
+ function calendarVenue(quote: Quote): string {
87
+ const venue = quoteVenue(quote);
88
+ const index = classifyInstrumentType(quote.instrumentType) === "index" || kindFromListingSyntax(quote.symbol) === "index";
89
+ return (index && INDEX_CALENDAR_VENUES[venue]) || venue;
90
+ }
91
+
68
92
  function isCurrencyPair(quote: Quote): boolean {
69
93
  return classifyInstrumentType(quote.instrumentType) === "currency"
70
94
  || kindFromListingSyntax(quote.symbol, quote.listingExchangeName || quote.exchangeName) === "currency";
@@ -93,11 +117,12 @@ function previousIndexSession(quote: Quote, date: string): string | null {
93
117
 
94
118
  /**
95
119
  * The session before the one a move is dated to: from the venue's published
96
- * calendar, with the closures in between; for an index from its own sessions;
97
- * for a currency pair the weekday before. Null when nothing dates it.
120
+ * calendar, with the closures in between (an index's, the venue whose days it
121
+ * follows); otherwise for an index from its own sessions; for a currency pair
122
+ * the weekday before. Null when nothing dates it.
98
123
  */
99
124
  function previousSession(quote: Quote, sessionDate: string): DatedChangeBasis | null {
100
- const venue = quoteVenue(quote);
125
+ const venue = calendarVenue(quote);
101
126
  const published = previousPublishedSession(venue, sessionDate);
102
127
  if (published) return { kind: "close", date: published.date, venue, closed: published.closed };
103
128
  const index = previousIndexSession(quote, sessionDate);
@@ -110,7 +135,8 @@ function previousSession(quote: Quote, sessionDate: string): DatedChangeBasis |
110
135
  * What the quote's move is measured from. A coin moves from its previous UTC
111
136
  * day's close, the price at 00:00 UTC, unless Gloom Cloud says it moves over
112
137
  * the last 24 hours; a perpetual always moves over 24 hours. A future's is the
113
- * settlement or trade its terms name (futuresChangeBasis). Anything else is
138
+ * settlement or trade its terms name, or the close of the trade date before
139
+ * on its venue's holiday calendar (futuresChangeBasis). Anything else is
114
140
  * the close of the session before the move's, dated by the venue's calendar;
115
141
  * a venue without one has a previous close that is left undated, never
116
142
  * guessed. Null for a quote with no move: none reported, or a listing that no
@@ -127,13 +153,27 @@ export function quoteChangeBasis(
127
153
  if (isSpotCoin(quote)) return { kind: "utc day" };
128
154
  const sessionDate = (session === "active" ? quote.changeSessionDate : regularSessionDisplayDate(quote)) ?? quoteTradingDay(quote);
129
155
  if (isFuturesInstrument(quote.symbol, quote.instrumentType)) {
130
- const basis = futuresChangeBasis(terms ?? { settlement: null }, { ...display, sessionDate });
156
+ const basis = futuresChangeBasis(terms ?? { settlement: null }, { ...display, sessionDate }, quoteVenue(quote));
131
157
  return basis ? { kind: basis.kind, date: basis.session } : { kind: "previous close" };
132
158
  }
133
159
  if (!sessionDate || !ISO_DATE.test(sessionDate)) return { kind: "previous close" };
134
160
  return previousSession(quote, sessionDate) ?? { kind: "previous close" };
135
161
  }
136
162
 
163
+ /**
164
+ * A futures quote's Settle line, paired with its Change line: the settlement
165
+ * is shown when it is of the session the move is measured from or a later one,
166
+ * and reads `--` with that session when the terms have not caught up to it
167
+ * (futuresSettleText), so the two lines never name different sessions.
168
+ */
169
+ export function quoteSettleText(
170
+ quote: Quote | null | undefined,
171
+ terms: NonNullable<QuoteChangeBasisOptions["terms"]> & Parameters<typeof futuresSettleText>[0],
172
+ ): string {
173
+ const basis = quoteChangeBasis(quote, { terms });
174
+ return futuresSettleText(terms, quote, basis && "date" in basis ? basis.date : null);
175
+ }
176
+
137
177
  /**
138
178
  * The exchange-local date of `quote.previousClose`: the session before the
139
179
  * one the quote's change is declared for (changeSessionDate), the UTC day
@@ -146,7 +186,9 @@ export function quotePreviousCloseDate(quote: Quote | null | undefined): string
146
186
  const sessionDate = quote.changeSessionDate ?? quoteTradingDay(quote);
147
187
  if (!sessionDate || !ISO_DATE.test(sessionDate)) return null;
148
188
  if (isSpotCoin(quote)) return dayBefore(sessionDate);
149
- if (isFuturesInstrument(quote.symbol, quote.instrumentType)) return futuresChangeBasis({ settlement: null }, { price: quote.price, change: 0, sessionDate })?.session ?? null;
189
+ if (isFuturesInstrument(quote.symbol, quote.instrumentType)) {
190
+ return futuresChangeBasis({ settlement: null }, { price: quote.price, change: 0, sessionDate }, quoteVenue(quote))?.session ?? null;
191
+ }
150
192
  return previousSession(quote, sessionDate)?.date ?? null;
151
193
  }
152
194
 
@@ -2,6 +2,7 @@ import type { MarketState, QuoteIndexSession } from "../../types/financials";
2
2
  import { canonicalExchange, EXCHANGE_TIME_ZONES, isUsListingExchange } from "../../utils/exchanges";
3
3
  import { hasPublishedApacCalendar, isPublishedApacClosure } from "../published-apac-sessions";
4
4
  import { hasPublishedCnCalendar, isPublishedCnClosure } from "../published-cn-sessions";
5
+ import { hasPublishedFuturesCalendar, isPublishedFuturesClosure, isPublishedFuturesVenue } from "../published-futures-sessions";
5
6
  import { hasPublishedJpxCalendar, isPublishedJpxClosure } from "../published-jpx-sessions";
6
7
  import { hasPublishedNseCalendar, isPublishedNseClosure } from "../published-nse-sessions";
7
8
  import { getPublishedUsEquityCalendarDay, getPublishedUsEquityCalendarYears, getPublishedUsEquitySession } from "../published-us-sessions";
@@ -275,7 +276,7 @@ function isPublishedClosure(exchange: string, date: string): boolean {
275
276
  if (exchange === "JPX") return isPublishedJpxClosure(date);
276
277
  if (exchange === "NSE" || exchange === "BSE") return isPublishedNseClosure(date);
277
278
  if (exchange === "SSE" || exchange === "SZSE") return isPublishedCnClosure(date);
278
- if (isPublishedApacClosure(exchange, date)) return true;
279
+ if (isPublishedApacClosure(exchange, date) || isPublishedFuturesClosure(exchange, date)) return true;
279
280
  return getPublishedUsEquityCalendarDay(exchange, date) === "closed";
280
281
  }
281
282
 
@@ -284,6 +285,16 @@ export function isTradingWeekday(exchange: string, weekday: number, weekendDays?
284
285
  return !(weekendDays ?? WEEKEND_DAYS[exchange] ?? DEFAULT_WEEKEND_DAYS).includes(weekday);
285
286
  }
286
287
 
288
+ /**
289
+ * Whether the venue trades on its local `date` (YYYY-MM-DD): a day of its
290
+ * trading week that is not a published closure. A venue without published
291
+ * closures counts every day of its trading week; an unknown venue Monday to
292
+ * Friday.
293
+ */
294
+ export function isVenueTradingDay(exchange: string | undefined, date: string): boolean {
295
+ return isLocalTradingDay(canonicalExchange(exchange), date);
296
+ }
297
+
287
298
  /** `weekendDays` replaces the venue's days off (historySourceWeekendDays). */
288
299
  function isLocalTradingDay(exchange: string, date: string, weekendDays?: readonly number[]): boolean {
289
300
  const weekday = localWeekday(date);
@@ -319,6 +330,11 @@ function regularCloseMinutes(exchange: string, date: string): number | undefined
319
330
  return (weekday == null ? undefined : WEEKDAY_CLOSE_MINUTES[exchange]?.[weekday]) ?? REGULAR_CLOSE_MINUTES[exchange];
320
331
  }
321
332
 
333
+ /** Whether the venue's regular close hour is known, so its sessions end on its own clock rather than at local midnight. */
334
+ export function hasRegularCloseHour(exchange: string | undefined): boolean {
335
+ return REGULAR_CLOSE_MINUTES[canonicalExchange(exchange)] !== undefined;
336
+ }
337
+
322
338
  /** The zone a venue's session dates are read in, or null when unknown. */
323
339
  export function sessionCalendarTimeZone(exchange: string | undefined): string | null {
324
340
  const canonical = canonicalExchange(exchange);
@@ -487,9 +503,13 @@ export function isRegularSessionTime(
487
503
  * True when the venue's full-day closures for the year of `date` are
488
504
  * published: US venues, JPX, NSE, BSE, SSE, SZSE, KRX, KOSDAQ, TWSE, TPEX,
489
505
  * HKEX, SGX, ASX and EGX. Elsewhere a local holiday reads as a trading day.
506
+ * For the futures venues (CME, CBT, NYM, CMX, NYB) a closure is a weekday
507
+ * with no trade date, and a day some of a venue's contracts settled and
508
+ * others did not is unknown.
490
509
  */
491
510
  export function hasPublishedSessionCalendar(exchange: string | undefined, date: string): boolean {
492
511
  const canonical = canonicalExchange(exchange);
512
+ if (isPublishedFuturesVenue(canonical)) return hasPublishedFuturesCalendar(canonical, date);
493
513
  const year = Number(date.slice(0, 4));
494
514
  if (canonical === "JPX") return hasPublishedJpxCalendar(year);
495
515
  if (canonical === "NSE" || canonical === "BSE") return hasPublishedNseCalendar(year);
@@ -505,17 +525,22 @@ export function hasPublishedSessionCalendar(exchange: string | undefined, date:
505
525
  * Mon 19 Oct 2026 lies between Fri 16 and Tue 20 Oct). A `date` that is no
506
526
  * session (a quote dated by when it was read, on a Saturday or a holiday) is
507
527
  * the latest session on or before it: Friday's move, read on Saturday, is
508
- * from Thursday's close. Null for round-the-clock and unknown venues, and
509
- * when a day the walk passes is in a year whose closures the venue has not
510
- * published: a holiday there would read as a session.
528
+ * from Thursday's close. With `closedDayRollsForward`, a `date` the venue had
529
+ * no session on is instead the next session's: CME Globex trades most US
530
+ * holidays and books those trades on the next trade date, so a future's move
531
+ * dated Memorial Day is Tuesday's, from Friday's settlement. Null for
532
+ * round-the-clock and unknown venues, and when a day the walk passes is in a
533
+ * year whose closures the venue has not published: a holiday there would
534
+ * read as a session.
511
535
  */
512
536
  export function previousPublishedSession(
513
537
  exchange: string | undefined,
514
538
  date: string,
539
+ { closedDayRollsForward = false }: { closedDayRollsForward?: boolean } = {},
515
540
  ): { date: string; closed: string[] } | null {
516
541
  const canonical = canonicalExchange(exchange);
517
542
  const day = isoLocalDateToUtcDay(date);
518
- if (day == null || ALWAYS_OPEN_EXCHANGES.has(canonical) || !sessionCalendarTimeZone(canonical)) return null;
543
+ if (day == null || ALWAYS_OPEN_EXCHANGES.has(canonical)) return null;
519
544
  let session: number | null = null;
520
545
  const closed: string[] = [];
521
546
  for (let offset = 0; offset <= SESSION_LOOKBACK_DAYS * 2; offset++) {
@@ -527,6 +552,10 @@ export function previousPublishedSession(
527
552
  // First the session the move is from's own day, then the one before it.
528
553
  if (session == null) {
529
554
  if (open) session = offset;
555
+ else if (offset === 0 && closedDayRollsForward) {
556
+ session = offset;
557
+ closed.push(iso);
558
+ }
530
559
  continue;
531
560
  }
532
561
  if (offset - session > SESSION_LOOKBACK_DAYS) return null;
@@ -0,0 +1,163 @@
1
+ import { calendarMonthsBefore } from "../../utils/calendar-date";
2
+ import { zonedDateKey } from "../../utils/zoned-date-time";
3
+ import { isAlwaysOpenExchange, latestRegularSessionClose, sessionCalendarTimeZone } from "./freshness";
4
+
5
+ /**
6
+ * One convention for every period return (CMP, RETURN, the futures board,
7
+ * sector and short-interest boards, the volatility curve's look-backs): a
8
+ * period runs from the close on or before the same calendar date one period
9
+ * before its end, and says so, `from Mon 21 Sep close`. A month before Wed 21
10
+ * Oct is Mon 21 Sep, so 1M is measured from Mon 21 Sep's close; a month
11
+ * before Tue 20 Oct is Sun 20 Sep, so from Fri 18 Sep's close.
12
+ */
13
+ export type ReturnPeriod = "1W" | "1M" | "3M" | "6M" | "1Y" | "3Y" | "5Y" | "YTD";
14
+
15
+ const PERIOD_MONTHS: Readonly<Record<Exclude<ReturnPeriod, "1W" | "YTD">, number>> = { "1M": 1, "3M": 3, "6M": 6, "1Y": 12, "3Y": 36, "5Y": 60 };
16
+ const PERIODS: ReadonlySet<string> = new Set<ReturnPeriod>(["1W", "1M", "3M", "6M", "1Y", "3Y", "5Y", "YTD"]);
17
+ const DAY_MS = 86_400_000;
18
+
19
+ /**
20
+ * How far before its base day a base close may be: a weekend with the longest
21
+ * closures markets take (Spring Festival put TWSE's previous session twelve
22
+ * days back in February 2026). A close further back is a gap in the history (a
23
+ * halt, a listing that started later), so the period has no base.
24
+ */
25
+ export const PERIOD_BASE_MAX_GAP_DAYS = 14;
26
+
27
+ /** What a period whose newest point is the session still trading says of that point. */
28
+ export const LATEST_INTRADAY_TEXT = "latest, intraday";
29
+
30
+ export function isReturnPeriod(value: unknown): value is ReturnPeriod {
31
+ return typeof value === "string" && PERIODS.has(value);
32
+ }
33
+
34
+ function shiftDay(day: string, days: number): string {
35
+ return new Date(Date.parse(`${day}T00:00:00Z`) + days * DAY_MS).toISOString().slice(0, 10);
36
+ }
37
+
38
+ /**
39
+ * The calendar date a period ending on `endDay` (`YYYY-MM-DD`) is measured
40
+ * from: seven days before for a week, the same day of the month before for a
41
+ * month (31 Mar's is 28 or 29 Feb), and 31 Dec of the year before for YTD.
42
+ */
43
+ export function periodBaseDay(endDay: string, period: ReturnPeriod): string {
44
+ const day = endDay.slice(0, 10);
45
+ if (period === "YTD") return `${Number(day.slice(0, 4)) - 1}-12-31`;
46
+ if (period === "1W") return shiftDay(day, -7);
47
+ return calendarMonthsBefore(new Date(`${day}T00:00:00Z`), PERIOD_MONTHS[period]).toISOString().slice(0, 10);
48
+ }
49
+
50
+ /**
51
+ * The session day of a daily or longer bar stamped at `time`, `YYYY-MM-DD`:
52
+ * a date-only stamp (UTC midnight) is its UTC date; any other is read on the
53
+ * venue's clock, as feeds stamp a JPX bar at 00:00 JST (15:00 UTC the day
54
+ * before) and a European one at local midnight. The UTC date for a venue
55
+ * that trades every day or whose sessions are unknown.
56
+ */
57
+ export function barSessionDay(time: number, venue?: string): string {
58
+ const utc = new Date(time).toISOString().slice(0, 10);
59
+ if (time % DAY_MS === 0 || !venue || isAlwaysOpenExchange(venue)) return utc;
60
+ const zone = sessionCalendarTimeZone(venue);
61
+ return zone ? zonedDateKey(time, zone) : utc;
62
+ }
63
+
64
+ /**
65
+ * The day a bar's close is from, to compare with a base day: a daily bar's own
66
+ * date, a weekly bar's (dated by the Monday its week starts) Friday, or Sunday
67
+ * at a venue that trades every day, a monthly bar's last day of the month.
68
+ * `YYYY-MM-DD`.
69
+ */
70
+ export function barCloseDay(day: string, interval?: string | null, venue?: string): string {
71
+ const date = day.slice(0, 10);
72
+ if (interval === "1wk") return shiftDay(date, venue && isAlwaysOpenExchange(venue) ? 6 : 4);
73
+ if (interval === "1mo") {
74
+ const start = new Date(`${date}T00:00:00Z`);
75
+ return new Date(Date.UTC(start.getUTCFullYear(), start.getUTCMonth() + 1, 0)).toISOString().slice(0, 10);
76
+ }
77
+ return date;
78
+ }
79
+
80
+ /**
81
+ * The index of the close a period is measured from among chronological
82
+ * `days` (each close's day, barCloseDay): the last on or before `baseDay`,
83
+ * at most `maxGapDays` before it. -1 when there is none, because the history
84
+ * starts after the base day or has a gap there.
85
+ */
86
+ export function periodBaseIndex(days: readonly string[], baseDay: string, maxGapDays = PERIOD_BASE_MAX_GAP_DAYS): number {
87
+ const earliest = Number.isFinite(maxGapDays) ? shiftDay(baseDay, -maxGapDays) : "";
88
+ for (let index = days.length - 1; index >= 0; index -= 1) {
89
+ const day = days[index]!;
90
+ if (day > baseDay) continue;
91
+ return day >= earliest ? index : -1;
92
+ }
93
+ return -1;
94
+ }
95
+
96
+ export interface PeriodClose {
97
+ /** The close's day, `YYYY-MM-DD`. */
98
+ day: string;
99
+ close: number;
100
+ }
101
+
102
+ export interface PeriodReturn {
103
+ /** The calendar date the period is measured back to (periodBaseDay). */
104
+ baseDay: string;
105
+ /** The close it is measured from: the last on or before `baseDay`. */
106
+ base: PeriodClose;
107
+ /** The price it runs to: the newest close, or the live price given. */
108
+ end: PeriodClose;
109
+ /** The return in percent. */
110
+ percent: number;
111
+ }
112
+
113
+ /**
114
+ * A period return over chronological closes, from the close on or before
115
+ * the base day (periodBaseIndex) to the newest close, or to `latest` when a
116
+ * live price is given, dated by its session day. Null without a base, an end,
117
+ * or a positive base close.
118
+ */
119
+ export function periodReturn(
120
+ closes: readonly PeriodClose[],
121
+ period: ReturnPeriod,
122
+ latest?: PeriodClose | null,
123
+ maxGapDays = PERIOD_BASE_MAX_GAP_DAYS,
124
+ ): PeriodReturn | null {
125
+ const end = latest && Number.isFinite(latest.close) ? latest : closes.at(-1);
126
+ if (!end) return null;
127
+ const baseDay = periodBaseDay(end.day, period);
128
+ const index = periodBaseIndex(closes.map((close) => close.day), baseDay, maxGapDays);
129
+ const base = index < 0 ? null : closes[index]!;
130
+ if (!base || !(base.close > 0) || !Number.isFinite(end.close)) return null;
131
+ const percent = (end.close / base.close - 1) * 100;
132
+ return Number.isFinite(percent) ? { baseDay, base, end, percent } : null;
133
+ }
134
+
135
+ const WEEKDAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"] as const;
136
+ const MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] as const;
137
+
138
+ /** `Mon 21 Sep`, with the year when it is not `currentYear`'s: `Tue 21 Oct 2025`. */
139
+ export function periodDayText(day: string, currentYear: number): string {
140
+ const date = new Date(`${day.slice(0, 10)}T00:00:00Z`);
141
+ if (!Number.isFinite(date.getTime())) return day;
142
+ const year = date.getUTCFullYear() === currentYear ? "" : ` ${date.getUTCFullYear()}`;
143
+ return `${WEEKDAYS[date.getUTCDay()]} ${date.getUTCDate()} ${MONTHS[date.getUTCMonth()]}${year}`;
144
+ }
145
+
146
+ /** `from Mon 21 Sep close`: the close a period is measured from, as its output names it. */
147
+ export function periodBaseText(day: string, now = Date.now()): string {
148
+ return `from ${periodDayText(day, new Date(now).getUTCFullYear())} close`;
149
+ }
150
+
151
+ /**
152
+ * Whether a daily bar dated `day` is the session still trading at `venue`
153
+ * at `now`: dated after the venue's latest closed session, or today's UTC
154
+ * date for a venue that never closes. False where the venue's sessions are
155
+ * unknown, which cannot tell.
156
+ */
157
+ export function isIntradayDailyBar(day: string, venue: string | undefined, now: number): boolean {
158
+ if (!venue || !Number.isFinite(now)) return false;
159
+ if (isAlwaysOpenExchange(venue)) return day.slice(0, 10) === new Date(now).toISOString().slice(0, 10);
160
+ if (!sessionCalendarTimeZone(venue)) return false;
161
+ const last = latestRegularSessionClose(venue, now);
162
+ return !!last && day.slice(0, 10) > last.date;
163
+ }
@@ -72,6 +72,19 @@ export function latestTradingSessionOpen(symbol: string | undefined, exchange: s
72
72
  return futures ? latestOpen(futures, time) : latestRegularSessionOpen(exchange, time);
73
73
  }
74
74
 
75
+ /**
76
+ * When a futures listing's sessions open, in minutes after local midnight:
77
+ * its source's minute and hour bars start on the clock, not at the open, so a
78
+ * bar built from them must not straddle it. Null for other listings, whose
79
+ * bars start at the open.
80
+ */
81
+ export function futuresSessionOpenMinute(symbol: string | undefined, exchange: string | undefined): number | null {
82
+ const session = symbol || exchange ? futuresSessionOpen(symbol ?? "", exchange) : null;
83
+ if (!session) return null;
84
+ const gcd = (left: number, right: number): number => (right === 0 ? left : gcd(right, left % right));
85
+ return session.sundayOpen === undefined ? session.open : gcd(session.open, session.sundayOpen);
86
+ }
87
+
75
88
  /**
76
89
  * The zone a listing's intraday times read in: a futures venue's own clock
77
90
  * (Chicago for CME Group, New York for ICE U.S.), otherwise the venue's. Null
@@ -1,4 +1,5 @@
1
1
  import { barLastSession } from "./bar-period";
2
+ import { barCloseDay, barSessionDay, periodBaseDay, periodBaseIndex } from "./period-return";
2
3
 
3
4
  const MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] as const;
4
5
 
@@ -29,18 +30,12 @@ export function yearToDateBaseLabel(day: string, venue: string | undefined, now
29
30
  * every bar is from the year itself (a listing that started trading in it);
30
31
  * -1 without bars.
31
32
  */
32
- export function yearToDateStartIndex(dates: readonly string[], interval?: string | null): number {
33
- const last = dates.at(-1);
33
+ export function yearToDateStartIndex(dates: readonly string[], interval?: string | null, venue?: string): number {
34
+ // A timestamped bar is read on the venue's clock (barSessionDay), a crypto week as running through Sunday.
35
+ const days = dates.map((date) => date.length > 10 && Number.isFinite(Date.parse(date)) ? barSessionDay(Date.parse(date), venue) : date.slice(0, 10));
36
+ const last = days.at(-1);
34
37
  if (!last) return -1;
35
- const yearEnd = `${Number(last.slice(0, 4)) - 1}-12-31`;
36
- const closes = (date: string) => {
37
- const day = Date.parse(`${date.slice(0, 10)}T00:00:00Z`);
38
- if (interval === "1wk") return new Date(day + 6 * 86_400_000).toISOString().slice(0, 10);
39
- if (interval === "1mo") return new Date(Date.UTC(new Date(day).getUTCFullYear(), new Date(day).getUTCMonth() + 1, 0)).toISOString().slice(0, 10);
40
- return date.slice(0, 10);
41
- };
42
- for (let index = dates.length - 1; index >= 0; index -= 1) {
43
- if (closes(dates[index]!) <= yearEnd) return index;
44
- }
45
- return 0;
38
+ // The listing's whole history counts here, however far before 31 Dec its last close of the year was.
39
+ const index = periodBaseIndex(days.map((day) => barCloseDay(day, interval, venue)), periodBaseDay(last, "YTD"), Number.POSITIVE_INFINITY);
40
+ return Math.max(0, index);
46
41
  }
@@ -1,6 +1,7 @@
1
1
  import type { PricePoint, Quote } from "../types/financials";
2
2
  import { pricePointIntegrity } from "../utils/price-history-integrity";
3
3
  import { calendarMonthsBefore } from "../utils/calendar-date";
4
+ import { barSessionDay, isReturnPeriod, periodBaseDay, periodBaseIndex } from "./market/period-return";
4
5
 
5
6
  export interface PriceReturnHorizon {
6
7
  id: string;
@@ -66,20 +67,26 @@ export function appendQuoteToPriceReturnHistory(
66
67
  ];
67
68
  }
68
69
 
69
- function subtractHorizon(date: Date, horizon: PriceReturnHorizon): Date {
70
- return calendarMonthsBefore(date, horizon.amount * (horizon.unit === "year" ? 12 : 1));
70
+ /** The calendar date a horizon ending on `day` is measured back to (periodBaseDay). */
71
+ function horizonBaseDay(day: string, horizon: PriceReturnHorizon): string {
72
+ return isReturnPeriod(horizon.id)
73
+ ? periodBaseDay(day, horizon.id)
74
+ : calendarMonthsBefore(new Date(`${day}T00:00:00Z`), horizon.amount * (horizon.unit === "year" ? 12 : 1)).toISOString().slice(0, 10);
71
75
  }
72
76
 
77
+ /** `venue` is the listing's exchange, whose clock dates its bars and quote (barSessionDay). */
73
78
  export function computePriceReturnForHorizon(
74
79
  points: readonly PricePoint[],
75
80
  horizon: PriceReturnHorizon,
81
+ venue?: string,
76
82
  ): number | null {
77
- return priceReturnForHorizon(points, horizon).value;
83
+ return priceReturnForHorizon(points, horizon, venue).value;
78
84
  }
79
85
 
80
86
  function priceReturnForHorizon(
81
87
  points: readonly PricePoint[],
82
88
  horizon: PriceReturnHorizon,
89
+ venue: string | undefined,
83
90
  ): Pick<PriceReturnField, "value" | "unavailableReason"> {
84
91
  const history = normalizePriceReturnHistory(points);
85
92
  if (history.length < 2) return {
@@ -88,16 +95,14 @@ function priceReturnForHorizon(
88
95
  };
89
96
 
90
97
  const latest = history.at(-1)!;
91
- const cutoff = subtractHorizon(latest.date, horizon);
92
- let baseline: PricePoint | null = null;
93
-
94
- for (const point of history) {
95
- if (point.date.getTime() <= cutoff.getTime()) {
96
- baseline = point;
97
- } else {
98
- break;
99
- }
100
- }
98
+ // The close on or before the same date a horizon earlier, as every period return is measured. No gap
99
+ // limit: the overview's history can be sparse, and its base is whatever close it holds on or before then.
100
+ // Each bar and the quote by its session day: a JPX bar stamped 00:00 JST, or a quote after a New York close, is not the UTC date's.
101
+ const days = history.map((point) => barSessionDay(point.date.getTime(), venue));
102
+ const baseDay = horizonBaseDay(days.at(-1)!, horizon);
103
+ const baseIndex = periodBaseIndex(days, baseDay, Number.POSITIVE_INFINITY);
104
+ const baseline = baseIndex < 0 ? null : history[baseIndex]!;
105
+ const cutoff = new Date(`${baseDay}T00:00:00Z`);
101
106
 
102
107
  if (history.some((point) => point.date >= (baseline?.date ?? cutoff) && pricePointIntegrity(point))) {
103
108
  return { value: null, unavailableReason: "inconsistent-ohlc" };
@@ -109,11 +114,12 @@ function priceReturnForHorizon(
109
114
 
110
115
  export function buildPriceReturnFields(
111
116
  points: readonly PricePoint[],
117
+ venue?: string,
112
118
  horizons: readonly PriceReturnHorizon[] = PRICE_RETURN_HORIZONS,
113
119
  ): PriceReturnField[] {
114
120
  return horizons.map((horizon) => ({
115
121
  id: horizon.id,
116
122
  label: horizon.label,
117
- ...priceReturnForHorizon(points, horizon),
123
+ ...priceReturnForHorizon(points, horizon, venue),
118
124
  }));
119
125
  }
@@ -0,0 +1,32 @@
1
+ import type { Quote } from "../types/financials";
2
+
3
+ /** What a stock perpetual's premium to its stock is worked out from: its row, as PERP and the lists read it. */
4
+ export interface PerpetualPremiumRow {
5
+ markPrice?: number | null;
6
+ priceMultiplier?: number;
7
+ underlying?: { currency: string } | null;
8
+ /**
9
+ * How Gloom Cloud matched the contract to the listing asked about: that very listing, or another of its issuer's
10
+ * (a GOOGL contract for GOOG, BRK.A's for BRK.B), whose price is not the contract's reference.
11
+ */
12
+ equityMatch?: { basis: "listing" | "issuer" } | null;
13
+ /** Gloom Cloud's figure: against the stock's stored price, or its regular close while its market is shut. */
14
+ underlyingPremium: number | null;
15
+ }
16
+
17
+ /**
18
+ * A stock perpetual's premium to its stock. While the stock's market is open, the stored price Gloom Cloud compares a
19
+ * streaming mark with is minutes old, so a live quote of the stock, where the screen has one, is the reference
20
+ * instead, when the contract tracks that very listing. Otherwise (another listing of the issuer, a quote that is
21
+ * itself a contract's, a delayed quote, a shut market, another currency) the row's own figure stands.
22
+ */
23
+ export function premiumToUnderlying(row: PerpetualPremiumRow, stock: Quote | null | undefined): number | null {
24
+ const mark = row.markPrice;
25
+ if (
26
+ mark == null || !row.underlying || row.equityMatch?.basis !== "listing" || !stock || stock.instrumentType === "PERP"
27
+ || stock.stale === true || stock.dataSource !== "live"
28
+ || stock.marketState !== "REGULAR" || stock.currency !== row.underlying.currency
29
+ || !Number.isFinite(stock.price) || stock.price <= 0
30
+ ) return row.underlyingPremium;
31
+ return mark / (row.priceMultiplier ?? 1) / stock.price - 1;
32
+ }
@@ -5,6 +5,7 @@
5
5
  // KRX, also KOSDAQ: http://open.krx.co.kr/contents/MKD/01/0110/01100305/MKD01100305.jsp
6
6
  // TWSE, whose closures TPEx shares: https://www.twse.com.tw/en/trading/holiday.html
7
7
  // (2027 not yet published; 12 and 13 Feb 2026 are clearing-only days without trading)
8
+ // and a day it closed unscheduled: 23 Oct 2026 for Typhoon Champi, announced the evening before
8
9
  // BHB closes on the dates its own daily closes skip in 2026, which match the holidays it lists
9
10
  // (some moved, as its list warns), and on National Day, 16 and 17 Dec. Its week is Sunday to Thursday.
10
11
  // HKEX: https://www.hkex.com.hk/-/media/HKEX-Market/Services/Circulars-and-Notices/Participant-and-Members-Circulars/SEHK/2025/ce_SEHK_CT_075_2025.pdf
@@ -39,7 +40,7 @@ const WIENER_BOERSE_CLOSURES: Record<number, readonly string[]> = {
39
40
  const TWSE_CLOSURES: Record<number, readonly string[]> = {
40
41
  2026: [
41
42
  "01-01", "02-12", "02-13", "02-16", "02-17", "02-18", "02-19", "02-20", "02-27",
42
- "04-03", "04-06", "05-01", "06-19", "09-25", "09-28", "10-09", "10-26", "12-25",
43
+ "04-03", "04-06", "05-01", "06-19", "09-25", "09-28", "10-09", "10-23", "10-26", "12-25",
43
44
  ],
44
45
  };
45
46
 
@@ -0,0 +1,69 @@
1
+ // Published trade-date holidays of the futures venues quotes name (weekend
2
+ // dates omitted), not a holiday-rule engine: weekdays with no trade date, on
3
+ // which nothing settles. CME Globex trades an abbreviated session on most of
4
+ // them and books it on the next trade date; ICE Futures U.S. softs do not
5
+ // trade at all. A year a venue has not published is unknown, not open.
6
+ // Checked 2026-10-21:
7
+ // CME Group, one calendar for CME, CBOT, NYMEX and COMEX:
8
+ // https://www.cmegroup.com/trading-hours.html (2026 and 2027 Globex holiday schedules and notes)
9
+ // and its clearing advisories, such as
10
+ // https://www.cmegroup.com/tools-information/holiday-calendar/files/2026/2026-memorial-day-clearing-advisory.pdf
11
+ // ("Prices will be carried forward from Prior day").
12
+ // ICE Futures U.S. softs (cocoa, coffee, cotton, FCOJ, sugar):
13
+ // https://www.ice.com/publicdocs/futures_us/exchange_notices/ICE_Futures_US_Exchange_Notice_2026_Holiday_Calendar_20260609.pdf
14
+ // https://www.ice.com/publicdocs/futures_us/exchange_notices/ICE_Futures_US_Exchange_Notice-2027_Holiday_Calendar_20260604.pdf
15
+ // Its canola closes on Canada's holidays and its financial contracts trade most US ones; Gloom
16
+ // Cloud quotes neither (RS=F and DX=F are not tickers), so NYB is its softs.
17
+ // ICE Futures Europe has no listing Gloom Cloud quotes, so no calendar.
18
+ const CME_GROUP_CLOSURES: Record<number, readonly string[]> = {
19
+ 2026: ["01-01", "01-19", "02-16", "04-03", "05-25", "06-19", "07-03", "09-07", "11-26", "12-25"],
20
+ 2027: ["01-01", "01-18", "02-15", "03-26", "05-31", "06-18", "07-05", "09-06", "11-25", "12-24"],
21
+ };
22
+
23
+ const ICE_US_SOFTS_CLOSURES: Record<number, readonly string[]> = {
24
+ 2026: ["01-01", "01-19", "02-16", "04-03", "05-25", "06-19", "07-03", "09-07", "11-26", "12-25"],
25
+ 2027: ["01-01", "01-18", "02-15", "03-26", "05-31", "06-18", "07-05", "09-06", "11-25", "12-24"],
26
+ };
27
+
28
+ /** Closures by canonical venue code. */
29
+ export const PUBLISHED_FUTURES_CLOSURES: Readonly<Record<string, Record<number, readonly string[]>>> = {
30
+ CME: CME_GROUP_CLOSURES,
31
+ CBT: CME_GROUP_CLOSURES,
32
+ NYM: CME_GROUP_CLOSURES,
33
+ CMX: CME_GROUP_CLOSURES,
34
+ NYB: ICE_US_SOFTS_CLOSURES,
35
+ };
36
+
37
+ /**
38
+ * Closures some of a venue's contracts settled on and others did not, which
39
+ * its calendar cannot say either way. Good Friday 2026 fell on a payrolls
40
+ * release: CME and CBOT settled their FX, interest rate and crypto contracts
41
+ * and rolled their equity index and agricultural ones forward from Thursday
42
+ * (https://www.cmegroup.com/tools-information/holiday-calendar/files/2026/2026-good-friday-clearing-advisory.pdf).
43
+ * NYMEX and COMEX settled nothing.
44
+ */
45
+ const PARTIAL_CLOSURES: Readonly<Record<string, readonly string[]>> = {
46
+ CME: ["2026-04-03"],
47
+ CBT: ["2026-04-03"],
48
+ };
49
+
50
+ /** Whether `exchange` (a canonical venue code) is a futures venue with a published calendar. */
51
+ export function isPublishedFuturesVenue(exchange: string): boolean {
52
+ return Object.hasOwn(PUBLISHED_FUTURES_CLOSURES, exchange);
53
+ }
54
+
55
+ /** True only for a published trade-date holiday; unpublished years are unknown, not open. */
56
+ export function isPublishedFuturesClosure(exchange: string, date: string): boolean {
57
+ if (!isPublishedFuturesVenue(exchange)) return false;
58
+ return PUBLISHED_FUTURES_CLOSURES[exchange]![Number(date.slice(0, 4))]?.includes(date.slice(5)) ?? false;
59
+ }
60
+
61
+ /**
62
+ * True when the venue's calendar says whether `date` had a trade date: its
63
+ * year is published and the day is not one some of its contracts settled and
64
+ * others did not.
65
+ */
66
+ export function hasPublishedFuturesCalendar(exchange: string, date: string): boolean {
67
+ return isPublishedFuturesVenue(exchange) && PUBLISHED_FUTURES_CLOSURES[exchange]![Number(date.slice(0, 4))] !== undefined
68
+ && !PARTIAL_CLOSURES[exchange]?.includes(date);
69
+ }
@@ -214,6 +214,10 @@ export function mergeQuoteContribution(
214
214
  tradingExchangeName: next.tradingExchangeName,
215
215
  // Whether the listing no longer trades is said with each observation: a symbol that trades again drops it.
216
216
  delisting: next.delisting,
217
+ // So is a pair's price being its bar's close, and why a stale one stands; a bar's close is no trade.
218
+ intradayBar: next.intradayBar,
219
+ staleReason: next.staleReason,
220
+ ...(next.intradayBar ? { lastTradePrice: next.lastTradePrice, lastTradeTime: next.lastTradeTime } : {}),
217
221
  regularClose: next.regularClose,
218
222
  regularCloseSessionDate: next.regularClose != null ? next.regularCloseSessionDate : undefined,
219
223
  regularChange: next.regularClose != null ? next.regularChange : undefined,
@@ -221,7 +225,7 @@ export function mergeQuoteContribution(
221
225
  };
222
226
 
223
227
  // What this observation's move is from, when not its previous close (a coin's
224
- // 24 hours, Linear: GLO-1089), is said with each one: a quote back on its
228
+ // 24 hours), is said with each one: a quote back on its
225
229
  // previous close drops an earlier "24h", and one on 24 hours drops the
226
230
  // earlier close its move no longer runs from.
227
231
  if (next.changeBasis == null) {