gloomberb 0.17.6 → 0.18.0

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 (768) hide show
  1. package/README.md +2 -0
  2. package/README.zh-CN.md +2 -0
  3. package/package.json +6 -1
  4. package/patches/electrobun@1.18.1.patch +74 -0
  5. package/src/account/auth-model.ts +3 -2
  6. package/src/account/device-signin-dialog.tsx +38 -13
  7. package/src/account/device-signin.ts +2 -1
  8. package/src/account/upgrade-dialog.tsx +6 -2
  9. package/src/api-client/askg.ts +5 -3
  10. package/src/api-client/bank-figures.ts +73 -0
  11. package/src/api-client/credit-boards.ts +21 -1
  12. package/src/api-client/crypto-markets.ts +88 -1
  13. package/src/api-client/data.ts +104 -4
  14. package/src/api-client/debt-maturities.ts +18 -0
  15. package/src/api-client/equity-screener.ts +3 -0
  16. package/src/api-client/errors.ts +13 -0
  17. package/src/api-client/fund-facts.ts +72 -0
  18. package/src/api-client/futures-curve.ts +26 -3
  19. package/src/api-client/geo.ts +11 -1
  20. package/src/api-client/index.ts +25 -2
  21. package/src/api-client/insider-signals.ts +95 -11
  22. package/src/api-client/normalizers.ts +1 -0
  23. package/src/api-client/paths.ts +20 -1
  24. package/src/api-client/request.ts +11 -3
  25. package/src/api-client/research-activity.ts +15 -8
  26. package/src/api-client/socket.ts +6 -3
  27. package/src/api-client/supply-chain-graph.ts +2 -2
  28. package/src/api-client/supply-chain.ts +8 -0
  29. package/src/api-client/tape.ts +12 -0
  30. package/src/api-client/types.ts +66 -2
  31. package/src/api-client/upgrade-experiment.ts +4 -3
  32. package/src/api-client/wall-experiments.ts +5 -3
  33. package/src/api-client/wall-summary.ts +3 -1
  34. package/src/api-client/web-experiments.ts +5 -2
  35. package/src/api-client/yield-curves.ts +17 -0
  36. package/src/app/command-bar-intro.ts +38 -0
  37. package/src/app/keybindings/actions.ts +1 -1
  38. package/src/app/pane-runtime/pane-template-runtime.ts +35 -7
  39. package/src/app/pane-runtime/plugin-bindings.ts +4 -0
  40. package/src/app/pane-runtime/ticker-open-runtime.ts +4 -14
  41. package/src/app/pane-runtime/ticker-open-target.ts +31 -0
  42. package/src/app/runtime/desktop-deeplink.ts +3 -4
  43. package/src/app/runtime/plugin-bindings.ts +3 -2
  44. package/src/app/runtime/startup.ts +3 -4
  45. package/src/app/runtime/ticker-refresh.ts +13 -12
  46. package/src/app/runtime/update.ts +3 -2
  47. package/src/architecture/core-builtin-allowlist.json +0 -3
  48. package/src/architecture/silent-catch-allowlist.json +3 -0
  49. package/src/architecture/ui-literals-allowlist.json +186 -0
  50. package/src/architecture/ui-tokens-allowlist.json +40 -0
  51. package/src/ask-gloom/pane-context.ts +3 -1
  52. package/src/brokers/signed-in/catalog.ts +2 -1
  53. package/src/brokers/signed-in/client.ts +7 -2
  54. package/src/brokers/signed-in/sign-in-dialog.tsx +120 -26
  55. package/src/brokers/signed-in/sign-in.ts +22 -20
  56. package/src/brokers/sync-broker-instance.ts +2 -1
  57. package/src/capabilities/chart-series.ts +2 -0
  58. package/src/capabilities/registry.ts +1 -3
  59. package/src/cli/bank-section.ts +147 -0
  60. package/src/cli/base-converter.ts +5 -2
  61. package/src/cli/board-coins.ts +70 -0
  62. package/src/cli/commands/fred-series.ts +90 -0
  63. package/src/cli/commands/market.ts +340 -69
  64. package/src/cli/commands/news-search.ts +35 -2
  65. package/src/cli/commands/options-chain.ts +7 -5
  66. package/src/cli/commands/options-leaps.ts +3 -3
  67. package/src/cli/commands/overview.ts +78 -29
  68. package/src/cli/commands/plugins.ts +1 -0
  69. package/src/cli/commands/search.ts +87 -24
  70. package/src/cli/commands/system.ts +5 -2
  71. package/src/cli/commands/ticker.ts +337 -60
  72. package/src/cli/context.ts +2 -1
  73. package/src/cli/desktop-pane-shot.ts +11 -3
  74. package/src/cli/earnings-calendar.ts +2 -1
  75. package/src/cli/errors.ts +10 -0
  76. package/src/cli/export-source.ts +18 -3
  77. package/src/cli/glossary.ts +196 -14
  78. package/src/cli/history-rows.ts +60 -9
  79. package/src/cli/index-roots.ts +26 -0
  80. package/src/cli/index.ts +34 -9
  81. package/src/cli/known-gaps.ts +156 -22
  82. package/src/cli/listing-arg.ts +156 -12
  83. package/src/cli/listing-suggestion.ts +4 -2
  84. package/src/cli/name-entries.ts +76 -0
  85. package/src/cli/not-a-ticker.ts +15 -6
  86. package/src/cli/pane-functions/access-gate.ts +22 -0
  87. package/src/cli/pane-functions/capabilities.ts +62 -4
  88. package/src/cli/pane-functions/catalog.ts +94 -39
  89. package/src/cli/pane-functions/data.ts +6 -5
  90. package/src/cli/pane-functions/discovery.ts +1 -1
  91. package/src/cli/pane-functions/dom.ts +3 -3
  92. package/src/cli/pane-functions/freshness.ts +49 -8
  93. package/src/cli/pane-functions/function-help.ts +13 -10
  94. package/src/cli/pane-functions/headless.ts +177 -42
  95. package/src/cli/pane-functions/index.ts +64 -8
  96. package/src/cli/pane-functions/options.ts +17 -3
  97. package/src/cli/pane-functions/report-notices.ts +17 -3
  98. package/src/cli/pane-functions/resolver.ts +48 -13
  99. package/src/cli/pane-functions/screenshot.ts +124 -23
  100. package/src/cli/pane-functions/shot-options.ts +68 -0
  101. package/src/cli/perpetual-contract.ts +3 -1
  102. package/src/cli/report-tables.ts +10 -2
  103. package/src/cli/staged-tickers.ts +5 -0
  104. package/src/cli/statement-filings.ts +261 -0
  105. package/src/cli/symbol-args.ts +47 -8
  106. package/src/cli/symbol-list.ts +9 -2
  107. package/src/cli/symbol-rows.ts +269 -29
  108. package/src/cli/ticker-resolution.ts +148 -34
  109. package/src/cli/treasury-yields.ts +86 -0
  110. package/src/cli/types.ts +3 -0
  111. package/src/cli/uncovered-instrument.ts +20 -0
  112. package/src/components/chart/composite/axis-overlays.tsx +16 -9
  113. package/src/components/chart/composite/composite-chart.tsx +85 -6
  114. package/src/components/chart/composite/downsample.ts +19 -3
  115. package/src/components/chart/composite/format.ts +3 -0
  116. package/src/components/chart/composite/legend.tsx +155 -76
  117. package/src/components/chart/composite/panel-bitmap.ts +8 -2
  118. package/src/components/chart/composite/panel-surface.tsx +3 -3
  119. package/src/components/chart/composite/toolbar.tsx +12 -7
  120. package/src/components/chart/composite/types.ts +6 -0
  121. package/src/components/chart/composite/use-composite-chart-keyboard.ts +28 -1
  122. package/src/components/chart/curve/curve-surface.tsx +1 -1
  123. package/src/components/chart/static/series.ts +39 -0
  124. package/src/components/chart/static/trail-chart-surface.tsx +2 -1
  125. package/src/components/command-bar/commands/collection-list.ts +45 -15
  126. package/src/components/command-bar/commands/collection.ts +10 -3
  127. package/src/components/command-bar/commands/registry.ts +2 -2
  128. package/src/components/command-bar/list/badge.ts +4 -3
  129. package/src/components/command-bar/list/model.ts +5 -0
  130. package/src/components/command-bar/list/view.tsx +1 -1
  131. package/src/components/command-bar/panel/index.tsx +19 -8
  132. package/src/components/command-bar/panel/native-surface.ts +6 -4
  133. package/src/components/command-bar/panel/prompt-example.ts +22 -0
  134. package/src/components/command-bar/routes/root/provider-search.ts +3 -9
  135. package/src/components/command-bar/routes/root/results.ts +13 -0
  136. package/src/components/command-bar/routes/root/start-here.ts +90 -0
  137. package/src/components/command-bar/routes/ticker-search/results.ts +42 -3
  138. package/src/components/command-bar/routes/ticker-search/route.ts +3 -10
  139. package/src/components/command-bar/theme-picker.tsx +3 -1
  140. package/src/components/command-bar/workflow/builtin.ts +5 -1
  141. package/src/components/command-bar/workflow/collection-actions.ts +21 -12
  142. package/src/components/command-bar/workflow/ops.ts +21 -1
  143. package/src/{plugins/builtin/portfolio-list/command-bar.ts → components/command-bar/workflow/portfolio-position.ts} +42 -9
  144. package/src/components/command-bar/workflow/tickers.ts +6 -4
  145. package/src/components/feedback-dialog.tsx +1 -1
  146. package/src/components/form-modal/broker-step.tsx +7 -63
  147. package/src/components/form-modal/content.tsx +7 -2
  148. package/src/components/form-modal/field-row.tsx +6 -8
  149. package/src/components/form-modal/host.tsx +3 -3
  150. package/src/components/form-modal/model.ts +3 -0
  151. package/src/components/form-modal/routes.ts +17 -2
  152. package/src/components/index.ts +6 -6
  153. package/src/components/input-search-bar.tsx +43 -6
  154. package/src/components/layout/detached-pane-shell.tsx +0 -1
  155. package/src/components/layout/floating-pane.tsx +0 -1
  156. package/src/components/layout/header.tsx +8 -7
  157. package/src/components/layout/pane/footer/index.tsx +7 -4
  158. package/src/components/layout/pane/footer/model.ts +28 -2
  159. package/src/components/layout/pane/header.tsx +9 -19
  160. package/src/components/layout/pane/index.tsx +0 -1
  161. package/src/components/layout/pane/instrument-coverage-gate.tsx +57 -0
  162. package/src/components/layout/pane/pane-tabs.tsx +4 -3
  163. package/src/components/layout/pane/sizing.ts +9 -0
  164. package/src/components/layout/pane/ticker-fate-gate.tsx +8 -2
  165. package/src/components/layout/shell/pane/capture.ts +44 -20
  166. package/src/components/layout/status-bar.tsx +3 -6
  167. package/src/components/markdown-text.tsx +17 -2
  168. package/src/components/market-board/index.tsx +19 -8
  169. package/src/components/metric-treemap/heat-surface.tsx +2 -7
  170. package/src/components/onboarding/account-step/qr-panel.tsx +5 -2
  171. package/src/components/onboarding/onboarding-frame.tsx +24 -21
  172. package/src/components/onboarding/portfolio-step/positions-panel.tsx +20 -10
  173. package/src/components/onboarding/wizard-positions.ts +40 -11
  174. package/src/components/pane-settings-dialog/desktop.tsx +12 -50
  175. package/src/components/pane-settings-dialog/field-dialogs.tsx +1 -1
  176. package/src/components/price-performance.tsx +18 -2
  177. package/src/components/reader/article-reader.tsx +11 -10
  178. package/src/components/reader/detail-reader.tsx +9 -5
  179. package/src/components/reader/reader-text.tsx +51 -24
  180. package/src/components/sign-in-code-panel.tsx +129 -75
  181. package/src/components/ticker/badge/index.tsx +2 -1
  182. package/src/components/ui/action-row.tsx +5 -2
  183. package/src/components/ui/audio-player.tsx +70 -0
  184. package/src/components/ui/card.tsx +75 -0
  185. package/src/components/ui/data-table/index.tsx +4 -2
  186. package/src/components/ui/data-table/types.ts +11 -0
  187. package/src/components/ui/detail-scroll-body.tsx +1 -1
  188. package/src/components/ui/dialog-actions.tsx +1 -21
  189. package/src/components/ui/display.tsx +13 -5
  190. package/src/components/ui/external-link.tsx +4 -2
  191. package/src/components/ui/fields.tsx +12 -0
  192. package/src/components/ui/figure.tsx +5 -3
  193. package/src/components/ui/frame.tsx +40 -6
  194. package/src/components/ui/icon.tsx +4 -0
  195. package/src/components/ui/index.ts +4 -1
  196. package/src/components/ui/list-view.tsx +8 -0
  197. package/src/components/ui/prose.tsx +97 -25
  198. package/src/components/ui/query-bar-keys.tsx +3 -1
  199. package/src/components/ui/query-bar.tsx +6 -0
  200. package/src/components/ui/quote.ts +42 -0
  201. package/src/components/ui/range-track.tsx +15 -2
  202. package/src/components/ui/reveal-in-scroll-box.ts +21 -3
  203. package/src/components/ui/select-button.tsx +38 -3
  204. package/src/components/ui/status.tsx +73 -4
  205. package/src/components/ui/table-layout.ts +20 -0
  206. package/src/components/use-pinned-moment.ts +19 -0
  207. package/src/core/app-runtime.ts +2 -2
  208. package/src/core/state/app/instrument.ts +18 -1
  209. package/src/core/state/app/layout.ts +6 -0
  210. package/src/core/state/app/state.ts +14 -2
  211. package/src/data/cached-query.ts +1 -1
  212. package/src/data/config/chart-settings.ts +3 -1
  213. package/src/data/config/home.ts +4 -1
  214. package/src/data/config/store/node.ts +9 -4
  215. package/src/data/config/store/normalize.ts +9 -0
  216. package/src/data/json-storage.ts +6 -3
  217. package/src/data/json-ticker-repository.ts +3 -1
  218. package/src/data/plugin-cache.ts +5 -1
  219. package/src/data/sqlite/json.ts +3 -1
  220. package/src/data/ticker-repository.ts +5 -2
  221. package/src/feedback/diagnostics.ts +2 -6
  222. package/src/i18n/es.ts +86 -6
  223. package/src/i18n/index.ts +3 -9
  224. package/src/i18n/ja.ts +86 -6
  225. package/src/i18n/ko.ts +86 -6
  226. package/src/i18n/zh-cn.ts +86 -6
  227. package/src/i18n/zh-tw.ts +86 -6
  228. package/src/layout-marketplace/gallery-desktop.tsx +8 -4
  229. package/src/market-data/bars-per-year.ts +43 -0
  230. package/src/market-data/bond-funds.ts +85 -0
  231. package/src/market-data/coordinator/auxiliary.ts +5 -2
  232. package/src/market-data/coordinator/index.ts +6 -5
  233. package/src/market-data/futures-contract.ts +102 -5
  234. package/src/market-data/hooks.tsx +20 -11
  235. package/src/market-data/market/bar-period.ts +36 -0
  236. package/src/market-data/market/format.ts +5 -13
  237. package/src/market-data/market/freshness.ts +1 -3
  238. package/src/market-data/market/index-level.ts +51 -0
  239. package/src/market-data/model-dividend-yield.ts +57 -16
  240. package/src/market-data/quotes/live-valuation.ts +48 -2
  241. package/src/market-data/realized-volatility.ts +16 -7
  242. package/src/market-data/tax-equivalent.ts +344 -0
  243. package/src/news/aggregator.ts +4 -2
  244. package/src/notifications/notification-log.ts +5 -3
  245. package/src/plugins/auto-update-node.ts +1 -0
  246. package/src/plugins/builtin/account-management/footer.ts +1 -1
  247. package/src/plugins/builtin/account-management/keyboard.ts +3 -0
  248. package/src/plugins/builtin/account-management/model.ts +1 -0
  249. package/src/plugins/builtin/account-management/pane.tsx +71 -19
  250. package/src/plugins/builtin/account-management/trial-cancel.ts +40 -0
  251. package/src/plugins/builtin/alerts/cli.ts +7 -18
  252. package/src/plugins/builtin/alerts/constants.ts +8 -0
  253. package/src/plugins/builtin/alerts/event-rows.ts +16 -0
  254. package/src/plugins/builtin/alerts/events-pane.tsx +2 -14
  255. package/src/plugins/builtin/alerts/headless.ts +182 -0
  256. package/src/plugins/builtin/alerts/index.tsx +3 -0
  257. package/src/plugins/builtin/alerts/pane.tsx +1 -7
  258. package/src/plugins/builtin/alerts/storage.ts +17 -1
  259. package/src/plugins/builtin/analytics/index.tsx +6 -1
  260. package/src/plugins/builtin/analytics/metrics.ts +47 -9
  261. package/src/plugins/builtin/analytics/risk-headless.ts +14 -2
  262. package/src/plugins/builtin/analytics/risk-math.ts +83 -0
  263. package/src/plugins/builtin/analytics/risk-model.ts +97 -4
  264. package/src/plugins/builtin/analytics/risk-pane.tsx +11 -6
  265. package/src/plugins/builtin/analytics/sector-model.ts +14 -3
  266. package/src/plugins/builtin/awards/headless.ts +6 -5
  267. package/src/plugins/builtin/awards/index.tsx +1 -1
  268. package/src/plugins/builtin/backtest/client.ts +38 -8
  269. package/src/plugins/builtin/backtest/engine.ts +25 -13
  270. package/src/plugins/builtin/backtest/export.ts +27 -0
  271. package/src/plugins/builtin/backtest/format.ts +19 -3
  272. package/src/plugins/builtin/backtest/headless.ts +42 -28
  273. package/src/plugins/builtin/backtest/index.tsx +3 -0
  274. package/src/plugins/builtin/backtest/pane.tsx +39 -10
  275. package/src/plugins/builtin/backtest/report.ts +160 -0
  276. package/src/plugins/builtin/backtest/rules.ts +2 -0
  277. package/src/plugins/builtin/backtest/window.ts +112 -0
  278. package/src/plugins/builtin/bond-calculator/headless.ts +3 -2
  279. package/src/plugins/builtin/broker-manager/add-flow.tsx +4 -4
  280. package/src/plugins/builtin/catalysts/headless.ts +24 -13
  281. package/src/plugins/builtin/catalysts/index.tsx +4 -2
  282. package/src/plugins/builtin/catalysts/model.ts +18 -1
  283. package/src/plugins/builtin/catalysts/pane.tsx +2 -2
  284. package/src/plugins/builtin/cds/client.ts +28 -5
  285. package/src/plugins/builtin/cds/headless.ts +183 -31
  286. package/src/plugins/builtin/cds/index.tsx +1 -1
  287. package/src/plugins/builtin/cds/model.ts +229 -53
  288. package/src/plugins/builtin/cds/pane.tsx +82 -26
  289. package/src/plugins/builtin/central-bank-rates/headless.ts +1 -1
  290. package/src/plugins/builtin/chart-composer/catalog-inventory.ts +39 -1
  291. package/src/plugins/builtin/chart-composer/chart-spec-edit.ts +77 -0
  292. package/src/plugins/builtin/chart-composer/chart-spec.ts +15 -0
  293. package/src/plugins/builtin/chart-composer/data-catalog-pane.tsx +22 -2
  294. package/src/plugins/builtin/chart-composer/editor/desktop-view.tsx +2 -2
  295. package/src/plugins/builtin/chart-composer/headless-schema.ts +10 -2
  296. package/src/plugins/builtin/chart-composer/headless.ts +99 -21
  297. package/src/plugins/builtin/chart-composer/index.tsx +70 -13
  298. package/src/plugins/builtin/chart-composer/pane.tsx +65 -15
  299. package/src/plugins/builtin/chart-composer/presets.ts +79 -11
  300. package/src/plugins/builtin/chart-composer/series-catalog.ts +50 -14
  301. package/src/plugins/builtin/chart-composer/series-expression.ts +9 -7
  302. package/src/plugins/builtin/chart-composer/series-listings.ts +178 -0
  303. package/src/plugins/builtin/chart-composer/session-range.ts +87 -0
  304. package/src/plugins/builtin/chat/attachments/desktop.tsx +4 -1
  305. package/src/plugins/builtin/chat/content/composer-runtime.ts +49 -14
  306. package/src/plugins/builtin/chat/content/composer.tsx +22 -1
  307. package/src/plugins/builtin/chat/content/index.tsx +35 -5
  308. package/src/plugins/builtin/chat/content/layout-metrics.ts +3 -0
  309. package/src/plugins/builtin/chat/content/shortcuts.ts +32 -13
  310. package/src/plugins/builtin/chat/content/snapshot.ts +29 -6
  311. package/src/plugins/builtin/chat/ghost-user.ts +11 -3
  312. package/src/plugins/builtin/chat/layout.ts +2 -0
  313. package/src/plugins/builtin/chat/message/desktop.tsx +13 -5
  314. package/src/plugins/builtin/chat/message/header.tsx +26 -4
  315. package/src/plugins/builtin/chat/message/pane-chip.tsx +131 -35
  316. package/src/plugins/builtin/chat/message/render-state.ts +28 -1
  317. package/src/plugins/builtin/chat/message/terminal.tsx +9 -3
  318. package/src/plugins/builtin/chat/pane-links/composer.ts +87 -0
  319. package/src/plugins/builtin/chat/pane-links/model.ts +1 -1
  320. package/src/plugins/builtin/chat/share/flow.tsx +9 -73
  321. package/src/plugins/builtin/cloud/askg/controller.ts +5 -3
  322. package/src/plugins/builtin/cloud/askg/executor.ts +3 -1
  323. package/src/plugins/builtin/cloud/askg/lock-note.ts +16 -0
  324. package/src/plugins/builtin/cloud/askg/pane.tsx +6 -2
  325. package/src/plugins/builtin/cloud/auth-actions.tsx +4 -2
  326. package/src/plugins/builtin/cloud/company-picker.tsx +21 -26
  327. package/src/plugins/builtin/cloud/mcp-connect/dialog.tsx +5 -3
  328. package/src/plugins/builtin/cloud/plugin.tsx +2 -0
  329. package/src/plugins/builtin/cloud/team/module.tsx +5 -1
  330. package/src/plugins/builtin/cloud/team/pane.tsx +11 -4
  331. package/src/plugins/builtin/cloud/team/views.ts +11 -4
  332. package/src/plugins/builtin/cloud/terminal-relay/engine.ts +9 -4
  333. package/src/plugins/builtin/cloud/terminal-relay/prompts.tsx +3 -2
  334. package/src/plugins/builtin/cloud/thesis/detail.tsx +2 -1
  335. package/src/plugins/builtin/cloud/thesis/exposure.ts +3 -0
  336. package/src/plugins/builtin/cloud/thesis/prompts.tsx +3 -2
  337. package/src/plugins/builtin/cloud/thesis/ticker-tab.tsx +2 -1
  338. package/src/plugins/builtin/cloud/trial-offer-status-widget.tsx +2 -1
  339. package/src/plugins/builtin/cloud/verification-status-widget.tsx +2 -1
  340. package/src/plugins/builtin/commodities-energy/index.tsx +8 -5
  341. package/src/plugins/builtin/commodities-energy/view-state.ts +11 -0
  342. package/src/plugins/builtin/company-attention/headless.ts +15 -7
  343. package/src/plugins/builtin/company-attention/index.tsx +1 -1
  344. package/src/plugins/builtin/company-attention/model.ts +49 -4
  345. package/src/plugins/builtin/company-attention/pane.tsx +11 -9
  346. package/src/plugins/builtin/company-kpis/headless.ts +4 -3
  347. package/src/plugins/builtin/company-kpis/index.tsx +2 -2
  348. package/src/plugins/builtin/company-kpis/pane.tsx +9 -3
  349. package/src/plugins/builtin/congress-trades/headless.ts +23 -2
  350. package/src/plugins/builtin/correlation/relationship/pane.tsx +18 -46
  351. package/src/plugins/builtin/cot/headless.ts +5 -2
  352. package/src/plugins/builtin/credit-boards/cdx-pane.tsx +41 -13
  353. package/src/plugins/builtin/credit-boards/client.ts +9 -2
  354. package/src/plugins/builtin/credit-boards/headless.ts +93 -27
  355. package/src/plugins/builtin/credit-boards/index.tsx +15 -4
  356. package/src/plugins/builtin/credit-boards/model.ts +105 -6
  357. package/src/plugins/builtin/credit-boards/sovr-pane.tsx +14 -3
  358. package/src/plugins/builtin/credit-documents/detail.tsx +2 -1
  359. package/src/plugins/builtin/credit-documents/index.tsx +3 -0
  360. package/src/plugins/builtin/credit-documents/model.ts +3 -10
  361. package/src/plugins/builtin/crypto-board/client.ts +152 -2
  362. package/src/plugins/builtin/crypto-board/headless.ts +138 -19
  363. package/src/plugins/builtin/crypto-board/index.tsx +5 -3
  364. package/src/plugins/builtin/crypto-board/model.ts +210 -12
  365. package/src/plugins/builtin/crypto-board/pane.tsx +148 -9
  366. package/src/plugins/builtin/crypto-board/series.ts +52 -1
  367. package/src/plugins/builtin/crypto-board/supply.ts +123 -0
  368. package/src/plugins/builtin/debt-maturities/client.ts +54 -1
  369. package/src/plugins/builtin/debt-maturities/headless.ts +27 -3
  370. package/src/plugins/builtin/debt-maturities/index.tsx +2 -0
  371. package/src/plugins/builtin/debt-maturities/model.ts +58 -13
  372. package/src/plugins/builtin/debt-maturities/pane.tsx +47 -7
  373. package/src/plugins/builtin/dividend-yield/client.ts +42 -36
  374. package/src/plugins/builtin/dividend-yield/headless.ts +113 -18
  375. package/src/plugins/builtin/dividend-yield/index.tsx +5 -2
  376. package/src/plugins/builtin/dividend-yield/pane.tsx +37 -13
  377. package/src/plugins/builtin/dividend-yield/provider-client.ts +7 -3
  378. package/src/plugins/builtin/dividend-yield/ranking.ts +187 -0
  379. package/src/plugins/builtin/dividend-yield/reference-price.ts +28 -5
  380. package/src/plugins/builtin/dividend-yield/types.ts +6 -1
  381. package/src/plugins/builtin/dividend-yield/view.ts +1 -1
  382. package/src/plugins/builtin/docs/blocks.tsx +54 -8
  383. package/src/plugins/builtin/docs/pane.tsx +8 -13
  384. package/src/plugins/builtin/earnings/headless.ts +3 -2
  385. package/src/plugins/builtin/earnings-calls/data.ts +51 -0
  386. package/src/plugins/builtin/earnings-calls/headless.ts +7 -0
  387. package/src/plugins/builtin/earnings-calls/index.tsx +1 -0
  388. package/src/plugins/builtin/earnings-calls/model.ts +97 -0
  389. package/src/plugins/builtin/earnings-calls/pane.tsx +107 -7
  390. package/src/plugins/builtin/earnings-calls/transcript-view.tsx +140 -22
  391. package/src/plugins/builtin/earnings-calls/use-call-playback.ts +194 -0
  392. package/src/plugins/builtin/econ/calendar-model.ts +22 -0
  393. package/src/plugins/builtin/econ/calendar-source.ts +35 -0
  394. package/src/plugins/builtin/econ/index.tsx +40 -8
  395. package/src/plugins/builtin/econ-statistics/defs.ts +7 -0
  396. package/src/plugins/builtin/econ-statistics/detail.tsx +8 -1
  397. package/src/plugins/builtin/econ-statistics/headless.ts +26 -5
  398. package/src/plugins/builtin/econ-statistics/pane.tsx +4 -2
  399. package/src/plugins/builtin/econ-statistics/stats.ts +10 -0
  400. package/src/plugins/builtin/econ-statistics/view.ts +19 -0
  401. package/src/plugins/builtin/equity-screener/client.ts +1 -1
  402. package/src/plugins/builtin/equity-screener/model.ts +46 -4
  403. package/src/plugins/builtin/equity-screener/pane.tsx +3 -0
  404. package/src/plugins/builtin/estimate-revisions/client.ts +32 -22
  405. package/src/plugins/builtin/estimate-revisions/headless.ts +1 -0
  406. package/src/plugins/builtin/estimate-revisions/index.tsx +1 -0
  407. package/src/plugins/builtin/estimate-revisions/pane.tsx +5 -3
  408. package/src/plugins/builtin/executives/index.tsx +1 -0
  409. package/src/plugins/builtin/exposure/editor.tsx +3 -3
  410. package/src/plugins/builtin/fear-greed/index.tsx +9 -0
  411. package/src/plugins/builtin/filing-events/index.tsx +1 -0
  412. package/src/plugins/builtin/futures/index.tsx +2 -2
  413. package/src/plugins/builtin/futures/model.ts +34 -21
  414. package/src/plugins/builtin/futures/table.tsx +1 -1
  415. package/src/plugins/builtin/futures/use-board-terms.ts +2 -2
  416. package/src/plugins/builtin/futures-curve/headless.ts +4 -2
  417. package/src/plugins/builtin/futures-curve/model.ts +5 -7
  418. package/src/plugins/builtin/help/index.tsx +55 -8
  419. package/src/plugins/builtin/help/shortcut-table.tsx +15 -2
  420. package/src/plugins/builtin/holders/headless.ts +12 -0
  421. package/src/plugins/builtin/insider/headless.ts +311 -41
  422. package/src/plugins/builtin/insider/index.tsx +280 -106
  423. package/src/plugins/builtin/insider/insiders.tsx +224 -0
  424. package/src/plugins/builtin/insider/signals-cells.tsx +52 -0
  425. package/src/plugins/builtin/insider/signals-client.ts +135 -11
  426. package/src/plugins/builtin/insider/signals-model.ts +628 -56
  427. package/src/plugins/builtin/insider/signals.tsx +283 -83
  428. package/src/plugins/builtin/ipo-calendar/headless.ts +17 -7
  429. package/src/plugins/builtin/ipo-calendar/index.tsx +23 -3
  430. package/src/plugins/builtin/ipo-calendar/model.ts +84 -36
  431. package/src/plugins/builtin/ipo-calendar/pane.tsx +20 -8
  432. package/src/plugins/builtin/iv-history/headless.ts +2 -0
  433. package/src/plugins/builtin/jobs/headless.ts +1 -0
  434. package/src/plugins/builtin/jobs/index.tsx +1 -0
  435. package/src/plugins/builtin/jodi/headless.ts +2 -0
  436. package/src/plugins/builtin/kelly-sizer/pane.tsx +1 -1
  437. package/src/plugins/builtin/kelly-sizer/portfolio.ts +1 -1
  438. package/src/plugins/builtin/market-heatmap/headless.ts +1 -0
  439. package/src/plugins/builtin/market-heatmap/portfolio.ts +3 -1
  440. package/src/plugins/builtin/market-valuation/pane.tsx +1 -1
  441. package/src/plugins/builtin/market-valuation/zone-scale/desktop.tsx +31 -57
  442. package/src/plugins/builtin/mna/distress/headless.ts +2 -1
  443. package/src/plugins/builtin/mna/headless.ts +14 -2
  444. package/src/plugins/builtin/mna/index.tsx +1 -0
  445. package/src/plugins/builtin/news/headless.ts +4 -0
  446. package/src/plugins/builtin/news/wire/news/footer.ts +5 -3
  447. package/src/plugins/builtin/news/wire/news/table.tsx +57 -11
  448. package/src/plugins/builtin/notes/cli.ts +8 -4
  449. package/src/plugins/builtin/notes/files.ts +66 -20
  450. package/src/plugins/builtin/notes/migration.ts +18 -6
  451. package/src/plugins/builtin/notes/owner.tsx +3 -2
  452. package/src/plugins/builtin/notes/quick-notes-pane.tsx +3 -2
  453. package/src/plugins/builtin/options-scenario/client.ts +7 -4
  454. package/src/plugins/builtin/options-scenario/headless.ts +5 -3
  455. package/src/plugins/builtin/pe-band/index.tsx +1 -1
  456. package/src/plugins/builtin/pe-band/model.ts +1 -15
  457. package/src/plugins/builtin/perps/headless.ts +30 -13
  458. package/src/plugins/builtin/perps/model.ts +45 -3
  459. package/src/plugins/builtin/perps/pane.tsx +7 -7
  460. package/src/plugins/builtin/portfolio-list/cell-version.ts +10 -4
  461. package/src/plugins/builtin/portfolio-list/cli/bulk-symbols.ts +128 -14
  462. package/src/plugins/builtin/portfolio-list/cli/portfolio-command.ts +108 -46
  463. package/src/plugins/builtin/portfolio-list/cli/render.ts +368 -45
  464. package/src/plugins/builtin/portfolio-list/cli/shared.ts +8 -2
  465. package/src/plugins/builtin/portfolio-list/cli/watchlist-command.ts +24 -34
  466. package/src/plugins/builtin/portfolio-list/grid.tsx +3 -1
  467. package/src/plugins/builtin/portfolio-list/headless.ts +151 -29
  468. package/src/plugins/builtin/portfolio-list/income.ts +296 -0
  469. package/src/plugins/builtin/portfolio-list/metrics.ts +2 -2
  470. package/src/plugins/builtin/portfolio-list/pane/futures-terms.ts +58 -0
  471. package/src/plugins/builtin/portfolio-list/pane/index.tsx +27 -10
  472. package/src/plugins/builtin/portfolio-list/pane/supplemental.ts +47 -28
  473. package/src/plugins/builtin/portfolio-list/quick-add/index.tsx +3 -2
  474. package/src/plugins/builtin/portfolio-list/quick-add/resolution.ts +10 -3
  475. package/src/plugins/builtin/portfolio-list/summary/index.tsx +26 -4
  476. package/src/plugins/builtin/portfolio-list/summary/totals.ts +31 -3
  477. package/src/plugins/builtin/portfolio-list/table.tsx +25 -5
  478. package/src/plugins/builtin/power/prices-headless.ts +2 -1
  479. package/src/plugins/builtin/realized-vol/chart-model.ts +29 -5
  480. package/src/plugins/builtin/realized-vol/charts.tsx +14 -8
  481. package/src/plugins/builtin/realized-vol/evidence.ts +2 -0
  482. package/src/plugins/builtin/realized-vol/headless.ts +6 -4
  483. package/src/plugins/builtin/realized-vol/model.ts +5 -1
  484. package/src/plugins/builtin/realized-vol/pane.tsx +31 -11
  485. package/src/plugins/builtin/realized-vol/settings.ts +1 -1
  486. package/src/plugins/builtin/research/analyst-headless.ts +4 -0
  487. package/src/plugins/builtin/research/corporate-actions-pane.tsx +2 -0
  488. package/src/plugins/builtin/research/event-model.ts +22 -2
  489. package/src/plugins/builtin/research/headless-schema.ts +1 -0
  490. package/src/plugins/builtin/research/headless.ts +3 -0
  491. package/src/plugins/builtin/research/index.tsx +3 -0
  492. package/src/plugins/builtin/research/relative-valuation-columns.ts +27 -5
  493. package/src/plugins/builtin/research/relative-valuation-headless.ts +2 -0
  494. package/src/plugins/builtin/revenue-breakdown/index.tsx +1 -0
  495. package/src/plugins/builtin/reverse-dcf/headless.ts +9 -6
  496. package/src/plugins/builtin/reverse-dcf/index.tsx +2 -2
  497. package/src/plugins/builtin/reverse-dcf/model.ts +51 -4
  498. package/src/plugins/builtin/reverse-dcf/pane.tsx +23 -10
  499. package/src/plugins/builtin/risk-factors/headless.ts +7 -0
  500. package/src/plugins/builtin/risk-factors/index.tsx +1 -0
  501. package/src/plugins/builtin/scanner/feed.ts +5 -3
  502. package/src/plugins/builtin/scanner/headless.ts +9 -57
  503. package/src/plugins/builtin/scanner/index.ts +1 -2
  504. package/src/plugins/builtin/sec/forms.ts +2 -6
  505. package/src/plugins/builtin/sec/fund-facts-view.tsx +53 -0
  506. package/src/plugins/builtin/sec/fund-facts.ts +328 -0
  507. package/src/plugins/builtin/sec/headless.ts +140 -44
  508. package/src/plugins/builtin/sec/index.tsx +95 -30
  509. package/src/plugins/builtin/sec/model.ts +2 -44
  510. package/src/plugins/builtin/shared/headless-options.ts +10 -0
  511. package/src/plugins/builtin/shared/locked-rows.tsx +3 -1
  512. package/src/plugins/builtin/shared/move-rank.ts +108 -0
  513. package/src/plugins/builtin/shared/report-freshness.ts +25 -9
  514. package/src/plugins/builtin/shared/scanner-capture.ts +95 -0
  515. package/src/plugins/builtin/shared/treasury-cutoffs.ts +15 -0
  516. package/src/plugins/builtin/shared/use-quote-board.ts +1 -0
  517. package/src/plugins/builtin/shared/volatility/live-session.ts +34 -0
  518. package/src/plugins/builtin/shared/volatility-indices.ts +32 -0
  519. package/src/plugins/builtin/short-interest/headless.ts +3 -0
  520. package/src/plugins/builtin/short-interest/watch-model.ts +2 -2
  521. package/src/plugins/builtin/social-mentions/client.ts +8 -1
  522. package/src/plugins/builtin/social-mentions/pane.tsx +8 -6
  523. package/src/plugins/builtin/supply-chain/client.ts +12 -3
  524. package/src/plugins/builtin/supply-chain/disclosure-quote.tsx +9 -5
  525. package/src/plugins/builtin/supply-chain/evidence.ts +3 -1
  526. package/src/plugins/builtin/supply-chain/flow-layout.ts +2 -1
  527. package/src/plugins/builtin/supply-chain/flow.tsx +23 -16
  528. package/src/plugins/builtin/supply-chain/graph-client.ts +8 -5
  529. package/src/plugins/builtin/supply-chain/graph-evidence.ts +1 -1
  530. package/src/plugins/builtin/supply-chain/graph-model.ts +10 -2
  531. package/src/plugins/builtin/supply-chain/graph-pane.tsx +9 -7
  532. package/src/plugins/builtin/supply-chain/graph.tsx +8 -6
  533. package/src/plugins/builtin/supply-chain/headless.ts +69 -27
  534. package/src/plugins/builtin/supply-chain/index.tsx +1 -1
  535. package/src/plugins/builtin/supply-chain/model.ts +76 -15
  536. package/src/plugins/builtin/supply-chain/pane.tsx +29 -15
  537. package/src/plugins/builtin/supply-chain/row-evidence.tsx +5 -4
  538. package/src/plugins/builtin/themes/model.ts +2 -5
  539. package/src/plugins/builtin/thirteenf/api.ts +50 -2
  540. package/src/plugins/builtin/thirteenf/data.ts +250 -11
  541. package/src/plugins/builtin/thirteenf/headless.ts +311 -28
  542. package/src/plugins/builtin/thirteenf/index.tsx +4 -1
  543. package/src/plugins/builtin/thirteenf/model.ts +244 -19
  544. package/src/plugins/builtin/thirteenf/overlap-pane.tsx +133 -33
  545. package/src/plugins/builtin/thirteenf/overlap.ts +1 -1
  546. package/src/plugins/builtin/thirteenf/pane.tsx +24 -5
  547. package/src/plugins/builtin/thirteenf/report-notes.ts +78 -0
  548. package/src/plugins/builtin/thirteenf/types.ts +49 -0
  549. package/src/plugins/builtin/ticker-detail/data-panes/historical-prices.tsx +22 -8
  550. package/src/plugins/builtin/ticker-detail/data-panes/history-bars.ts +17 -1
  551. package/src/plugins/builtin/ticker-detail/financials/model.ts +2 -42
  552. package/src/plugins/builtin/ticker-detail/financials/tab.tsx +1 -1
  553. package/src/plugins/builtin/ticker-detail/headless.ts +23 -10
  554. package/src/plugins/builtin/ticker-detail/overview/components.tsx +27 -3
  555. package/src/plugins/builtin/ticker-detail/overview/dividend.ts +60 -0
  556. package/src/plugins/builtin/ticker-detail/overview/model.ts +46 -9
  557. package/src/plugins/builtin/ticker-detail/overview/pane.tsx +3 -0
  558. package/src/plugins/builtin/ticker-detail/overview-tab.tsx +36 -3
  559. package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +18 -19
  560. package/src/plugins/builtin/time-sales/client.ts +7 -4
  561. package/src/plugins/builtin/time-sales/headless.ts +71 -22
  562. package/src/plugins/builtin/time-sales/model.ts +12 -0
  563. package/src/plugins/builtin/time-sales/pane.tsx +31 -7
  564. package/src/plugins/builtin/time-sales/window.ts +128 -0
  565. package/src/plugins/builtin/trace-bonds/client.ts +351 -33
  566. package/src/plugins/builtin/trace-bonds/headless.ts +60 -22
  567. package/src/plugins/builtin/trace-bonds/index.tsx +4 -2
  568. package/src/plugins/builtin/trace-bonds/model.ts +27 -25
  569. package/src/plugins/builtin/trace-bonds/pane.tsx +63 -45
  570. package/src/plugins/builtin/treasury-auctions/cache.ts +61 -15
  571. package/src/plugins/builtin/treasury-auctions/client.ts +45 -10
  572. package/src/plugins/builtin/treasury-auctions/headless.ts +35 -13
  573. package/src/plugins/builtin/treasury-auctions/index.tsx +5 -2
  574. package/src/plugins/builtin/treasury-auctions/model.ts +20 -16
  575. package/src/plugins/builtin/treasury-auctions/pane.tsx +29 -12
  576. package/src/plugins/builtin/vol-surface/charts.tsx +2 -1
  577. package/src/plugins/builtin/vol-surface/headless.ts +3 -2
  578. package/src/plugins/builtin/vol-surface/pane.tsx +2 -1
  579. package/src/plugins/builtin/vol-surface/stored.ts +4 -7
  580. package/src/plugins/builtin/volatility/chart-model.ts +16 -15
  581. package/src/plugins/builtin/volatility/charts.tsx +5 -5
  582. package/src/plugins/builtin/volatility/client.ts +73 -2
  583. package/src/plugins/builtin/volatility/evidence.ts +13 -14
  584. package/src/plugins/builtin/volatility/headless.ts +13 -7
  585. package/src/plugins/builtin/volatility/index.tsx +1 -1
  586. package/src/plugins/builtin/volatility/model.ts +104 -38
  587. package/src/plugins/builtin/volatility/pane.tsx +42 -24
  588. package/src/plugins/builtin/volatility/series.ts +22 -13
  589. package/src/plugins/builtin/world-venue-map/geo-series.ts +9 -0
  590. package/src/plugins/builtin/world-venue-map/headless.ts +8 -5
  591. package/src/plugins/builtin/world-venue-map/index.ts +16 -2
  592. package/src/plugins/builtin/world-venue-map/map.tsx +13 -17
  593. package/src/plugins/builtin/yield-curve/curves.ts +29 -5
  594. package/src/plugins/builtin/yield-curve/headless.ts +41 -8
  595. package/src/plugins/builtin/yield-curve/history.ts +5 -5
  596. package/src/plugins/builtin/yield-curve/index.tsx +30 -13
  597. package/src/plugins/compat.ts +3 -1
  598. package/src/plugins/dependencies.ts +8 -2
  599. package/src/plugins/host-link.ts +12 -5
  600. package/src/plugins/installer.ts +16 -7
  601. package/src/plugins/loader.ts +9 -2
  602. package/src/plugins/marketplace/activation.ts +10 -4
  603. package/src/plugins/registry/host-actions.ts +3 -0
  604. package/src/plugins/registry/index.ts +3 -1
  605. package/src/{plugins/builtin/portfolio-list → portfolio}/allocation.ts +74 -12
  606. package/src/{plugins/builtin/portfolio-list → portfolio}/column-values.ts +140 -53
  607. package/src/portfolio/futures-positions.ts +213 -0
  608. package/src/portfolio/futures-terms.ts +75 -0
  609. package/src/portfolio/manual-lots.ts +78 -0
  610. package/src/portfolio/mutations.ts +54 -10
  611. package/src/portfolio/position-metrics.ts +44 -10
  612. package/src/portfolio/valuation-basis.ts +31 -4
  613. package/src/public/__snapshots__/public-api.test.ts.snap +4 -0
  614. package/src/public/time-series.ts +2 -1
  615. package/src/remote/confirm-change.tsx +2 -1
  616. package/src/remote/server.ts +1 -1
  617. package/src/remote/watchlist.ts +9 -1
  618. package/src/renderers/dom/data-table/row.tsx +1 -1
  619. package/src/renderers/dom/desktop/audio-player.tsx +312 -0
  620. package/src/renderers/dom/desktop/control-styles.ts +17 -82
  621. package/src/renderers/dom/desktop/controls.tsx +39 -63
  622. package/src/renderers/dom/desktop/dialog-actions.tsx +13 -53
  623. package/src/renderers/dom/desktop/icons.tsx +8 -0
  624. package/src/renderers/dom/desktop/list-view.tsx +6 -6
  625. package/src/renderers/dom/desktop/popover.tsx +0 -3
  626. package/src/renderers/dom/desktop/query-bar.tsx +6 -4
  627. package/src/renderers/dom/desktop/select-field.tsx +9 -8
  628. package/src/renderers/dom/desktop/stack-header.ts +3 -0
  629. package/src/renderers/dom/dom-ui-host.tsx +3 -2
  630. package/src/renderers/dom/host/chart-surface.tsx +3 -3
  631. package/src/renderers/dom/host/size-observer.ts +33 -4
  632. package/src/renderers/dom/host/surface-3d.tsx +3 -2
  633. package/src/renderers/dom/host/surface-fit.ts +4 -1
  634. package/src/renderers/dom/host/tabs.tsx +22 -132
  635. package/src/renderers/dom/styles.css +358 -160
  636. package/src/renderers/electrobun/bun/core-capabilities.ts +1 -1
  637. package/src/renderers/electrobun/bun/desktop/backend.ts +1 -1
  638. package/src/renderers/electrobun/bun/desktop/initialization.ts +1 -0
  639. package/src/renderers/electrobun/bun/desktop/state-broadcaster.ts +43 -1
  640. package/src/renderers/electrobun/bun/desktop/workspace/requests.ts +5 -1
  641. package/src/renderers/electrobun/shared/rpc-codec.ts +7 -0
  642. package/src/renderers/electrobun/view/cli-pane-shot-entry.tsx +21 -17
  643. package/src/renderers/electrobun/view/cli-pane-shot-frame.tsx +3 -3
  644. package/src/renderers/electrobun/view/desktop/window/bridge.ts +6 -8
  645. package/src/renderers/electrobun/view/desktop/window/snapshot.ts +18 -0
  646. package/src/series/capability.ts +1 -0
  647. package/src/series/files.ts +9 -3
  648. package/src/series/registry.ts +40 -14
  649. package/src/series/resolve.ts +121 -18
  650. package/src/series/standalone.ts +3 -2
  651. package/src/series/types.ts +55 -1
  652. package/src/series/validate.ts +39 -0
  653. package/src/shares/api.ts +26 -7
  654. package/src/shares/bug-report-dialog.tsx +2 -2
  655. package/src/shares/bug-report-flow.tsx +4 -7
  656. package/src/shares/capture-flow.ts +5 -4
  657. package/src/shares/capture-preview.tsx +2 -2
  658. package/src/shares/chat.ts +7 -27
  659. package/src/shares/flow.tsx +86 -40
  660. package/src/shares/location.ts +1 -3
  661. package/src/shares/pane-image.ts +11 -9
  662. package/src/shares/pane.ts +5 -2
  663. package/src/shares/payload.ts +1 -1
  664. package/src/shares/personal-pane.ts +3 -3
  665. package/src/shares/portable-layout.ts +9 -2
  666. package/src/shares/ready.ts +42 -0
  667. package/src/shares/test-harness.ts +62 -0
  668. package/src/sources/gloomberb-cloud/batched-lookups.ts +73 -0
  669. package/src/sources/gloomberb-cloud/index.ts +64 -12
  670. package/src/sources/gloomberb-cloud/normalizers.ts +31 -2
  671. package/src/sources/gloomberb-cloud/perpetuals.ts +20 -1
  672. package/src/sources/history-omitted.ts +34 -0
  673. package/src/sources/history-result.ts +3 -0
  674. package/src/sources/history-retention.ts +1 -1
  675. package/src/sources/provider-errors.ts +43 -1
  676. package/src/sources/provider-router/batches.ts +3 -2
  677. package/src/sources/provider-router/cache.ts +2 -1
  678. package/src/sources/provider-router/cached-routes.ts +9 -3
  679. package/src/sources/provider-router/history.ts +9 -8
  680. package/src/sources/provider-router/index.ts +18 -3
  681. package/src/sources/provider-router/primary.ts +5 -4
  682. package/src/sources/provider-router/quote-route.ts +3 -1
  683. package/src/sources/provider-router/routing.ts +2 -1
  684. package/src/sources/provider-router/search.ts +47 -13
  685. package/src/sources/provider-router/streaming.ts +7 -4
  686. package/src/sources/sec-edgar.ts +1 -3
  687. package/src/state/app/context/index.tsx +9 -13
  688. package/src/state/app/tab-cursor.ts +149 -12
  689. package/src/state/hooks/quote-streaming.ts +3 -2
  690. package/src/state/hooks/session-snapshot.ts +3 -2
  691. package/src/state/persist-scheduler.ts +12 -4
  692. package/src/sync/controller.ts +22 -1
  693. package/src/sync/core-contributors.ts +58 -15
  694. package/src/team/collections-sync.ts +14 -4
  695. package/src/team/collections.ts +40 -11
  696. package/src/team/store.ts +5 -4
  697. package/src/telemetry/attention-counts.ts +8 -2
  698. package/src/telemetry/crash-reports-dom.ts +3 -0
  699. package/src/telemetry/crash-reports-node.ts +7 -4
  700. package/src/telemetry/crash-reports.ts +11 -11
  701. package/src/telemetry/usage-counts.ts +16 -12
  702. package/src/theme/colors.ts +2 -0
  703. package/src/theme/font-scale.ts +2 -0
  704. package/src/theme/ui-tokens.ts +71 -0
  705. package/src/tickers/batched-lookups.ts +186 -0
  706. package/src/tickers/company-name-listing.ts +97 -0
  707. package/src/tickers/company-name.ts +13 -0
  708. package/src/tickers/instrument-coverage.ts +112 -0
  709. package/src/tickers/listing-fate.ts +49 -9
  710. package/src/tickers/listing-venues.ts +24 -5
  711. package/src/tickers/open-target.ts +13 -5
  712. package/src/tickers/search/index.ts +112 -35
  713. package/src/tickers/search/ranking.ts +49 -1
  714. package/src/tickers/terminal-codes.ts +79 -0
  715. package/src/tickers/ticker-changes.ts +74 -3
  716. package/src/tickers/us-listing.ts +2 -1
  717. package/src/time-series/chart-data.ts +79 -8
  718. package/src/time-series/fundamentals.ts +55 -7
  719. package/src/time-series/ice-credit.ts +17 -2
  720. package/src/time-series/live-bars.ts +21 -8
  721. package/src/time-series/live-quotes.ts +2 -3
  722. package/src/time-series/price-comparison.ts +6 -1
  723. package/src/time-series/resolve.ts +65 -10
  724. package/src/time-series/spec.ts +2 -1
  725. package/src/time-series/studies.ts +3 -3
  726. package/src/time-series/types.ts +22 -0
  727. package/src/time-series/use-chart-resolution.ts +2 -1
  728. package/src/types/config.ts +7 -0
  729. package/src/types/data-provider.ts +20 -0
  730. package/src/types/headless.ts +142 -1
  731. package/src/types/instrument.ts +6 -0
  732. package/src/types/plugin.ts +32 -9
  733. package/src/types/price-history.ts +5 -0
  734. package/src/types/ticker-changes.ts +19 -0
  735. package/src/types/ticker.ts +10 -2
  736. package/src/ui/context-menu.tsx +2 -0
  737. package/src/ui/host.tsx +40 -4
  738. package/src/ui/measured-cells.ts +13 -7
  739. package/src/ui/qr.ts +7 -5
  740. package/src/updater/index.ts +5 -5
  741. package/src/utils/calendar-date.ts +86 -27
  742. package/src/utils/currency-units.ts +17 -0
  743. package/src/utils/debug-log.ts +1 -1
  744. package/src/utils/dividend-cash.ts +48 -0
  745. package/src/utils/dom-screenshot-rasters.ts +3 -1
  746. package/src/utils/dom-screenshot.ts +14 -10
  747. package/src/utils/exchange-rate-snapshot.ts +9 -4
  748. package/src/utils/external-url.ts +1 -0
  749. package/src/utils/fiscal-period.ts +47 -0
  750. package/src/utils/format.ts +5 -2
  751. package/src/utils/forward-dividend.ts +160 -11
  752. package/src/utils/futures-generic.ts +34 -8
  753. package/src/utils/http-proxy-response.ts +2 -1
  754. package/src/utils/local-utc-offset.ts +2 -0
  755. package/src/utils/log-failure.ts +31 -0
  756. package/src/utils/option-expiry.ts +12 -12
  757. package/src/utils/price-history-integrity.ts +56 -0
  758. package/src/utils/price-history.ts +13 -1
  759. package/src/utils/sec-filings.ts +245 -0
  760. package/src/utils/selection-clipboard.ts +5 -2
  761. package/src/utils/throttled-fetch.ts +1 -0
  762. package/src/{plugins/builtin/dividend-yield/trailing-cash.ts → utils/trailing-dividend.ts} +55 -8
  763. package/src/utils/url.ts +1 -0
  764. package/src/utils/utc-time.ts +11 -0
  765. package/src/plugins/builtin/chat/share/targets.ts +0 -27
  766. package/src/renderers/dom/host/top-surface.ts +0 -119
  767. package/src/shares/dialog.tsx +0 -221
  768. package/src/shares/live.ts +0 -19
