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
@@ -1,9 +1,13 @@
1
1
  import { scalarPointValue } from "./alignment";
2
2
  import { getTimeSeriesField } from "./field-catalog";
3
3
  import type { ChartSpec, ResolvedSeries, TimeSeriesPoint } from "./types";
4
- import type { ManualChartResolution } from "./resolution";
4
+ import { chartBarSizeSource, type ManualChartResolution } from "./resolution";
5
+ import type { TimeRange } from "./range";
5
6
  import { zonedDateTimeParts } from "../utils/zoned-date-time";
6
7
  import { barLastSession } from "../market-data/market/bar-period";
8
+ import {
9
+ barCloseDay, isIntradayDailyBar, isReturnPeriod, LATEST_INTRADAY_TEXT, periodBaseDay, periodBaseIndex, periodDayText,
10
+ } from "../market-data/market/period-return";
7
11
 
8
12
  const PRICE_COMPARISON_BASIS = "Price returns in each listing's currency; cash distributions and FX conversion excluded.";
9
13
 
@@ -15,6 +19,26 @@ export interface PriceComparison {
15
19
  notice: string;
16
20
  alignment?: "session-date" | "timestamp";
17
21
  sourceBounds?: Record<string, { start: number; end: number }>;
22
+ /**
23
+ * Each compared leg's base and end as the notice names them, `YYYY-MM-DD`:
24
+ * the day its base close is from, the day of its newest observation, and
25
+ * whether that observation is the session still trading.
26
+ */
27
+ legs?: Record<string, { baseDay: string; endDay: string; intraday: boolean }>;
28
+ /** Legs left out of the comparison, by the symbol asked for, and why; the rest still compare. */
29
+ dropped?: Array<{ seriesId: string; label: string; reason: string }>;
30
+ }
31
+
32
+ export interface PriceComparisonOptions {
33
+ /**
34
+ * The chart's untouched preset range; null for authored dates or a view
35
+ * panned or zoomed off it. A preset's legs each run to their own newest
36
+ * observation, so one that is behind does not cut the others short, and a
37
+ * calendar range (1W to 5Y) is measured from the close on or before the
38
+ * same date a range before (periodBaseDay), as RETURN is.
39
+ */
40
+ preset?: TimeRange | null;
41
+ now?: number;
18
42
  }
19
43
 
20
44
  export function observationDate(time: number, series: Pick<ResolvedSeries, "timeBasis">): string {
@@ -47,6 +71,8 @@ export function priceObservationWindowFilter(
47
71
  }
48
72
 
49
73
  export function priceComparisonBoundsForSeries(series: ResolvedSeries, comparison: PriceComparison | null) {
74
+ // A leg left out of the comparison shows nothing of it.
75
+ if (comparison?.dropped?.some((entry) => entry.seriesId === series.id)) return { start: null, end: null };
50
76
  return comparison?.sourceBounds?.[series.id] ?? comparison;
51
77
  }
52
78
 
@@ -55,6 +81,20 @@ function displayDate(time: number): string {
55
81
  return iso.endsWith("T00:00:00.000Z") ? iso.slice(0, 10) : iso.replace("T", " ").replace(".000Z", " UTC");
56
82
  }
57
83
 
84
+ /** "Mon 21 Sep close (EWJ Fri 18 Sep close)": the text most legs share, then the others by symbol. */
85
+ function legsText(entries: ReadonlyArray<{ label: string; text: string }>): string {
86
+ const groups = new Map<string, string[]>();
87
+ for (const { label, text } of entries) groups.set(text, [...groups.get(text) ?? [], label]);
88
+ const [main, ...rest] = [...groups].sort((left, right) => right[1].length - left[1].length);
89
+ if (!main) return "";
90
+ return rest.length ? `${main[0]} (${rest.map(([text, labels]) => `${labels.join(", ")} ${text}`).join("; ")})` : main[0];
91
+ }
92
+
93
+ /** A leg's venue, whose sessions say whether its newest bar is still trading. */
94
+ function legVenue(series: ResolvedSeries | undefined): string | undefined {
95
+ return series?.timeBasis?.exchange || series?.listing?.exchange || undefined;
96
+ }
97
+
58
98
  /** Comparable normalized closing-price legs share observed endpoints. Other chart meanings are unchanged. */
59
99
  export function priceComparisonSeriesIds(spec: ChartSpec): string[] | null {
60
100
  if (spec.viewport.maxPoints !== undefined) return null;
@@ -71,58 +111,163 @@ export function priceComparisonSeriesIds(spec: ChartSpec): string[] | null {
71
111
  return visible.map((entry) => entry.id);
72
112
  }
73
113
 
114
+ interface ComparedLeg {
115
+ id: string;
116
+ label: string;
117
+ entry: ResolvedSeries;
118
+ /** Every priced observation by key, chronological: a period's base can be before the window. */
119
+ keys: string[];
120
+ points: Map<string, TimeSeriesPoint>;
121
+ /** The keys inside the window. */
122
+ window: string[];
123
+ }
124
+
125
+ /**
126
+ * Where each compared leg starts and ends, and what the comparison says of it.
127
+ *
128
+ * Calendar bars compare by session date. An untouched preset range measures
129
+ * each leg from its own close on or before the same date a range before the
130
+ * newest observation of the chart (periodBaseDay), the convention RETURN
131
+ * and every period return share, and runs each leg to its own newest
132
+ * observation. Authored dates and a panned view start every leg at the first
133
+ * date they share and end them at the last. A leg with no prices, or one,
134
+ * is left out with its reason and the others still compare.
135
+ */
74
136
  export function resolvePriceComparison(
75
137
  spec: ChartSpec,
76
138
  series: readonly ResolvedSeries[],
77
139
  bounds: { start: number | null; end: number | null },
78
- resolution: ManualChartResolution | "auto" = spec.viewport.resolution,
140
+ resolution: ManualChartResolution | "auto" = spec.viewport.resolution === "auto" ? "auto" : chartBarSizeSource(spec.viewport.resolution),
79
141
  dateWindow: ChartSpec["viewport"]["dateWindow"] | null = spec.viewport.dateWindow,
142
+ options: PriceComparisonOptions = {},
80
143
  ): PriceComparison | null {
81
144
  const seriesIds = priceComparisonSeriesIds(spec);
82
145
  if (!seriesIds) return null;
146
+ const now = options.now ?? Date.now();
83
147
  const byId = new Map(series.map((entry) => [entry.id, entry]));
84
148
  const calendarBars = resolution === "1d" || resolution === "1wk" || resolution === "1mo";
85
- const observations = seriesIds.map((id) => {
86
- const entry = byId.get(id);
87
- if (!entry) return new Map<string, TimeSeriesPoint>();
149
+ const order = (left: string, right: string) => calendarBars ? left.localeCompare(right) : Number(left) - Number(right);
150
+ const symbolOf = (id: string) => {
151
+ const source = spec.series.find((entry) => entry.id === id)?.source;
152
+ return source?.kind === "security" ? source.instrument.symbol : id;
153
+ };
154
+ // A leg not loaded yet (a seed from cached history) has not failed: nothing compares until it is.
155
+ const unavailable = `${PRICE_COMPARISON_BASIS} Comparison unavailable: need two shared dates and a nonzero baseline.`;
156
+ if (seriesIds.some((id) => !byId.has(id))) return { seriesIds, start: null, end: null, notice: unavailable };
157
+ const dropped: NonNullable<PriceComparison["dropped"]> = [];
158
+ const reported = new Set<string>();
159
+ const legs: ComparedLeg[] = [];
160
+ for (const id of seriesIds) {
161
+ const entry = byId.get(id)!;
88
162
  const inWindow = priceObservationWindowFilter(entry, bounds, resolution, dateWindow);
89
- return new Map(entry.points.flatMap((point) => {
163
+ const points = new Map<string, TimeSeriesPoint>();
164
+ const window = new Set<string>();
165
+ for (const point of entry.points) {
90
166
  const time = point.date.getTime();
91
- if (!inWindow(time) || scalarPointValue(point) === null) return [];
92
- return [[calendarBars ? observationDate(time, entry) : String(time), point] as const];
93
- }));
94
- });
95
- const shared = [...observations[0]!.keys()].filter((key) => observations.every((points) => points.has(key)))
96
- .sort((a, b) => calendarBars ? a.localeCompare(b) : Number(a) - Number(b));
97
- const start = shared.find((key) => observations.every((points) => {
98
- const point = points.get(key);
99
- return point && scalarPointValue(point) !== 0;
100
- }));
101
- const end = shared.at(-1);
102
- if (start === undefined || end === undefined || start === end) return {
103
- seriesIds, start: null, end: null,
104
- notice: `${PRICE_COMPARISON_BASIS} Comparison unavailable: need two shared dates and a nonzero baseline.`,
105
- };
167
+ if (!Number.isFinite(time) || scalarPointValue(point) === null) continue;
168
+ const key = calendarBars ? observationDate(time, entry) : String(time);
169
+ points.set(key, point);
170
+ if (inWindow(time)) window.add(key);
171
+ }
172
+ const leg = { id, label: symbolOf(id), entry, keys: [...points.keys()].sort(order), points, window: [...window].sort(order) };
173
+ if (leg.window.length) legs.push(leg);
174
+ else if (entry.warning?.trim()) {
175
+ // A leg that failed to load: the chart's errors already say why.
176
+ dropped.push({ seriesId: id, label: leg.label, reason: entry.warning.trim() });
177
+ reported.add(id);
178
+ } else dropped.push({ seriesId: id, label: leg.label, reason: "no prices in this range" });
179
+ }
180
+ const nonzero = (leg: ComparedLeg, key: string) => scalarPointValue(leg.points.get(key)!) !== 0;
106
181
  // A weekly or monthly bar's close is from the last session of its period, which the notice dates it by.
107
- const period = resolution === "1wk" ? "week" : resolution === "1mo" ? "month" : null;
108
- const venue = byId.get(seriesIds[0]!)?.timeBasis?.exchange || byId.get(seriesIds[0]!)?.listing?.exchange || undefined;
109
- const sessionDay = (key: string) => (period ? barLastSession(key, period, venue, Date.now()) : null) ?? key;
110
- const sourceBounds = Object.fromEntries(seriesIds.map((id, index) => [id, {
111
- start: observations[index]!.get(start)!.date.getTime(),
112
- end: observations[index]!.get(end)!.date.getTime(),
182
+ const barPeriod = resolution === "1wk" ? "week" : resolution === "1mo" ? "month" : null;
183
+ const venue = legVenue(byId.get(seriesIds[0]!));
184
+ const sessionDay = (key: string) => (barPeriod ? barLastSession(key, barPeriod, venue, now) : null) ?? key;
185
+ const dayOf = (leg: ComparedLeg, key: string) => calendarBars ? key : observationDate(Number(key), leg.entry);
186
+ const preset = options.preset ?? null;
187
+ const period = !dateWindow && isReturnPeriod(preset) ? preset : null;
188
+ const ownEnds = preset !== null && !dateWindow;
189
+ const shared = (keys: (leg: ComparedLeg) => readonly string[]) => {
190
+ const sets = legs.map((leg) => new Set(keys(leg)));
191
+ return legs.length ? keys(legs[0]!).filter((key) => sets.every((set) => set.has(key))) : [];
192
+ };
193
+ const sharedWindow = shared((leg) => leg.window);
194
+ const sharedStart = sharedWindow.find((key) => legs.every((leg) => nonzero(leg, key)));
195
+ // The period is measured back from the chart's newest observation, by its session day.
196
+ const anchor = period && legs.length
197
+ ? legs.map((leg) => calendarBars ? sessionDay(leg.window.at(-1)!) : dayOf(leg, leg.window.at(-1)!)).sort().at(-1)!
198
+ : null;
199
+ const baseDay = anchor && period ? periodBaseDay(anchor, period) : null;
200
+ const closeDay = (leg: ComparedLeg, key: string) => calendarBars && resolution !== "1d" ? barCloseDay(key, resolution, legVenue(leg.entry)) : key;
201
+ // Intraday bars share their times, so their base is the last bar the legs share on or before the base day.
202
+ const sharedBase = baseDay && !calendarBars ? (() => {
203
+ const keys = shared((leg) => leg.keys).filter((key) => legs.every((leg) => nonzero(leg, key)));
204
+ const index = periodBaseIndex(keys.map((key) => dayOf(legs[0]!, key)), baseDay);
205
+ return index < 0 ? undefined : keys[index];
206
+ })() : undefined;
207
+ const startOf = (leg: ComparedLeg): string | undefined => {
208
+ if (!baseDay) return sharedStart;
209
+ if (!calendarBars) return sharedBase ?? sharedStart;
210
+ const index = periodBaseIndex(leg.keys.map((key) => closeDay(leg, key)), baseDay);
211
+ const base = index < 0 ? undefined : leg.keys[index];
212
+ // Without a close on or before the base day (a listing younger than the range), its first close in range.
213
+ return base !== undefined && nonzero(leg, base) ? base : leg.window.find((key) => nonzero(leg, key));
214
+ };
215
+ const sharedEnd = sharedWindow.at(-1);
216
+ // Legs that share their dates compare over two of them or not at all; a leg that runs on its own is left out alone.
217
+ const sharedSpan = sharedStart !== undefined && sharedEnd !== undefined && order(sharedStart, sharedEnd) < 0;
218
+ const compared = baseDay || ownEnds || sharedSpan ? legs.flatMap((leg) => {
219
+ const start = startOf(leg);
220
+ const end = ownEnds ? leg.window.at(-1) : sharedEnd;
221
+ if (start !== undefined && end !== undefined && order(start, end) < 0) return [{ leg, start, end }];
222
+ if (baseDay || sharedStart !== undefined) {
223
+ dropped.push({ seriesId: leg.id, label: leg.label, reason: start === undefined ? "no nonzero price to measure from in this range" : "only one price in this range" });
224
+ }
225
+ return [];
226
+ }) : [];
227
+ // "Left out: VIX; EWJ (only one price in this range)."
228
+ const droppedText = dropped.length
229
+ ? ` Left out: ${dropped.map((entry) => reported.has(entry.seriesId) ? entry.label : `${entry.label} (${entry.reason})`).join("; ")}.`
230
+ : "";
231
+ if (!compared.length) return { seriesIds, start: null, end: null, notice: unavailable, ...(dropped.length ? { dropped } : {}) };
232
+ const sourceBounds = Object.fromEntries(compared.map(({ leg, start, end }) => [leg.id, {
233
+ start: leg.points.get(start)!.date.getTime(),
234
+ end: leg.points.get(end)!.date.getTime(),
113
235
  }]));
236
+ const currentYear = new Date(now).getUTCFullYear();
237
+ const legDays = Object.fromEntries(compared.map(({ leg, start, end }) => {
238
+ const endDay = calendarBars ? sessionDay(end) : dayOf(leg, end);
239
+ // A daily bar of the session still trading, or a week or month running through it.
240
+ return [leg.id, { baseDay: calendarBars ? sessionDay(start) : dayOf(leg, start), endDay,
241
+ intraday: calendarBars && isIntradayDailyBar(endDay, legVenue(leg.entry), now) }];
242
+ }));
243
+ const span = calendarBars
244
+ ? (() => {
245
+ const from = legsText(compared.map(({ leg }) => ({ label: leg.label, text: `${periodDayText(legDays[leg.id]!.baseDay, currentYear)} close` })));
246
+ const to = legsText(compared.map(({ leg }) => ({ label: leg.label, text: legDays[leg.id]!.intraday
247
+ ? `${periodDayText(legDays[leg.id]!.endDay, currentYear)}, ${LATEST_INTRADAY_TEXT}`
248
+ : `${periodDayText(legDays[leg.id]!.endDay, currentYear)} close` })));
249
+ return `From ${from} to ${to}; market session times may differ.`;
250
+ })()
251
+ : baseDay && sharedBase !== undefined
252
+ ? `From ${periodDayText(legDays[compared[0]!.leg.id]!.baseDay, currentYear)} close to ${displayDate(Math.max(...Object.values(sourceBounds).map((range) => range.end)))}.`
253
+ : `Shared observations: ${displayDate(Math.min(...Object.values(sourceBounds).map((range) => range.start)))} to ${displayDate(Math.max(...Object.values(sourceBounds).map((range) => range.end)))}.`;
114
254
  return {
115
255
  seriesIds,
116
256
  start: Math.min(...Object.values(sourceBounds).map((range) => range.start)),
117
257
  end: Math.max(...Object.values(sourceBounds).map((range) => range.end)),
118
258
  alignment: calendarBars ? "session-date" : "timestamp",
119
259
  sourceBounds,
120
- notice: calendarBars
121
- ? `${PRICE_COMPARISON_BASIS} Shared calendar dates: ${sessionDay(start)} to ${sessionDay(end)}; market session times may differ.`
122
- : `${PRICE_COMPARISON_BASIS} Shared observations: ${displayDate(Number(start))} to ${displayDate(Number(end))}.`,
260
+ legs: legDays,
261
+ ...(dropped.length ? { dropped } : {}),
262
+ notice: `${PRICE_COMPARISON_BASIS} ${span}${droppedText}`,
123
263
  };
124
264
  }
125
265
 
266
+ /** Whether a comparison's newest point is the session still trading on any leg. */
267
+ export function priceComparisonEndsIntraday(comparison: PriceComparison | null | undefined): boolean {
268
+ return Object.values(comparison?.legs ?? {}).some((leg) => leg.intraday);
269
+ }
270
+
126
271
  /**
127
272
  * The bars a compared leg pans and zooms over: inside the view only its shared
128
273
  * dates, as the chart shows them, and every loaded bar past either edge of the
@@ -1,5 +1,13 @@
1
1
  export type TimeRange = "1D" | "1W" | "1M" | "3M" | "6M" | "1Y" | "5Y" | "ALL";
2
- export type ChartResolution = "auto" | "1m" | "5m" | "15m" | "30m" | "45m" | "1h" | "1d" | "1wk" | "1mo";
2
+ /** A bar size's unit: minutes, hours, days, weeks and months. */
3
+ export type ChartBarSizeUnit = "m" | "h" | "d" | "wk" | "mo";
4
+ /**
5
+ * A bar size a chart builds from the bars a source serves: `10m` from 5-minute
6
+ * bars, `4h` from hourly ones, `2d` from daily ones. Always in the form
7
+ * `parseChartBarSize` returns; sources and brokers never see one.
8
+ */
9
+ export type CustomChartResolution = `${number}${ChartBarSizeUnit}`;
10
+ export type ChartResolution = "auto" | "1m" | "5m" | "15m" | "30m" | "45m" | "1h" | "1d" | "1wk" | "1mo" | CustomChartResolution;
3
11
 
4
12
  export interface ChartDateWindow {
5
13
  start: Date | null;
@@ -1,8 +1,11 @@
1
- import type { ChartResolution, TimeRange } from "./range";
1
+ import type { ChartBarSizeUnit, ChartResolution, CustomChartResolution, TimeRange } from "./range";
2
2
  import { CHART_RESOLUTIONS, TIME_RANGES } from "./range";
3
3
  import { isDateWindowWithinTimeRange } from "./date-window";
4
4
 
5
- export type ManualChartResolution = Exclude<ChartResolution, "auto">;
5
+ /** The bar sizes sources and brokers serve, and the only ones they are asked for. */
6
+ export type ManualChartResolution = "1m" | "5m" | "15m" | "30m" | "45m" | "1h" | "1d" | "1wk" | "1mo";
7
+ /** Any bar size a chart draws: one a source serves, or one built from them. */
8
+ export type ChartBarSize = Exclude<ChartResolution, "auto">;
6
9
 
7
10
  export interface ChartResolutionSupport {
8
11
  resolution: ManualChartResolution;
@@ -13,7 +16,7 @@ export interface ChartResolutionSupport {
13
16
  export const TIME_RANGE_ORDER = TIME_RANGES;
14
17
  const CHART_RESOLUTION_ORDER = CHART_RESOLUTIONS;
15
18
 
16
- const CHART_RESOLUTION_LABELS: Record<ChartResolution, string> = {
19
+ const CHART_RESOLUTION_LABELS: Record<ManualChartResolution | "auto", string> = {
17
20
  auto: "AUTO",
18
21
  "1m": "1M",
19
22
  "5m": "5M",
@@ -39,7 +42,7 @@ const RANGE_PRESET_RESOLUTION: Record<TimeRange, ManualChartResolution> = {
39
42
 
40
43
  /**
41
44
  * The bar size a price history for a range is served in, unlike the chart
42
- * presets above: what `gloomberb history` and the historical prices pane get.
45
+ * presets above: what `gloom history` and the historical prices pane get.
43
46
  */
44
47
  export const RANGE_HISTORY_RESOLUTION: Readonly<Record<TimeRange, ManualChartResolution>> = {
45
48
  "1D": "5m",
@@ -137,21 +140,153 @@ function compareTimeRange(left: TimeRange, right: TimeRange): number {
137
140
  return getTimeRangeIndex(left) - getTimeRangeIndex(right);
138
141
  }
139
142
 
140
- function isChartResolution(value: unknown): value is ChartResolution {
141
- return CHART_RESOLUTION_ORDER.includes(value as ChartResolution);
143
+ export function isManualChartResolution(value: unknown): value is ManualChartResolution {
144
+ return value !== "auto" && CHART_RESOLUTION_ORDER.includes(value as ChartResolution);
142
145
  }
143
146
 
144
- function isManualChartResolution(value: unknown): value is ManualChartResolution {
145
- return value !== "auto" && CHART_RESOLUTION_ORDER.includes(value as ChartResolution);
147
+ const BAR_SIZE_UNIT_MS: Readonly<Record<ChartBarSizeUnit, number>> = {
148
+ m: 60_000,
149
+ h: 60 * 60_000,
150
+ d: 24 * 60 * 60_000,
151
+ wk: 7 * 24 * 60 * 60_000,
152
+ mo: 30 * 24 * 60 * 60_000,
153
+ };
154
+
155
+ /** The longest bar of each unit: a day of minutes or hours, a year of days, weeks or months. */
156
+ const BAR_SIZE_MAX_COUNT: Readonly<Record<ChartBarSizeUnit, number>> = { m: 1440, h: 24, d: 365, wk: 52, mo: 12 };
157
+
158
+ const BAR_SIZE_UNITS: Readonly<Record<string, ChartBarSizeUnit>> = {
159
+ m: "m", min: "m", mins: "m", minute: "m", minutes: "m",
160
+ h: "h", hr: "h", hrs: "h", hour: "h", hours: "h",
161
+ d: "d", day: "d", days: "d",
162
+ w: "wk", wk: "wk", week: "wk", weeks: "wk",
163
+ mo: "mo", mon: "mo", month: "mo", months: "mo",
164
+ };
165
+
166
+ /** A bar size in its one stored form: `90m`, `4h` (not `240m`), `2d`, `1wk`, `3mo`. */
167
+ function canonicalBarSize(count: number, unit: ChartBarSizeUnit): ChartBarSize | null {
168
+ if (!Number.isSafeInteger(count) || count <= 0) return null;
169
+ if (unit === "m" && count % 60 === 0) return canonicalBarSize(count / 60, "h");
170
+ if (count > BAR_SIZE_MAX_COUNT[unit]) return null;
171
+ return `${count}${unit}` as ChartBarSize;
172
+ }
173
+
174
+ /** A stored bar size's count and unit; null for anything that is not one. */
175
+ export function chartBarSizeParts(size: unknown): { count: number; unit: ChartBarSizeUnit } | null {
176
+ if (typeof size !== "string") return null;
177
+ const match = /^([1-9]\d{0,3})(m|h|d|wk|mo)$/.exec(size);
178
+ if (!match) return null;
179
+ const count = Number(match[1]);
180
+ const unit = match[2] as ChartBarSizeUnit;
181
+ return canonicalBarSize(count, unit) === size ? { count, unit } : null;
182
+ }
183
+
184
+ /** A stored bar size (`4h`, `2d`, `1wk`); `auto` is not one. */
185
+ function isChartBarSize(value: unknown): value is ChartBarSize {
186
+ return chartBarSizeParts(value) !== null;
187
+ }
188
+
189
+ /** Any value a chart's resolution may hold: `auto` or a stored bar size. */
190
+ export function isChartResolution(value: unknown): value is ChartResolution {
191
+ return value === "auto" || isChartBarSize(value);
192
+ }
193
+
194
+ /** A bar size the source does not serve, which the chart builds from one it does. */
195
+ export function isCustomChartResolution(value: unknown): value is CustomChartResolution {
196
+ return isChartBarSize(value) && !isManualChartResolution(value);
197
+ }
198
+
199
+ /**
200
+ * Reads a bar size as typed: `10m`, `10 min`, `4h`, `240` (minutes), `2D`,
201
+ * `3 days`, `2W`, `3mo`, `1Y`. A capital `M` alone is read as nothing: the
202
+ * chart labels months `M` and the command line minutes `1M`, so `3M` could be
203
+ * either. Null for anything else, and for bars longer than a day of minutes
204
+ * or hours, a year of days or weeks, or twelve months.
205
+ */
206
+ export function parseChartBarSize(value: unknown): ChartBarSize | null {
207
+ if (typeof value !== "string") return null;
208
+ const match = /^(\d{1,4})\s*([A-Za-z]*)$/.exec(value.trim());
209
+ if (!match) return null;
210
+ const count = Number(match[1]);
211
+ const written = match[2]!;
212
+ if (written === "") return canonicalBarSize(count, "m");
213
+ if (written === "M") return null;
214
+ const lower = written.toLowerCase();
215
+ if (lower === "y" || lower === "yr" || lower === "year" || lower === "years") return canonicalBarSize(count * 12, "mo");
216
+ const unit = BAR_SIZE_UNITS[lower];
217
+ return unit ? canonicalBarSize(count, unit) : null;
218
+ }
219
+
220
+ /** A chart resolution as typed or stored: `auto`, or any bar size `parseChartBarSize` reads. */
221
+ export function parseChartResolution(value: unknown): ChartResolution | null {
222
+ if (typeof value === "string" && value.trim().toLowerCase() === "auto") return "auto";
223
+ return parseChartBarSize(value);
224
+ }
225
+
226
+ /** How long one bar is; a month counts as 30 days. */
227
+ export function chartBarSizeStepMs(size: ChartBarSize): number {
228
+ const parts = chartBarSizeParts(size);
229
+ return parts ? parts.count * BAR_SIZE_UNIT_MS[parts.unit] : Number.NaN;
230
+ }
231
+
232
+ /** Source bar sizes that can make up minute and hour bars, longest first. */
233
+ const INTRADAY_SOURCE_RESOLUTIONS: readonly ManualChartResolution[] = ["1h", "45m", "30m", "15m", "5m", "1m"];
234
+
235
+ /**
236
+ * The bars a source serves that a bar size is built from: the longest that
237
+ * divide it (1h for 4h, 5m for 10m, 30m for 90m), among those the source
238
+ * serves when `support` says. Day, week and month multiples come from 1d, 1wk
239
+ * and 1mo bars. `openMinute`, minutes after local midnight, is when sessions
240
+ * open on a listing whose source bars start on the clock rather than at the
241
+ * open (futures): its source bars must also divide it, or a bar would straddle
242
+ * the open. A bar size the source serves is its own.
243
+ */
244
+ export function chartBarSizeSource(
245
+ size: ChartBarSize,
246
+ support: readonly ChartResolutionSupport[] = [],
247
+ openMinute: number | null = null,
248
+ ): ManualChartResolution {
249
+ if (isManualChartResolution(size)) return size;
250
+ const parts = chartBarSizeParts(size);
251
+ if (!parts) return "1d";
252
+ if (parts.unit === "d") return "1d";
253
+ if (parts.unit === "wk") return "1wk";
254
+ if (parts.unit === "mo") return "1mo";
255
+ const minutes = parts.unit === "h" ? parts.count * 60 : parts.count;
256
+ const candidates = INTRADAY_SOURCE_RESOLUTIONS.filter((resolution) => {
257
+ const step = CHART_RESOLUTION_STEP_MS[resolution] / 60_000;
258
+ return minutes % step === 0 && (openMinute === null || openMinute % step === 0);
259
+ });
260
+ const served = support.length > 0
261
+ ? candidates.find((resolution) => getSupportMaxRange(support, resolution) !== null)
262
+ : undefined;
263
+ return served ?? candidates[0] ?? "1m";
264
+ }
265
+
266
+ /**
267
+ * Every bar size the chart lists, shortest first: the ones sources serve and
268
+ * the ones most asked for that it builds from them. Any other is typed in.
269
+ */
270
+ export const CHART_BAR_SIZE_PRESETS: readonly ChartBarSize[] = [
271
+ "1m", "5m", "10m", "15m", "30m", "45m", "1h", "2h", "4h", "1d", "2d", "3d", "1wk", "1mo",
272
+ ];
273
+
274
+ /** Orders bar sizes from the shortest bar to the longest. */
275
+ export function sortChartBarSizes<T extends ChartBarSize>(sizes: readonly T[]): T[] {
276
+ return [...sizes].sort((left, right) => chartBarSizeStepMs(left) - chartBarSizeStepMs(right));
146
277
  }
147
278
 
148
- /** @deprecated Slated for removal. Check the value against `CHART_RESOLUTIONS` instead. */
279
+ /** @deprecated Slated for removal. Check the value with `isChartResolution` instead. */
149
280
  export function normalizeChartResolution(value: unknown, fallback: ChartResolution = "auto"): ChartResolution {
150
281
  return isChartResolution(value) ? value : fallback;
151
282
  }
152
283
 
284
+ const CUSTOM_BAR_UNIT_LABELS: Readonly<Record<ChartBarSizeUnit, string>> = { m: "M", h: "H", d: "D", wk: "W", mo: "MO" };
285
+
153
286
  export function getChartResolutionLabel(resolution: ChartResolution): string {
154
- return CHART_RESOLUTION_LABELS[resolution];
287
+ if (isManualChartResolution(resolution) || resolution === "auto") return CHART_RESOLUTION_LABELS[resolution];
288
+ const parts = chartBarSizeParts(resolution);
289
+ return parts ? `${parts.count}${CUSTOM_BAR_UNIT_LABELS[parts.unit]}` : String(resolution).toUpperCase();
155
290
  }
156
291
 
157
292
  export function getPresetResolution(range: TimeRange): ManualChartResolution {
@@ -199,11 +334,11 @@ export function getExpandedBufferRange(
199
334
  const nextCandidate = getNextBufferRange(bufferRange);
200
335
  const nextBufferRange = resolution === "auto"
201
336
  ? nextCandidate
202
- : clampTimeRangeToMaxRange(nextCandidate, supportMap.get(resolution) ?? bufferRange);
337
+ : clampTimeRangeToMaxRange(nextCandidate, supportMap.get(chartBarSizeSource(resolution)) ?? bufferRange);
203
338
  return isTimeRangeAtOrBelow(nextBufferRange, bufferRange) ? null : nextBufferRange;
204
339
  }
205
340
 
206
- export function sortChartResolutions<T extends ChartResolution>(resolutions: readonly T[]): T[] {
341
+ export function sortChartResolutions<T extends "auto" | ManualChartResolution>(resolutions: readonly T[]): T[] {
207
342
  return [...resolutions].sort((left, right) => (
208
343
  CHART_RESOLUTION_ORDER.indexOf(left) - CHART_RESOLUTION_ORDER.indexOf(right)
209
344
  ));
@@ -267,6 +402,31 @@ export function getSupportMaxRange(
267
402
  return normalizeChartResolutionSupport(support).find((entry) => entry.resolution === resolution)?.maxRange ?? null;
268
403
  }
269
404
 
405
+ function viewportSpanMs(range: TimeRange, dateWindow?: { start: string | Date; end: string | Date }): number {
406
+ const start = dateWindow ? new Date(dateWindow.start).getTime() : Number.NaN;
407
+ const end = dateWindow ? new Date(dateWindow.end).getTime() : Number.NaN;
408
+ return Number.isFinite(start) && Number.isFinite(end) && start <= end
409
+ ? end - start
410
+ : TIME_RANGE_APPROXIMATE_DAYS[range] * CHART_RESOLUTION_STEP_MS["1d"];
411
+ }
412
+
413
+ /**
414
+ * The bar sizes of `sizes` a chart of this range or window can draw: each
415
+ * one's source bars reach back over it, and it holds at least two bars.
416
+ */
417
+ export function getSupportedChartBarSizesForViewport<T extends ChartBarSize>(
418
+ range: TimeRange,
419
+ support: readonly ChartResolutionSupport[],
420
+ sizes: readonly T[],
421
+ dateWindow?: { start: string | Date; end: string | Date },
422
+ openMinute: number | null = null,
423
+ ): T[] {
424
+ const served = new Set<ManualChartResolution>(getSupportedChartResolutionsForViewport(range, support, dateWindow));
425
+ const span = viewportSpanMs(range, dateWindow);
426
+ return sizes.filter((size) => served.has(chartBarSizeSource(size, support, openMinute))
427
+ && span / chartBarSizeStepMs(size) >= MINIMUM_USEFUL_CHART_POINTS);
428
+ }
429
+
270
430
  export function getSupportedChartResolutionsForViewport(
271
431
  range: TimeRange,
272
432
  support: readonly ChartResolutionSupport[],
@@ -279,9 +439,7 @@ export function getSupportedChartResolutionsForViewport(
279
439
  && !!end
280
440
  && Number.isFinite(end.getTime())
281
441
  && start.getTime() <= end.getTime();
282
- const viewportSpanMs = hasValidDateWindow
283
- ? Math.max(end.getTime() - start.getTime(), 0)
284
- : TIME_RANGE_APPROXIMATE_DAYS[range] * CHART_RESOLUTION_STEP_MS["1d"];
442
+ const spanMs = viewportSpanMs(range, dateWindow);
285
443
  return normalizeChartResolutionSupport(support)
286
444
  .filter((entry) => (
287
445
  hasValidDateWindow
@@ -289,7 +447,7 @@ export function getSupportedChartResolutionsForViewport(
289
447
  : isTimeRangeAtOrBelow(range, entry.maxRange)
290
448
  ))
291
449
  .filter((entry) => (
292
- viewportSpanMs / CHART_RESOLUTION_STEP_MS[entry.resolution]
450
+ spanMs / CHART_RESOLUTION_STEP_MS[entry.resolution]
293
451
  >= MINIMUM_USEFUL_CHART_POINTS
294
452
  ))
295
453
  .map((entry) => entry.resolution);