@@ -1,6 +1,7 @@
1
1
  import { FINANCIAL_VINTAGE_NOTICE, SEC_EPS_BASIS_NOTICE } from "../../../utils/financial-statements";
2
2
  import { usePaneSharePreparation } from "../../../shares/prepare";
3
3
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
+ import { useTabCursorLink } from "../../../state/app/tab-cursor";
4
5
  import { Box, useUiCapabilities } from "../../../ui";
5
6
  import {
6
7
  ChoiceDialog,
@@ -30,6 +31,8 @@ import {
30
31
  type ManualChartResolution,
31
32
  } from "../../../time-series/resolution";
32
33
  import { useResolvedChartSpec } from "../../../time-series/hooks";
34
+ import { shortCompanyName } from "../../../tickers/company-name";
35
+ import { useSeriesListings } from "./series-listings";
33
36
  import { LIVE_CHART_TERMINAL_FRAME_MS } from "../../../time-series/live-quotes";
34
37
  import { FORWARD_VALUATION_BASIS_NOTICES } from "../../../time-series/forward-valuation";
35
38
  import { chartSeriesSourceKey } from "../../../capabilities";
@@ -56,8 +59,10 @@ import { chartComposerSemanticMetadata } from "./semantic";
56
59
  import {
57
60
  canToggleChartSeries,
58
61
  CHART_INTERACTION_VIEWPORT_SETTING_KEY,
62
+ CHART_PINNED_MOMENT_SETTING_KEY,
59
63
  CHART_SPEC_SETTING_KEY,
60
64
  parseChartInteractionViewport,
65
+ parseSharedPinnedMoment,
61
66
  parseChartSpecOr,
62
67
  projectVisibleChartSeries,
63
68
  toggleChartSeries,
@@ -67,6 +72,7 @@ import {
67
72
  futuresGenericRollFromValue,
68
73
  futuresGenericRollLabel,
69
74
  futuresGenericRollValue,
75
+ standardFuturesGenericRoll,
70
76
  type FuturesGenericAdjust,
71
77
  } from "../../../utils/futures-generic";
72
78
  import { chartSeriesLabel } from "./series-expression";
@@ -190,11 +196,14 @@ interface ChartComposerSurfaceProps {
190
196
  height: number;
191
197
  footerId: string;
192
198
  onCapture?: (capturing: boolean) => void;
199
+ /** The legend names each series' company; a ticker's own research tab already does. */
200
+ nameSeries?: boolean;
193
201
  }
194
202
 
195
203
  const QUICK_ADD_CAPTURE = "quick-add";
196
204
 
197
205
  const GENERIC_ROLL_OPTIONS = [
206
+ { value: "standard", label: "Standard" },
198
207
  { value: "oi", label: "OI switch" },
199
208
  { value: "f5", label: "5d before notice" },
200
209
  { value: "d15", label: "Day 15" },
@@ -277,6 +286,7 @@ function ChartComposerSurface({
277
286
  height,
278
287
  footerId,
279
288
  onCapture,
289
+ nameSeries = true,
280
290
  }: ChartComposerSurfaceProps) {
281
291
  const dialog = useDialog();
282
292
  const dispatch = useAppDispatch();
@@ -310,6 +320,19 @@ function ChartComposerSurface({
310
320
  CHART_INTERACTION_VIEWPORT_SETTING_KEY,
311
321
  null,
312
322
  );
323
+ // A link shared while its sender's crosshair was pinned opens on that
324
+ // moment: the chart pins its tab there once, then forgets it, so a restart
325
+ // does not pin it again. The value came from a link: anything but a
326
+ // plausible time is dropped without pinning. This handle only sets the
327
+ // pin; the chart it opens on is what shows and keeps it.
328
+ const [pinnedMoment, setPinnedMoment] = usePaneSettingValue<unknown>(CHART_PINNED_MOMENT_SETTING_KEY, null);
329
+ const momentLink = useTabCursorLink(paneId ? `${paneId}:moment` : null, { viewer: false });
330
+ useEffect(() => {
331
+ if (pinnedMoment == null || !momentLink?.pin) return;
332
+ const moment = parseSharedPinnedMoment(pinnedMoment);
333
+ if (moment !== null) momentLink.pin(moment);
334
+ setPinnedMoment(undefined);
335
+ }, [momentLink, pinnedMoment, setPinnedMoment]);
313
336
  const persistedInteractionViewport = useMemo(
314
337
  () => parseChartInteractionViewport(storedInteractionViewport),
315
338
  [storedInteractionViewport],
@@ -332,7 +355,9 @@ function ChartComposerSurface({
332
355
  // small zoom keeps the bars it already has. Read from the previous render:
333
356
  // the resolver only consults it when the viewport moves.
334
357
  const currentResolutionRef = useRef<ManualChartResolution | null>(null);
335
- const resolution = useResolvedChartSpec(spec, {
358
+ // Bare series are read as `quote` reads them before anything is loaded for them.
359
+ const listings = useSeriesListings(spec);
360
+ const resolution = useResolvedChartSpec(listings.spec, {
336
361
  autoViewport: spec.viewport.resolution === "auto"
337
362
  ? activeRuntimeViewport?.adaptiveViewport
338
363
  : null,
@@ -391,10 +416,18 @@ function ChartComposerSurface({
391
416
  // them. Without a placeholder they vanish from the legend entirely and the
392
417
  // only way back is the series dialog.
393
418
  const legendSeries = useMemo(() => {
394
- const resolved = resolution.legendSeries ?? [];
419
+ // Each security series names its company once, beside its label: "AAPL Price · Apple".
420
+ const named = new Set<string>();
421
+ const resolved = (resolution.legendSeries ?? []).map((entry) => {
422
+ const name = nameSeries ? listings.names.get(entry.id) : undefined;
423
+ const company = name ? shortCompanyName(name) : "";
424
+ if (!company || named.has(company)) return entry;
425
+ named.add(company);
426
+ return { ...entry, label: `${entry.label} · ${company}` };
427
+ });
395
428
  const resolvedIds = new Set(resolved.map((entry) => entry.id));
396
429
  const missing = spec.series.filter((entry) => !resolvedIds.has(entry.id));
397
- if (missing.length === 0) return resolution.legendSeries;
430
+ if (missing.length === 0) return named.size > 0 ? resolved : resolution.legendSeries;
398
431
  const bySpecOrder = new Map(spec.series.map((entry, index) => [entry.id, index] as const));
399
432
  return [
400
433
  ...resolved,
@@ -415,7 +448,7 @@ function ChartComposerSurface({
415
448
  points: [],
416
449
  })),
417
450
  ].sort((a, b) => (bySpecOrder.get(a.id) ?? Number.MAX_SAFE_INTEGER) - (bySpecOrder.get(b.id) ?? Number.MAX_SAFE_INTEGER));
418
- }, [resolution.legendSeries, spec.series]);
451
+ }, [listings.names, nameSeries, resolution.legendSeries, spec.series]);
419
452
  const plottedSeries = useMemo(
420
453
  () => projectVisibleChartSeries(
421
454
  spec,
@@ -896,7 +929,9 @@ function ChartComposerSurface({
896
929
  const comparisonUnavailable = comparisonHasNoWindow && !resolution.loading
897
930
  ? "Comparison unavailable: need two shared dates and a nonzero baseline."
898
931
  : null;
899
- const statusError = resolution.errors[0];
932
+ const loading = resolution.loading || listings.pending;
933
+ // A bare code several companies list asks which, as `quote` does, before anything else is said.
934
+ const statusError = listings.errors[0] ?? resolution.errors[0];
900
935
  // A spread or formula error names its legs and their units; the study's id adds nothing to it.
901
936
  const formulaStudy = spec.studies.find((study) => (study.kind === "spread" || study.kind === "formula")
902
937
  && statusError?.startsWith(`${study.id}: `));
@@ -904,7 +939,9 @@ function ChartComposerSurface({
904
939
  // Failed series use their authored id in errors and their display label in warnings.
905
940
  const errorSeries = spec.series.find((entry) => statusError?.startsWith(`${entry.label ?? entry.id}: `));
906
941
  const errorMessage = errorSeries ? statusError?.slice(`${errorSeries.label ?? errorSeries.id}: `.length) : undefined;
907
- const errorSeriesLabel = legendSeries?.find((entry) => entry.id === errorSeries?.id)?.label;
942
+ // The label the resolver wrote its warnings with, before the legend named the company.
943
+ const errorSeriesLabel = (resolution.legendSeries?.find((entry) => entry.id === errorSeries?.id)
944
+ ?? legendSeries?.find((entry) => entry.id === errorSeries?.id))?.label;
908
945
  const duplicateErrorNotices = new Set([statusError, errorMessage,
909
946
  errorSeriesLabel && errorMessage ? `${errorSeriesLabel}: ${errorMessage}` : undefined]);
910
947
  // A failed shared window empties every compared leg; one comparison message explains it.
@@ -923,7 +960,8 @@ function ChartComposerSurface({
923
960
  && warning.endsWith("; only matching observation times contribute."))
924
961
  ))
925
962
  ));
926
- const statusNotices = [...new Set([...(statusErrorNotice ? [statusErrorNotice] : []), ...(comparisonUnavailable ? [comparisonUnavailable] : []), ...statusWarnings])];
963
+ const statusNotices = [...new Set([...(statusErrorNotice ? [statusErrorNotice] : []), ...listings.errors, ...listings.notices,
964
+ ...(comparisonUnavailable ? [comparisonUnavailable] : []), ...statusWarnings])];
927
965
  usePaneNoticeFooter({
928
966
  registrationId: `${footerId}:notices`,
929
967
  notices: statusNotices,
@@ -964,7 +1002,7 @@ function ChartComposerSurface({
964
1002
  return newest > end ? formatCompositeDatasetDate(new Date(newest), end) : null;
965
1003
  }, [activeRuntimeViewport, plottedSeries, spec, viewport]);
966
1004
  usePaneFooter(footerId, () => ({
967
- info: resolution.loading
1005
+ info: loading
968
1006
  ? [{ id: "loading", parts: [{ text: "loading", tone: "muted" as const }] }]
969
1007
  : pickingAnchor
970
1008
  ? [{ id: "anchor", parts: [{ text: "pick a bar to anchor VWAP", tone: "muted" as const }] }]
@@ -978,7 +1016,7 @@ function ChartComposerSurface({
978
1016
  { id: "resolution", key: "t", label: "imeframe", onPress: footerResolution },
979
1017
  ...(anchorable ? [{ id: "vwap-anchor", key: "v", label: "wap anchor", title: "Anchor VWAP", onPress: footerAnchor }] : []),
980
1018
  ],
981
- }), [resolution.loading, pickingAnchor, newestBeyondView, footerSeries, openIndicators, indicatorsDisabled, openFormulas, formulasDisabled, footerResolution, anchorable, footerAnchor]);
1019
+ }), [loading, pickingAnchor, newestBeyondView, footerSeries, openIndicators, indicatorsDisabled, openFormulas, formulasDisabled, footerResolution, anchorable, footerAnchor]);
982
1020
 
983
1021
  // A fixed window (a GIP session) highlights no range, so the bar names it.
984
1022
  const dateWindowLabel = useMemo(() => {
@@ -996,9 +1034,12 @@ function ChartComposerSurface({
996
1034
  const genericFilters = useMemo(() => {
997
1035
  if (!generic) return [];
998
1036
  const roll = futuresGenericRollValue(generic.roll);
999
- const rollOptions = GENERIC_ROLL_OPTIONS.map((option) => option.value === "f5"
1000
- ? { ...option, label: futuresGenericNotice(generic.root) === "first notice" ? "5d before notice" : "5d before last trade" }
1001
- : option);
1037
+ const notice = futuresGenericNotice(generic.root) === "first notice" ? "notice" : "last trade";
1038
+ const standard = standardFuturesGenericRoll(generic.root);
1039
+ const rollOptions = GENERIC_ROLL_OPTIONS.map((option) => option.value === "f5" ? { ...option, label: `5d before ${notice}` }
1040
+ : option.value === "standard" && standard.rule === "first-notice"
1041
+ ? { ...option, label: standard.days === 0 ? `Standard, after ${notice}` : `Standard, ${standard.days}d before ${notice}` }
1042
+ : option);
1002
1043
  if (!rollOptions.some((option) => option.value === roll)) rollOptions.push({ value: roll, label: futuresGenericRollLabel(generic) });
1003
1044
  const update = (change: Parameters<typeof setChartFuturesGeneric>[1]) => {
1004
1045
  const next = setChartFuturesGeneric(specRef.current, change);
@@ -1008,7 +1049,7 @@ function ChartComposerSurface({
1008
1049
  return [
1009
1050
  { id: "roll", label: "Roll", value: roll, options: rollOptions, title: "Roll rule",
1010
1051
  onChange: (value: string) => {
1011
- const next = futuresGenericRollFromValue(value);
1052
+ const next = futuresGenericRollFromValue(value, generic.root);
1012
1053
  if (next) update({ roll: next });
1013
1054
  } },
1014
1055
  { id: "adjust", label: "Adjust", value: generic.adjust, options: GENERIC_ADJUST_OPTIONS, title: "Adjustment",
@@ -1041,11 +1082,18 @@ function ChartComposerSurface({
1041
1082
  }]
1042
1083
  : [];
1043
1084
 
1085
+ // A company that reports no quarterly figures says so, and where its annual ones are.
1086
+ const unreported = resolution.legendSeries?.find((entry) => entry.unreportedPeriod && entry.points.length === 0);
1044
1087
  const emptyMessage = spec.series.length === 0
1045
1088
  ? "Add a series to start the chart"
1046
- : resolution.loading
1089
+ : loading
1047
1090
  ? "Loading chart data"
1048
- : statusErrorNotice ?? comparisonUnavailable ?? "No observations in this range";
1091
+ : statusErrorNotice ?? comparisonUnavailable
1092
+ ?? (unreported ? `${unreported.label} has no ${unreported.unreportedPeriod} figures. Set Period to Annual in Series.` : "No observations in this range");
1093
+ // Under "Choose an exchange for BDI.", the listings it asks between.
1094
+ const emptyDetail = !loading && spec.series.length > 0 && emptyMessage === statusErrorNotice && statusError
1095
+ ? listings.choices.get(statusError)
1096
+ : undefined;
1049
1097
 
1050
1098
  return (
1051
1099
  <Box flexDirection="column" width={width} height={height}>
@@ -1127,6 +1175,7 @@ function ChartComposerSurface({
1127
1175
  timePick={timePick}
1128
1176
  levels={chartLevels}
1129
1177
  emptyMessage={emptyMessage}
1178
+ emptyDetail={emptyDetail}
1130
1179
  legendAccessory={(
1131
1180
  <ChartSeriesQuickAdd
1132
1181
  spec={spec}
@@ -1258,6 +1307,7 @@ export function ChartComposerResearchTab({ focused, width, height, onCapture }:
1258
1307
  height={height}
1259
1308
  footerId="chart-composer:research"
1260
1309
  onCapture={onCapture}
1310
+ nameSeries={false}
1261
1311
  />
1262
1312
  );
1263
1313
  }
@@ -6,7 +6,7 @@ import {
6
6
  } from "../../../time-series/types";
7
7
  import type { ChartResolution, TimeRange } from "../../../components/chart/core/types";
8
8
  import { MAX_CHART_COMPOSER_SERIES } from "./chart-spec";
9
- import { appendChartSeries, buildCustomSeries, buildSeriesSpec, panelsForSeries } from "./chart-spec-edit";
9
+ import { appendChartSeries, appendPlacedSeries, buildCustomSeries, buildSeriesSpec, panelsForSeries } from "./chart-spec-edit";
10
10
  import { currencyPairSpelling } from "../../../utils/currency-pair";
11
11
  import { dashedCoinPair } from "../../../utils/crypto-pair";
12
12
  import {
@@ -21,6 +21,8 @@ import {
21
21
  import { setBuiltinStudies, setPairStudies, type PairStudySelection } from "./studies";
22
22
  import { looksLikeFormula, parseFormulaExpression, type ParsedFormula } from "./formula";
23
23
  import type { SeriesCatalogSuggestion } from "./series-catalog";
24
+ import { getSharedRegistry } from "../../registry";
25
+ import { seriesCatalogEntry } from "../../../series/registry";
24
26
 
25
27
  function chartSpec(
26
28
  series: ChartSeriesSpec[],
@@ -43,7 +45,8 @@ export function buildEmptyChartPreset(): ChartSpec {
43
45
  /**
44
46
  * `GAA/VOO`, `GAA / VOO`, and `CL=F - ES=F` are a ratio or a spread of two series.
45
47
  * A slash that is the symbol stays one series (`EUR/USD`, `BTC/USD`), and so does
46
- * a field written with a slash (`AAPL:EV/EBITDA`). A comma-separated list stays a list.
48
+ * a field written with a slash (`AAPL:EV/EBITDA`) and the symbol a catalog series
49
+ * takes after one (`CAP:short-volume:ratio/AAPL`). A comma-separated list stays a list.
47
50
  */
48
51
  function derivedPair(expression: string): { series: ParsedSeriesExpression[]; formula: PairStudySelection } | null {
49
52
  const trimmed = expression.trim();
@@ -58,6 +61,7 @@ function derivedPair(expression: string): { series: ParsedSeriesExpression[]; fo
58
61
  const tight = /^([^/\s]+)\/([^/\s]+)$/.exec(trimmed);
59
62
  if (!tight) return null;
60
63
  const [leftToken, rightToken] = [tight[1]!, tight[2]!];
64
+ if (/^CAP:/i.test(leftToken) && !/^CAP:/i.test(rightToken)) return null;
61
65
  const quote = rightToken.split(":")[0]!;
62
66
  if (currencyPairSpelling(`${leftToken}/${quote}`) || dashedCoinPair(`${leftToken}/${quote}`)) return null;
63
67
  const left = parseSeriesExpression(leftToken);
@@ -129,14 +133,54 @@ function appendChartFormula(spec: ChartSpec, expression: string): { spec: ChartS
129
133
  };
130
134
  }
131
135
 
132
- /** The chart with a catalog suggestion added: one series, or a formula's legs and its study. */
136
+ /**
137
+ * The chart with a catalog suggestion added: one series, a registered
138
+ * series' lines where it asks for them, or a formula's legs and its study.
139
+ */
133
140
  export function appendCatalogSuggestion(
134
141
  spec: ChartSpec,
135
142
  suggestion: SeriesCatalogSuggestion,
136
143
  ): { spec: ChartSpec; series: ChartSeriesSpec } {
137
- return suggestion.formula !== undefined
138
- ? appendChartFormula(spec, suggestion.formula)
139
- : appendChartSeries(spec, suggestion.expression);
144
+ if (suggestion.formula !== undefined) return appendChartFormula(spec, suggestion.formula);
145
+ if (suggestion.lines || suggestion.placement) {
146
+ return appendPlacedSeries(spec, suggestion.lines ?? [suggestion.expression!], {
147
+ name: suggestion.seriesName ?? suggestion.label,
148
+ ...(suggestion.placement ? { placement: suggestion.placement } : {}),
149
+ ...(suggestion.symbol ? { symbol: suggestion.symbol } : {}),
150
+ });
151
+ }
152
+ return appendChartSeries(spec, suggestion.expression);
153
+ }
154
+
155
+ /**
156
+ * The chart CAT opens for a registered series that asks where it is drawn or
157
+ * draws several lines: the ticker's price with the series placed as it asks,
158
+ * or the lines on their own.
159
+ */
160
+ export function buildRegisteredSeriesChart(
161
+ series: { name: string; template: string; placement?: SeriesCatalogSuggestion["placement"]; lines?: ReadonlyArray<{ name: string; expression: string; style?: ChartSeriesSpec["style"] }> },
162
+ symbol?: string,
163
+ ): ChartSpec {
164
+ const fill = (template: string) => symbol
165
+ ? template.replaceAll("{ticker}", template.startsWith("CAP:") ? encodeURIComponent(symbol) : symbol)
166
+ : template;
167
+ const prefix = symbol ? `${symbol} · ` : "";
168
+ const lines = series.lines?.length
169
+ ? series.lines.map((line) => {
170
+ const parsed = parseSeriesExpression(fill(line.expression));
171
+ if (!parsed) throw new Error(`"${line.expression}" is not a chart series.`);
172
+ return { ...parsed, label: `${prefix}${series.name} · ${line.name}`, ...(line.style ? { style: line.style } : {}) };
173
+ })
174
+ : [(() => {
175
+ const parsed = parseSeriesExpression(fill(series.template));
176
+ if (!parsed) throw new Error(`"${series.template}" is not a chart series.`);
177
+ return { ...parsed, label: `${prefix}${series.name}` };
178
+ })()];
179
+ const base = series.placement && symbol ? buildPriceChartPreset(symbol) : buildEmptyChartPreset();
180
+ return appendPlacedSeries(base, lines, {
181
+ name: series.name,
182
+ ...(series.placement && symbol ? { placement: series.placement, symbol } : {}),
183
+ }).spec;
140
184
  }
141
185
 
142
186
  /**
@@ -157,9 +201,27 @@ export function buildCustomChartPreset(expression: string, fallbackSymbol?: stri
157
201
  return formulaChartPreset(formula);
158
202
  }
159
203
  if (parsed.length === 0) return fallbackSymbol ? buildPriceChartPreset(fallbackSymbol) : buildEmptyChartPreset();
204
+ const registered = parsed.length === 1 ? placedRegisteredSeries(parsed[0]!) : null;
205
+ if (registered) return buildRegisteredSeriesChart(registered.series, registered.ticker);
160
206
  return chartSpec(buildCustomSeries(parsed));
161
207
  }
162
208
 
209
+ /**
210
+ * A registered series typed alone (`CAP:studies:rsi/AAPL`) that says where it is
211
+ * drawn or draws several lines charts as CAT opens it. Naming one line
212
+ * (`rsi~signal/AAPL`) charts that line alone.
213
+ */
214
+ function placedRegisteredSeries(expression: ParsedSeriesExpression) {
215
+ if (expression.kind !== "capability" || expression.seriesId.split("/")[0]!.includes("~")) return null;
216
+ const found = getSharedRegistry()?.series?.findLoaded(expression.capabilityId, expression.seriesId);
217
+ if (!found || (!found.series.definition.placement && !found.series.definition.lines?.length)) return null;
218
+ const entry = seriesCatalogEntry(found.series);
219
+ return {
220
+ series: { name: entry.name, template: entry.expression, placement: entry.placement, lines: entry.lines },
221
+ ...(found.ticker ? { ticker: found.ticker } : {}),
222
+ };
223
+ }
224
+
163
225
  export function buildPriceChartPreset(symbol: string): ChartSpec {
164
226
  const normalized = normalizeInstrument(symbol, true);
165
227
  if (!normalized) return buildEmptyChartPreset();
@@ -209,9 +271,15 @@ export function buildValuationChartPreset(
209
271
  ): ChartSpec {
210
272
  const resolvedField = resolveChartFieldAlias(fieldId);
211
273
  const normalized = symbols.map((symbol) => normalizeInstrument(symbol, true)).filter((entry): entry is NonNullable<typeof entry> => entry !== null).slice(0, MAX_CHART_COMPOSER_SERIES);
212
- return chartSpec(normalized.map((instrument, index) => buildSeriesSpec(
213
- { kind: "security", ...instrument, fieldId: resolvedField },
214
- index,
215
- { style: normalized.length === 1 ? "line" : "columns", axis: "left" },
216
- )));
274
+ return chartSpec(normalized.map((instrument, index) => {
275
+ const series = buildSeriesSpec(
276
+ { kind: "security", ...instrument, fieldId: resolvedField },
277
+ index,
278
+ { style: normalized.length === 1 ? "line" : "columns", axis: "left" },
279
+ );
280
+ // Fiscal years: most US filers report no Q4 EPS, which charts do not
281
+ // reconstruct, so a quarterly trailing multiple has only its latest few
282
+ // quarters. Quarterly is the series' Period control away.
283
+ return series.source.kind === "security" ? { ...series, source: { ...series.source, period: "annual" } } : series;
284
+ }));
217
285
  }
@@ -7,7 +7,7 @@ import {
7
7
  type ChartSeriesCatalogItem,
8
8
  } from "../../../capabilities";
9
9
  import type { TimeSeriesFieldDefinition } from "../../../time-series/types";
10
- import type { SeriesCatalogEntry } from "../../../series/types";
10
+ import type { SeriesCatalogEntry, SeriesPlacement } from "../../../series/types";
11
11
  import {
12
12
  canonicalExchange,
13
13
  parsePublicTickerKey,
@@ -31,13 +31,20 @@ interface SeriesCatalogSuggestionText {
31
31
  }
32
32
 
33
33
  /**
34
- * One series to add, or a catalog formula (`42*HO=F - CL=F`): its legs join
35
- * the chart with the study that weighs them.
34
+ * One series to add, the lines of a registered series that draws several, or
35
+ * a catalog formula (`42*HO=F - CL=F`): its legs join the chart with the study
36
+ * that weighs them.
36
37
  */
37
38
  export type SeriesCatalogSuggestion = SeriesCatalogSuggestionText & (
38
- | { expression: ParsedSeriesExpression; formula?: never }
39
- | { formula: string; expression?: never }
40
- );
39
+ | { expression: ParsedSeriesExpression; formula?: never; lines?: never }
40
+ | { lines: ParsedSeriesExpression[]; expression?: never; formula?: never }
41
+ | { formula: string; expression?: never; lines?: never }
42
+ ) & {
43
+ /** A registered series' own name, and where it asks to be drawn for the ticker it was filled in for. */
44
+ seriesName?: string;
45
+ placement?: SeriesPlacement;
46
+ symbol?: string;
47
+ };
41
48
 
42
49
  export interface SeriesSearchAnalysis {
43
50
  directInstrument: SeriesCatalogInstrument | null;
@@ -306,31 +313,44 @@ function registeredSeriesSuggestions(
306
313
  if (!query.trim() || registered.length === 0) return [];
307
314
  const instrument = analysis.directInstrument ?? defaultInstrument;
308
315
  const tickerQuery = analysis.directInstrument ? analysis.metricQuery : query;
309
- const hits: Array<{ entry: SeriesCatalogEntry; rank: number } & (
310
- | { expression: ParsedSeriesExpression; formula?: never }
311
- | { formula: string; expression?: never }
316
+ const hits: Array<{ entry: SeriesCatalogEntry; rank: number; symbol?: string } & (
317
+ | { expression: ParsedSeriesExpression; formula?: never; lines?: never }
318
+ | { lines: ParsedSeriesExpression[]; expression?: never; formula?: never }
319
+ | { formula: string; expression?: never; lines?: never }
312
320
  )> = [];
313
321
  for (const entry of registered) {
314
322
  let template = entry.expression;
315
323
  let text = query;
324
+ let symbol: string | undefined;
325
+ const fill = (value: string) => symbol
326
+ ? value.replaceAll("{ticker}", value.startsWith("CAP:") ? encodeURIComponent(symbol) : symbol)
327
+ : value;
316
328
  if (entry.input) {
317
329
  // Ticker fields are ranked against the security below; options and pairs need their own symbol.
318
330
  if (entry.input !== "ticker" || /^\{ticker\}:[A-Za-z]/.test(template) || !tickerQuery.trim()) continue;
319
- const symbol = publicTickerKey(instrument.symbol, instrument.exchange);
320
- template = template.replaceAll("{ticker}", template.startsWith("CAP:") ? encodeURIComponent(symbol) : symbol);
331
+ symbol = publicTickerKey(instrument.symbol, instrument.exchange);
332
+ template = fill(template);
321
333
  text = tickerQuery;
322
334
  }
323
335
  if (!matchesAliasQuery(text, entry.name, entry.expression, entry.id, entry.group ?? "", ...(entry.tags ?? []))) continue;
336
+ const prefix = symbol ? `${symbol} · ` : "";
337
+ if (entry.lines?.length) {
338
+ const lines = entry.lines.flatMap((line) => {
339
+ const parsed = parseSeriesExpression(fill(line.expression));
340
+ return parsed ? [{ ...parsed, label: `${prefix}${entry.name} · ${line.name}`, ...(line.style ? { style: line.style } : {}) }] : [];
341
+ });
342
+ if (lines.length === entry.lines.length) hits.push({ entry, rank: registeredMatchRank(entry, text), lines, ...(symbol ? { symbol } : {}) });
343
+ continue;
344
+ }
324
345
  const parsed = parseSeriesExpression(template);
325
346
  if (!parsed) {
326
347
  if (!entry.input && catalogFormula(template)) hits.push({ entry, rank: registeredMatchRank(entry, text), formula: template });
327
348
  continue;
328
349
  }
329
- const label = entry.input ? `${publicTickerKey(instrument.symbol, instrument.exchange)} · ${entry.name}` : entry.name;
330
- hits.push({ entry, rank: registeredMatchRank(entry, text), expression: { ...parsed, label } });
350
+ hits.push({ entry, rank: registeredMatchRank(entry, text), expression: { ...parsed, label: `${prefix}${entry.name}` }, ...(symbol ? { symbol } : {}) });
331
351
  }
332
352
  hits.sort((left, right) => left.rank - right.rank || left.entry.name.length - right.entry.name.length);
333
- return hits.map(({ entry, expression, formula }): SeriesCatalogSuggestion => {
353
+ return hits.map(({ entry, expression, lines, formula, symbol }): SeriesCatalogSuggestion => {
334
354
  const description = [entry.group, entry.unit, entry.frequency].filter(Boolean).join(" · ");
335
355
  const detail = entry.group ?? "Series";
336
356
  if (formula !== undefined) {
@@ -338,12 +358,28 @@ function registeredSeriesSuggestions(
338
358
  const formulaDescription = [formula, entry.unit, entry.frequency].filter(Boolean).join(" · ");
339
359
  return { id: `formula:${formula}`, label: entry.name, description: formulaDescription, detail, formula };
340
360
  }
361
+ const placed = {
362
+ seriesName: entry.name,
363
+ ...(entry.placement ? { placement: entry.placement } : {}),
364
+ ...(symbol ? { symbol } : {}),
365
+ };
366
+ if (lines) {
367
+ return {
368
+ id: `lines:${suggestionId(lines[0]!)}`,
369
+ label: `${symbol ? `${symbol} · ` : ""}${entry.name}`,
370
+ description: [entry.lines!.map((line) => line.name).join(", "), entry.group].filter(Boolean).join(" · "),
371
+ detail,
372
+ lines,
373
+ ...placed,
374
+ };
375
+ }
341
376
  return {
342
377
  id: suggestionId(expression),
343
378
  label: expression.kind === "capability" ? expression.label ?? entry.name : `${entry.expression} · ${entry.name}`,
344
379
  description,
345
380
  detail,
346
381
  expression,
382
+ ...placed,
347
383
  };
348
384
  });
349
385
  }
@@ -162,10 +162,14 @@ export function parseSeriesExpression(value: string): ParsedSeriesExpression | n
162
162
  return { kind: "security", ...instrument, fieldId };
163
163
  }
164
164
 
165
+ const SERIES_FORMS = "Use SYMBOL, SYMBOL:field, FUT:code, UST:maturity, FRED:series, GEO:series, or CAP:capability-id:series-id.";
166
+
165
167
  export function parseChartExpression(value: string): ParsedSeriesExpression[] {
166
168
  if (!value.trim()) return [];
167
-
168
- const legs = value.split(/[;,\n]/);
169
+ // A list pasted with a stray separator (`BRK.B,SPY,`, `,SPY`, `A,,B`) has no series between them.
170
+ const legs = value.split(/[;,\n]/).filter((leg) => leg.trim());
171
+ // Separators alone name no series at all.
172
+ if (legs.length === 0) throw new Error(`Invalid chart series "${value.trim()}": no series between its separators. ${SERIES_FORMS}`);
169
173
  if (legs.length > MAX_CHART_COMPOSER_SERIES) {
170
174
  throw new Error(`Charts support up to ${MAX_CHART_COMPOSER_SERIES} base series.`);
171
175
  }
@@ -173,10 +177,7 @@ export function parseChartExpression(value: string): ParsedSeriesExpression[] {
173
177
  return legs.map((leg) => {
174
178
  const parsed = parseSeriesExpression(leg);
175
179
  if (parsed) return parsed;
176
- const display = leg.trim() || "empty series";
177
- throw new Error(
178
- `Invalid chart series "${display}". Use SYMBOL, SYMBOL:field, FUT:code, UST:maturity, FRED:series, GEO:series, or CAP:capability-id:series-id.`,
179
- );
180
+ throw new Error(`Invalid chart series "${leg.trim()}". ${SERIES_FORMS}`);
180
181
  });
181
182
  }
182
183
 
@@ -194,7 +195,8 @@ export function formatSeriesExpression(series: ChartSeriesSpec): string {
194
195
  export function registeredSeriesName(source: { capabilityId: string; seriesId: string }): string | null {
195
196
  const found = getSharedRegistry()?.series?.findLoaded(source.capabilityId, source.seriesId);
196
197
  if (!found) return null;
197
- return found.ticker ? `${found.ticker} ${found.series.definition.name}` : found.series.definition.name;
198
+ const name = found.line ? `${found.series.definition.name} · ${found.line.name}` : found.series.definition.name;
199
+ return found.ticker ? `${found.ticker} ${name}` : name;
198
200
  }
199
201
 
200
202
  export function chartSeriesLabel(series: ChartSeriesSpec): string {