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
@@ -0,0 +1,60 @@
1
+ import { useCallback, useMemo } from "react";
2
+ import { useAsyncResource } from "../../../../react/async-resource";
3
+ import type { CorporateActionsData, TickerFinancials } from "../../../../types/financials";
4
+ import { measuresTrailingYield } from "../../../../market-data/quotes/live-valuation";
5
+ import {
6
+ distributionHistory,
7
+ forwardDividendMayHaveLapsed,
8
+ lapsedDividend,
9
+ type DividendLapse,
10
+ } from "../../../../utils/forward-dividend";
11
+ import { useAssetData } from "../../../runtime";
12
+
13
+ /**
14
+ * What the overview's dividend yield reads beside the fundamentals: whether a
15
+ * forward yield stands, has stopped, or waits on the history that says, and
16
+ * the cash history a trailing yield is measured from.
17
+ */
18
+ export interface OverviewDividendState {
19
+ /** The history is still being read; the yield is held back rather than shown and then withdrawn. */
20
+ pending: boolean;
21
+ lapse: DividendLapse | null;
22
+ /**
23
+ * The listing's cash history, for a trailing yield (listingDividendYield).
24
+ * Null while it is read and when it cannot be, which leaves Gloom Cloud's
25
+ * yield: a trailing yield is never withdrawn, so it is not held back.
26
+ */
27
+ actions?: CorporateActionsData | null;
28
+ }
29
+
30
+ const CURRENT: OverviewDividendState = { pending: false, lapse: null };
31
+
32
+ /**
33
+ * The listing's distribution history as the overview's dividend yield reads
34
+ * it. A trailing yield is measured from it as DVD measures it. A forward
35
+ * yield's stopped dividend (lapsedDividend) is read from it only once its
36
+ * ex-date is far enough past for the dividend to have stopped; without a
37
+ * history, Gloom Cloud's fifteen months decide on the ex-date alone.
38
+ */
39
+ export function useOverviewDividend(
40
+ symbol: string | null,
41
+ exchange: string,
42
+ fundamentals: TickerFinancials["fundamentals"] | undefined,
43
+ ): OverviewDividendState {
44
+ const dataProvider = useAssetData();
45
+ const forward = fundamentals?.dividendYieldBasis === "forward" && fundamentals.dividendYield != null;
46
+ const trailing = measuresTrailingYield(fundamentals);
47
+ const asOf = fundamentals?.exDividendDate;
48
+ const readsHistory = !!symbol && !!dataProvider?.getCorporateActions && (trailing || (forward && forwardDividendMayHaveLapsed(asOf)));
49
+ const loader = useCallback(() => dataProvider!.getCorporateActions!(symbol!, exchange), [dataProvider, exchange, symbol]);
50
+ const cached = useMemo(() => readsHistory
51
+ ? dataProvider?.getCachedQuery?.("getCorporateActions", [symbol!, exchange]).getSnapshot().result?.value ?? null
52
+ : null, [dataProvider, exchange, readsHistory, symbol]);
53
+ const resource = useAsyncResource(readsHistory ? loader : null, { initialData: () => cached });
54
+ const actions = readsHistory ? resource.data ?? cached : null;
55
+ if (trailing) return { pending: false, lapse: null, actions };
56
+ if (!forward) return CURRENT;
57
+ if (!readsHistory) return { pending: false, lapse: lapsedDividend(asOf, null) };
58
+ if (!actions && resource.loading) return { pending: true, lapse: null };
59
+ return { pending: false, lapse: lapsedDividend(asOf, distributionHistory(actions)) };
60
+ }
@@ -18,14 +18,19 @@ import {
18
18
  formatMarketQuantity,
19
19
  withCurrencyMinorDigits,
20
20
  } from "../../../../market-data/market/format";
21
+ import { reportedQuoteVolume } from "../../../../market-data/market/index-level";
21
22
  import type { OverviewFunctionLink, PositionTableRow, StatField } from "./types";
23
+ import type { OverviewDividendState } from "./dividend";
24
+ import { NO_CURRENT_DIVIDEND } from "../../../../utils/forward-dividend";
22
25
  import { getPortfolioPositionMetrics, getPortfolioQuoteDisplay, resolvePortfolioMarketValue, resolvePortfolioPositionPnl, portfolioPnlPercent, signedPositionDirection } from "../../../../portfolio/position-metrics";
23
- import { liveDividendYield, liveForwardPE, liveMarketCapitalization, liveTrailingPE } from "../../../../market-data/quotes/live-valuation";
26
+ import { listingDividendYield, liveForwardPE, liveMarketCapitalization, liveTrailingPE } from "../../../../market-data/quotes/live-valuation";
24
27
  import { atRegularSessionPrice } from "../../../../market-data/quotes/regular-session-valuation";
25
28
  import { formatReportedMoney } from "../../../../utils/reported-money";
26
29
  import { enterpriseValueCheck, fundamentalsCurrency, fundamentalsEpsCurrency, reportedEnterpriseValue } from "../../../../utils/fundamentals";
27
30
  import { formatShortDate } from "../../../../utils/datetime-format";
28
31
  import { safeExternalUrl } from "../../../../utils/external-url";
32
+ import type { FundBondFacts } from "../../../../api-client/fund-facts";
33
+ import { bondFigures } from "../../../../market-data/bond-funds";
29
34
 
30
35
  type CurrencyConverter = (value: number, fromCurrency: string) => number;
31
36
 
@@ -34,6 +39,10 @@ const HOLDERS: OverviewFunctionLink = { name: "Holders", tabId: "holders", templ
34
39
  const SHORT_INTEREST: OverviewFunctionLink = { name: "Short Interest", tabId: "short-interest", templateId: "short-interest-pane" };
35
40
  const EARNINGS: OverviewFunctionLink = { name: "Earnings", templateId: "earnings-calendar-pane" };
36
41
  const DIVIDENDS: OverviewFunctionLink = { name: "Dividends", tabId: "dividend-yield", templateId: "dividend-yield-pane" };
42
+ const FUND_FACTS: OverviewFunctionLink = { name: "Fund Facts", templateId: "sec-etf-pane" };
43
+
44
+ /** A bond fund's sponsor figures in a narrow grid: `SEC Yield 4.04% 2026-10-15`. */
45
+ const BOND_STAT_LABELS = { secYield: "SEC Yield", yieldToWorst: "Yld to Worst" } as const;
37
46
 
38
47
  const MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] as const;
39
48
  const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
@@ -77,6 +86,8 @@ export function buildOverviewStats({
77
86
  nextEarnings,
78
87
  depositaryReceipt = false,
79
88
  today,
89
+ dividend,
90
+ bond = null,
80
91
  }: {
81
92
  quote: Quote | undefined;
82
93
  fundamentals: TickerFinancials["fundamentals"] | undefined;
@@ -91,13 +102,22 @@ export function buildOverviewStats({
91
102
  depositaryReceipt?: boolean;
92
103
  /** The listing's calendar day, YYYY-MM-DD; dates before it are left out. */
93
104
  today?: string;
105
+ /** The history the dividend yield reads (useOverviewDividend): a trailing one is measured from its cash, a forward one stops with it; without it the yield stands. */
106
+ dividend?: OverviewDividendState;
107
+ /**
108
+ * A bond fund's SEC yield, yield to worst and duration: its yield is then a
109
+ * distribution yield, not its SEC yield, which follows it with its date.
110
+ */
111
+ bond?: FundBondFacts | null;
94
112
  }): StatField[] {
95
113
  const stats: StatField[] = [];
96
114
  const money = (value: number, perShare = false) => formatReportedMoney(value, fundamentalsCurrency({ fundamentals, financialCurrency }), perShare);
97
115
 
98
- if (quote?.volume != null) {
116
+ // An index's 0 is volume nobody counts, not a quiet session: no Volume row.
117
+ const volume = reportedQuoteVolume(quote);
118
+ if (volume != null) {
99
119
  // Live figures keep their decimals (12.30M, not 12.3M) so the digits hold still.
100
- stats.push({ label: "Volume", value: formatCompact(quote.volume, { fixedDecimals: true }) });
120
+ stats.push({ label: "Volume", value: formatCompact(volume, { fixedDecimals: true }) });
101
121
  }
102
122
  // Price-derived statistics follow the quote; see live-valuation for when a stored figure is kept.
103
123
  const capitalization = liveMarketCapitalization(quote, fundamentals);
@@ -146,16 +166,33 @@ export function buildOverviewStats({
146
166
  link: EARNINGS,
147
167
  });
148
168
  }
149
- const dividendYield = liveDividendYield(quote, fundamentals);
150
- if (fundamentals && dividendYield != null) {
151
- const label = fundamentals.dividendYieldBasis === "forward" ? "Fwd Div Yld" : fundamentals.dividendYieldBasis === "trailing" ? "TTM Div Yld" : "Div Yield";
152
- stats.push({ label, value: formatLevelPercent(dividendYield) });
169
+ // A trailing yield as DVD measures it from the cash history, once that is read.
170
+ const dividendYield = listingDividendYield(quote, fundamentals, dividend?.actions);
171
+ // A dividend that stopped has no forward yield, and its last ex-date is when it was last paid.
172
+ const lapse = dividend?.lapse ?? null;
173
+ // A bond fund pays distributions, and its yield on them is not the SEC yield after it.
174
+ const kind = bond ? "Dist" : "Div";
175
+ const notSec = bond ? { detail: ["not SEC yield", "not SEC"] } : {};
176
+ if (fundamentals && lapse) {
177
+ stats.push({ label: `Fwd ${kind} Yld`, value: NO_CURRENT_DIVIDEND });
178
+ } else if (fundamentals && dividendYield != null && !dividend?.pending) {
179
+ const basis = fundamentals.dividendYieldBasis;
180
+ const label = basis === "forward" ? `Fwd ${kind} Yld` : basis === "trailing" ? `TTM ${kind} Yld` : `${kind} Yield`;
181
+ stats.push({ label, value: formatLevelPercent(dividendYield), ...notSec });
182
+ }
183
+ if (bond) {
184
+ // Each dated, as the sponsor publishes it; the narrowest column drops the year.
185
+ for (const figure of bondFigures(bond)) {
186
+ const label = figure.key === "duration" ? (bond.duration?.measure === "average" ? "Avg Duration" : "Eff Duration") : BOND_STAT_LABELS[figure.key];
187
+ const forms = figure.date ? [...new Set([figure.date, figure.date.replace(/\b\d{4}-(\d{2}-\d{2})\b/, "$1")])] : undefined;
188
+ stats.push({ label, value: figure.text, ...(forms ? { detail: forms } : {}), link: FUND_FACTS });
189
+ }
153
190
  }
154
- const exDividendDate = fundamentals?.exDividendDate;
191
+ const exDividendDate = lapse?.lastPaid ?? fundamentals?.exDividendDate;
155
192
  if (exDividendDate && ISO_DATE.test(exDividendDate)) {
156
193
  const days = today ? daysUntil(exDividendDate, today) : -1;
157
194
  stats.push({
158
- label: "Ex-Dividend",
195
+ label: lapse ? "Last Paid" : "Ex-Dividend",
159
196
  value: calendarDate(exDividendDate, today ?? exDividendDate),
160
197
  detail: days >= 0 ? daysAhead(days) : undefined,
161
198
  link: DIVIDENDS,
@@ -12,6 +12,7 @@ import { getTickerResearchPaneSettings } from "../settings";
12
12
  import { OverviewTab } from "../overview-tab";
13
13
  import { useOpenResearchTab } from "../research-tab-navigation";
14
14
  import type { OverviewFunctionLink } from "./types";
15
+ import { useOverviewDividend } from "./dividend";
15
16
 
16
17
  /** Registered by the chart composer, in the same plugin as this tab. */
17
18
  const CHART_TAB_ID = "chart";
@@ -23,6 +24,7 @@ export function OverviewResearchTab({ width, height, focused }: TickerResearchTa
23
24
  const paneInstance = usePaneInstance();
24
25
  const openResearchTab = useOpenResearchTab();
25
26
  const { createPaneFromTemplate } = usePluginAppActions();
27
+ const dividend = useOverviewDividend(ticker?.metadata.ticker ?? null, ticker?.metadata.exchange ?? "", financials?.fundamentals);
26
28
  // A pane locked to one tab has nowhere to go.
27
29
  const lockedToOneTab = getTickerResearchPaneSettings(paneInstance?.settings).hideTabs;
28
30
  const openChart = useCallback(() => {
@@ -43,6 +45,7 @@ export function OverviewResearchTab({ width, height, focused }: TickerResearchTa
43
45
  financials={financials}
44
46
  onOpenChart={paneId && !lockedToOneTab ? openChart : undefined}
45
47
  onOpenFunction={openFunction}
48
+ dividend={dividend}
46
49
  perpetuals={ticker ? <PerpEquityRow symbol={ticker.metadata.ticker} exchange={ticker.metadata.exchange} instrumentType={financials?.quote?.instrumentType ?? ticker.metadata.assetCategory} /> : undefined}
47
50
  />
48
51
  );
@@ -1,4 +1,8 @@
1
1
  import { TrendingSummary } from "../attention/trending";
2
+ import { fundFactOverviewFields } from "../sec/fund-facts";
3
+ import { useFundFacts } from "../sec/fund-facts-view";
4
+ import { resolveTickerInstrumentKind } from "../../../tickers/instrument-kind";
5
+ import { mayBeUsEquityOrFundTicker } from "../../../utils/sec";
2
6
  import type { ReactNode } from "react";
3
7
  import { EmptyState, PaneLinkMenu, SectionHeading, usePaneNoticeFooter } from "../../../components";
4
8
  import { CompositeChart, pricePointsToResolvedSeries } from "../../../components/chart/composite";
@@ -8,6 +12,7 @@ import { PriceReturnStrip } from "../../../components/price-performance";
8
12
  import { t } from "../../../i18n";
9
13
  import { useFxRatesMap } from "../../../market-data/hooks";
10
14
  import { formatMarketPriceWithCurrency, formatSignedMarketPrice, liveQuoteFormatOptions } from "../../../market-data/market/format";
15
+ import { priceSeriesUnit } from "../../../market-data/market/index-level";
11
16
  import {
12
17
  exchangeShortName,
13
18
  extendedSessionLineLabel,
@@ -41,6 +46,7 @@ import {
41
46
  textGridColumns,
42
47
  } from "./overview/components";
43
48
  import { useFuturesContractTerms } from "./overview/futures-contract";
49
+ import type { OverviewDividendState } from "./overview/dividend";
44
50
  import { buildOverviewStats, buildPositionRows, buildProfileFields } from "./overview/model";
45
51
  import type { OverviewFunctionLink, StatField } from "./overview/types";
46
52
  import { describeFundamentalMarketCap } from "../../../utils/market-capitalization";
@@ -80,6 +86,8 @@ interface OverviewTabProps {
80
86
  onOpenChart?: () => void;
81
87
  /** A click on a figure opens its research function (beta to GR, holders to HDS). */
82
88
  onOpenFunction?: (link: OverviewFunctionLink) => void;
89
+ /** The history the dividend yield reads (useOverviewDividend): a trailing one's cash, a forward one's lapse; without it the yield stands. */
90
+ dividend?: OverviewDividendState;
83
91
  }
84
92
 
85
93
  export function OverviewTab(props: OverviewTabProps) {
@@ -87,7 +95,10 @@ export function OverviewTab(props: OverviewTabProps) {
87
95
  return <ResolvedOverviewTab {...props} ticker={props.ticker} />;
88
96
  }
89
97
 
90
- function ResolvedOverviewTab({ width, height, focused = false, ticker, financials, onOpenChart, onOpenFunction, perpetuals }: OverviewTabProps & { ticker: TickerRecord }) {
98
+ /** Where a fund's facts open: the ETF function, its facts over its filings. */
99
+ const FUND_FACTS_LINK: OverviewFunctionLink = { name: "Fund Facts", templateId: "sec-etf-pane" };
100
+
101
+ function ResolvedOverviewTab({ width, height, focused = false, ticker, financials, onOpenChart, onOpenFunction, perpetuals, dividend }: OverviewTabProps & { ticker: TickerRecord }) {
91
102
  const baseCurrency = useAppSelector((state) => state.config.baseCurrency);
92
103
  const { width: termWidth } = useViewport();
93
104
  const { fractionalViewport = false, nativePaneChrome, cellWidthPx = 8, cellHeightPx = 18, pixelRatio = 1 } = useUiCapabilities();
@@ -125,6 +136,14 @@ function ResolvedOverviewTab({ width, height, focused = false, ticker, financial
125
136
  routingVenue && routingVenue !== listingVenue ? `route ${routingVenue}` : "",
126
137
  ].filter((part) => part.length > 0);
127
138
 
139
+ // A US-listed fund's facts (fee, NAV, premium, net assets) stand where a company's fundamentals would; each opens ETF.
140
+ const fundFactsSymbol = resolveTickerInstrumentKind(ticker, financials) === "fund" && mayBeUsEquityOrFundTicker(ticker) ? ticker.metadata.ticker : null;
141
+ const fundFacts = useFundFacts(fundFactsSymbol).data?.payload;
142
+ // Each figure dated; one older than it looks takes the warning colour, as in ETF.
143
+ const fundFactFields: StatField[] = fundFacts?.covered
144
+ ? fundFactOverviewFields(fundFacts).map(({ warn, ...field }) => ({ ...field, ...(warn ? { valueColor: colors.warning } : {}), link: FUND_FACTS_LINK }))
145
+ : [];
146
+
128
147
  const contentWidth = Math.max((width || Math.floor(termWidth * 0.5)) - (fractionalViewport ? 2 : 4), 20);
129
148
  const chartWidth = contentWidth;
130
149
  const hasHistory = (financials?.priceHistory?.length ?? 0) > 2;
@@ -139,7 +158,8 @@ function ResolvedOverviewTab({ width, height, focused = false, ticker, financial
139
158
  id: `${ticker.metadata.ticker}:price`,
140
159
  label: `${ticker.metadata.ticker} Price`,
141
160
  color: priceColor(chartDelta),
142
- unit: unknownHistoryBasis ? "unknown" : quoteCurrency,
161
+ // An index's axis reads in points: ^VIX at 20, never $20.
162
+ unit: unknownHistoryBasis ? "unknown" : priceSeriesUnit(quoteCurrency, instrumentType),
143
163
  style: "area",
144
164
  axis: "right",
145
165
  panelId: "price",
@@ -236,6 +256,8 @@ function ResolvedOverviewTab({ width, height, focused = false, ticker, financial
236
256
  depositaryReceipt: sharesOutstandingInReceipts(quote, fundamentals, description),
237
257
  // Report and ex-dividend dates are the listing's calendar days.
238
258
  today: zonedDateKey(Date.now(), chartTimeZone ?? "America/New_York"),
259
+ dividend,
260
+ bond: fundFacts?.bond ?? null,
239
261
  });
240
262
  const profileFields = buildProfileFields({
241
263
  instrumentType: instrumentTypeLabel(instrumentType, quote?.name || ticker.metadata.name),
@@ -355,7 +377,7 @@ function ResolvedOverviewTab({ width, height, focused = false, ticker, financial
355
377
  {perpetuals && <PaneLinkMenu>{perpetuals}</PaneLinkMenu>}
356
378
 
357
379
  {(hasDayRange || yearRange) && quote && (
358
- <Box flexDirection={rangeInline ? "row" : "column"} gap={rangeInline ? RANGE_PAIR_GAP : 0} width={contentWidth}>
380
+ <Box flexDirection={rangeInline ? "row" : "column"} gap={rangeInline ? RANGE_PAIR_GAP : 0} width={nativePaneChrome ? undefined : contentWidth}>
359
381
  {hasDayRange && (
360
382
  <CompactRangeBar
361
383
  current={sessionQuote?.price ?? quote.price}
@@ -366,6 +388,7 @@ function ResolvedOverviewTab({ width, height, focused = false, ticker, financial
366
388
  labelWidth={rangeLabelWidth}
367
389
  endpointWidth={rangeEndpointCells}
368
390
  width={rangeWidth}
391
+ grow={rangeInline}
369
392
  currency={quoteCurrency}
370
393
  priceOptions={moneyOptions}
371
394
  />
@@ -380,6 +403,7 @@ function ResolvedOverviewTab({ width, height, focused = false, ticker, financial
380
403
  labelWidth={rangeLabelWidth}
381
404
  endpointWidth={rangeEndpointCells}
382
405
  width={rangeWidth}
406
+ grow={rangeInline}
383
407
  currency={quoteCurrency}
384
408
  priceOptions={moneyOptions}
385
409
  />
@@ -426,6 +450,15 @@ function ResolvedOverviewTab({ width, height, focused = false, ticker, financial
426
450
  </Box>
427
451
  )}
428
452
 
453
+ {fundFactFields.length > 0 && (
454
+ <Box flexDirection="column">
455
+ <SectionHeading title={t("Fund Facts")} />
456
+ <PaneLinkMenu>
457
+ <FundamentalsGrid fields={fundFactFields} width={contentWidth} onOpenLink={onOpenFunction} />
458
+ </PaneLinkMenu>
459
+ </Box>
460
+ )}
461
+
429
462
  {stats.length > 0 && (
430
463
  <Box flexDirection="column">
431
464
  <SectionHeading title={t("Fundamentals")} />
@@ -59,7 +59,7 @@ function extendedLineParts(
59
59
  return candidates.find(({ label, figures }) => fits(`${label} ${figures}`)) ?? null;
60
60
  }
61
61
 
62
- const DESKTOP_DETAIL_TEXT_STYLE = { fontSize: "12px", lineHeight: "14px", whiteSpace: "nowrap" };
62
+ const DESKTOP_DETAIL_TEXT_STYLE = { fontSize: "var(--gloom-type-ui)", lineHeight: "14px", whiteSpace: "nowrap" };
63
63
 
64
64
  function ExtendedSessionLine({
65
65
  parts,
@@ -203,9 +203,10 @@ export function QuoteMonitorCard({
203
203
  || height >= (stacked ? 3 : 2) + statusRows + terminalSparklineHeight;
204
204
  // Figures sit over the sparkline, so the desktop rings them in the card colour.
205
205
  const figureHalo = { textShadow: `0 1px 2px ${colors.bg}` };
206
+ // The card's title: a heading over the app's 12px name, under the 20px price.
206
207
  const desktopSymbolStyle = nativePaneChrome
207
208
  ? {
208
- fontSize: "15px",
209
+ fontSize: "var(--gloom-type-heading)",
209
210
  lineHeight: "18px",
210
211
  }
211
212
  : undefined;
@@ -237,12 +238,10 @@ export function QuoteMonitorCard({
237
238
  position: "relative",
238
239
  width: "100%",
239
240
  height: "100%",
240
- paddingLeft: 10,
241
- paddingRight: 10,
242
- paddingTop: 6,
243
- paddingBottom: 4,
244
- borderRight: showRightDivider ? `1px solid ${colors.border}` : undefined,
245
- borderBottom: showBottomDivider ? `1px solid ${colors.border}` : undefined,
241
+ padding: "var(--gloom-space-xs) var(--gloom-inset)",
242
+ // The rules between the board's cards are the app's hairline.
243
+ borderRight: showRightDivider ? "1px solid var(--gloom-hairline)" : undefined,
244
+ borderBottom: showBottomDivider ? "1px solid var(--gloom-hairline)" : undefined,
246
245
  outline: selected ? `1px solid ${colors.borderFocused}` : undefined,
247
246
  outlineOffset: selected ? -1 : undefined,
248
247
  } : undefined}
@@ -267,7 +266,7 @@ export function QuoteMonitorCard({
267
266
  // The name gives way first; the price keeps its natural width.
268
267
  gridTemplateColumns: "minmax(0, 1fr) auto",
269
268
  gridTemplateRows: "auto 1fr auto auto",
270
- columnGap: 12,
269
+ columnGap: "var(--gloom-space-md)",
271
270
  width: "100%",
272
271
  height: "100%",
273
272
  }}
@@ -286,7 +285,7 @@ export function QuoteMonitorCard({
286
285
  {symbol}
287
286
  </Text>
288
287
  {quoteFailed && (
289
- <Text fg={colors.negative} style={{ fontSize: "12px", lineHeight: "14px" }}>
288
+ <Text fg={colors.negative} style={{ fontSize: "var(--gloom-type-ui)", lineHeight: "14px" }}>
290
289
  {quoteStatus.text}
291
290
  </Text>
292
291
  )}
@@ -294,7 +293,7 @@ export function QuoteMonitorCard({
294
293
  <Text
295
294
  fg={colors.textDim}
296
295
  style={{
297
- fontSize: "12px",
296
+ fontSize: "var(--gloom-type-ui)",
298
297
  lineHeight: "14px",
299
298
  maxWidth: "100%",
300
299
  overflow: "hidden",
@@ -306,7 +305,7 @@ export function QuoteMonitorCard({
306
305
  </Text>
307
306
  )}
308
307
  {navAsOf && (
309
- <Text fg={colors.textDim} style={{ fontSize: "12px", lineHeight: "14px" }}>
308
+ <Text fg={colors.textDim} style={{ fontSize: "var(--gloom-type-ui)", lineHeight: "14px" }}>
310
309
  {navAsOf}
311
310
  </Text>
312
311
  )}
@@ -320,9 +319,9 @@ export function QuoteMonitorCard({
320
319
  gridRow: "1",
321
320
  justifySelf: "end",
322
321
  backgroundColor: colors.bg,
323
- borderRadius: 4,
322
+ borderRadius: "var(--gloom-radius-sm)",
324
323
  boxShadow: `0 0 0 2px ${colors.bg}`,
325
- paddingLeft: 6,
324
+ paddingLeft: "var(--gloom-space-xs)",
326
325
  paddingBottom: 1,
327
326
  }}
328
327
  >
@@ -361,10 +360,10 @@ export function QuoteMonitorCard({
361
360
  gridRow: "3",
362
361
  justifySelf: "end",
363
362
  alignSelf: "end",
364
- fontSize: "11px",
365
- lineHeight: "13px",
363
+ fontSize: "var(--gloom-type-ui)",
364
+ lineHeight: "14px",
366
365
  backgroundColor: colors.bg,
367
- paddingLeft: 6,
366
+ paddingLeft: "var(--gloom-space-xs)",
368
367
  paddingRight: 2,
369
368
  boxShadow: `0 0 0 2px ${colors.bg}`,
370
369
  }}
@@ -410,7 +409,7 @@ export function QuoteMonitorCard({
410
409
  <Text
411
410
  fg={colors.textDim}
412
411
  style={{
413
- fontSize: "12px",
412
+ fontSize: "var(--gloom-type-ui)",
414
413
  lineHeight: "16px",
415
414
  overflow: "hidden",
416
415
  textOverflow: "ellipsis",
@@ -449,7 +448,7 @@ export function QuoteMonitorCard({
449
448
  area={!nativePaneChrome}
450
449
  />
451
450
  {nativePaneChrome && rangeLabel && (
452
- <Text fg={colors.textDim} style={{ fontSize: "11px", lineHeight: "14px" }}>
451
+ <Text fg={colors.textDim} style={{ fontSize: "var(--gloom-type-ui)", lineHeight: "14px" }}>
453
452
  {rangeLabel}
454
453
  </Text>
455
454
  )}
@@ -1,6 +1,6 @@
1
1
  import { apiClient } from "../../../api-client";
2
2
  import { ApiRequestError } from "../../../api-client/errors";
3
- import type { TapeSnapshot } from "../../../api-client/tape";
3
+ import type { TapeRange, TapeSnapshot } from "../../../api-client/tape";
4
4
  import { canonicalExchange, normalizeSymbol } from "../../../utils/exchanges";
5
5
  import { tapeTimeKey, tradeKey } from "./model";
6
6
 
@@ -25,7 +25,9 @@ export function validateTape(data: TapeSnapshot, symbol: string, exchange: strin
25
25
  || data.feed !== (data.access === "realtime" ? "sip" : "delayed_sip") || data.delaySeconds !== (data.access === "realtime" ? 0 : 900)
26
26
  || !data.capacity || !count(data.capacity.trades) || data.capacity.trades > 1000 || !count(data.capacity.quotes) || data.capacity.quotes > 500
27
27
  || !Array.isArray(data.trades) || data.trades.length > data.capacity.trades || !Array.isArray(data.quotes) || data.quotes.length > data.capacity.quotes
28
- || !data.dropped || !count(data.dropped.trades) || !count(data.dropped.quotes) || !count(data.corrections) || !count(data.cancels)) {
28
+ || !data.dropped || !count(data.dropped.trades) || !count(data.dropped.quotes) || !count(data.corrections) || !count(data.cancels)
29
+ || data.window !== undefined && (!data.window || !timestamp(data.window.from) || !timestamp(data.window.to) || !data.window.truncated
30
+ || typeof data.window.truncated.trades !== "boolean" || typeof data.window.truncated.quotes !== "boolean")) {
29
31
  throw new Error("The server returned an invalid tape snapshot");
30
32
  }
31
33
  const cutoffDate = new Date(Date.parse(data.generatedAt) - data.delaySeconds * 1000).toISOString();
@@ -56,9 +58,10 @@ export function validateTape(data: TapeSnapshot, symbol: string, exchange: strin
56
58
  return { ...data, source: "Gloom Cloud", trades: [...data.trades].sort((a, b) => tapeTimeKey(a.timestamp).localeCompare(tapeTimeKey(b.timestamp))),
57
59
  quotes: [...data.quotes].sort((a, b) => tapeTimeKey(a.timestamp).localeCompare(tapeTimeKey(b.timestamp))) };
58
60
  }
61
+ /** The latest tape, or with a `range` that window of the session. */
59
62
  export async function fetchTape(symbol: string, exchange: string, signal?: AbortSignal,
60
- client: Pick<typeof apiClient, "getCloudTape"> = apiClient): Promise<TapeSnapshot> {
61
- try { return validateTape(await client.getCloudTape(symbol, exchange, signal), symbol, exchange); }
63
+ client: Pick<typeof apiClient, "getCloudTape"> = apiClient, range?: TapeRange): Promise<TapeSnapshot> {
64
+ try { return validateTape(await (range ? client.getCloudTape(symbol, exchange, signal, range) : client.getCloudTape(symbol, exchange, signal)), symbol, exchange); }
62
65
  catch (error) {
63
66
  if (error instanceof ApiRequestError && [404, 503].includes(error.status ?? 0)) throw new Error("Time and sales is not available yet.");
64
67
  // A rejected request answers with an unavailable snapshot; show its reason, not the JSON body.
@@ -1,13 +1,14 @@
1
- import type { HeadlessPaneColumn, HeadlessPaneDefinition, HeadlessPaneRow } from "../../../types/plugin";
2
- import { subMinuteDataMessage } from "../../../cli/known-gaps";
3
- import { listingSuffixExchange } from "../../../sources/listing-symbols";
4
- import { parsePublicTickerKey } from "../../../utils/exchanges";
5
- import { listingAbroadVenue } from "../../../utils/sec";
1
+ import type { HeadlessPaneColumn, HeadlessPaneContext, HeadlessPaneDefinition, HeadlessPaneRow } from "../../../types/plugin";
2
+ import { listedAbroad, subMinuteDataMessage } from "../../../cli/known-gaps";
3
+ import type { TapeRange, TapeSnapshot } from "../../../api-client/tape";
6
4
  import { fetchTape } from "./client";
7
- import { newestFirst, quoteSpread, tapePrice, tapePriceDigits, tapeStatistics } from "./model";
5
+ import { newestFirst, quoteSpread, tapePrice, tapePriceDigits, tapeStatistics, tapeTimeKey } from "./model";
6
+ import { REPORT_ROWS } from "../shared/headless-options";
7
+ import { inTapeRange, normalizeTapeClock, parseTapeClock, servedWindow, sessionDay, tapeMoment, tapeWindowRange } from "./window";
8
8
 
9
9
  type Format = NonNullable<HeadlessPaneColumn["format"]>;
10
10
  const fixedPrice = (digits: number): Format => (value) => tapePrice(typeof value === "number" ? value : null, digits);
11
+ const whole: Format = (value) => typeof value === "number" && Number.isFinite(value) ? value.toFixed(0) : "--";
11
12
  const bps: Format = (value) => typeof value === "number" && Number.isFinite(value) ? value.toFixed(2) : "--";
12
13
 
13
14
  /** Every row key in order, with the pane's rounding where the report would otherwise print raw floats. */
@@ -16,22 +17,62 @@ function formattedColumns(rows: readonly HeadlessPaneRow[], formats: Record<stri
16
17
  .map((key) => ({ key, header: key, ...(formats[key] ? { format: formats[key] } : {}) }));
17
18
  }
18
19
 
20
+ function oldestFirst<T extends { timestamp: string }>(rows: readonly T[]): T[] {
21
+ return [...rows].sort((a, b) => tapeTimeKey(a.timestamp).localeCompare(tapeTimeKey(b.timestamp)));
22
+ }
23
+
24
+ /** When `--limit` cuts a window's trades: how many of them are listed. */
25
+ function listedNote(range: TapeRange, served: number, listed: number): string[] {
26
+ return listed < served ? [`Listing the first ${listed} of the ${served} trades from ${tapeMoment(Date.parse(range.from))}; --limit takes up to 1000.`] : [];
27
+ }
28
+
29
+
30
+ const WINDOW_OPTION = { reportOnly: "lists a window of the session in the text report" };
31
+
19
32
  /**
20
- * Whether a listing trades abroad, by its key, its saved exchange or its
21
- * listing suffix (RMS.AX is the ASX): the SIP tape carries US listings only,
22
- * so it has nothing for one, and its bare symbol can be another company there.
33
+ * The window `--from`/`--to` ask for, read against the session the latest tape
34
+ * serves, then fetched as that window. A server that predates windows answers
35
+ * with its latest tape: its prints that fall in the window stand, and a note
36
+ * says from when that tape runs.
23
37
  */
24
- function listedAbroad(key: string, exchange: string | undefined): boolean {
25
- const parsed = parsePublicTickerKey(key);
26
- const venue = parsed.exchange || exchange || listingSuffixExchange(parsed.symbol);
27
- return !!venue && listingAbroadVenue(`${parsed.symbol}:${venue}`) != null;
38
+ async function loadWindow(symbol: string, exchange: string, from: string, to: string, ctx: HeadlessPaneContext) {
39
+ const latest = await fetchTape(symbol, exchange, ctx.signal, ctx.apiClient);
40
+ const served = servedWindow(latest);
41
+ if (!served) throw new Error(`TAS has no session for ${symbol} to read a window of; run it without --from and --to for the latest prints.`);
42
+ const range = tapeWindowRange(served, from ? parseTapeClock(from) : null, to ? parseTapeClock(to) : null);
43
+ const data = await fetchTape(symbol, exchange, ctx.signal, ctx.apiClient, range);
44
+ const notes = [`Window: ${sessionDay(served.date)}, ${tapeMoment(Date.parse(range.from))} to ${tapeMoment(Date.parse(range.to))}.`];
45
+ if (data.window) {
46
+ if (data.window.truncated.trades) {
47
+ const last = data.trades.at(-1)?.timestamp;
48
+ notes.push(`The window holds more than ${data.capacity.trades} trades: these are the first${last ? `, through ${tapeMoment(Date.parse(last))}` : ""}; start --from there to read on.`);
49
+ }
50
+ return { data, range, notes };
51
+ }
52
+ const trades = data.trades.filter((row) => inTapeRange(row.timestamp, range)), quotes = data.quotes.filter((row) => inTapeRange(row.timestamp, range));
53
+ // Dated by what it lists, as a served window is.
54
+ const times = oldestFirst([...trades, ...quotes]).map((row) => row.timestamp);
55
+ const kept = { ...data, trades, quotes, asOf: times.at(-1) ?? null, observedFrom: times[0] ?? null };
56
+ if (data.observedFrom && tapeTimeKey(data.observedFrom) > tapeTimeKey(range.from)) {
57
+ notes.push(`This server serves only its latest tape, from ${tapeMoment(Date.parse(data.observedFrom))}: prints before it are not listed.`);
58
+ }
59
+ return { data: kept, range, notes };
28
60
  }
29
61
 
30
62
  export const timeSalesHeadless: HeadlessPaneDefinition<"bundle"> = {
31
63
  shape: "bundle", argument: { kind: "ticker", placeholder: "ticker", description: "US equity ticker." },
32
64
  usListingsOnly: "Time and sales",
33
- usListingsOnlyHint: subMinuteDataMessage,
34
- options: [{ key: "limit", type: "integer", minimum: 1, maximum: 1000, defaultValue: 100, description: "Maximum recent prints in the report." }],
65
+ usListingsOnlyHint: (symbol) => subMinuteDataMessage(symbol, "abroad"),
66
+ options: [
67
+ { key: "limit", shot: REPORT_ROWS, type: "integer", minimum: 1, maximum: 1000, defaultValue: 100, description: "Maximum recent prints in the report." },
68
+ { key: "from", shot: WINDOW_OPTION, type: "string", defaultValue: "", placeholder: "time", example: "--from 10:30 --to 10:35",
69
+ description: "Start of a window of the served session, as a time of day: 10:30 or 10:30:15 on New York's clock, 14:30Z on UTC's."
70
+ + " The report then lists that window's prints oldest first; without --to it runs to the end of what is served.",
71
+ normalize: normalizeTapeClock },
72
+ { key: "to", shot: WINDOW_OPTION, type: "string", defaultValue: "", placeholder: "time",
73
+ description: "End of the window, as --from takes it; without --from the window starts at 04:00 New York time.",
74
+ normalize: normalizeTapeClock },
75
+ ],
35
76
  discovery: { aliases: ["TAS", "QR"], dataRequirements: ["Gloom Cloud SIP trade and quote feed"],
36
77
  limitations: ["Bounded observed window, not a complete session.", "SIP is delayed fifteen minutes without realtime entitlement.", "Quote sizes are round lots.", "No Level 2 or inferred aggressor side."] },
37
78
  describe: (args) => `Time and sales ${args.argument ?? ""}`,
@@ -41,28 +82,36 @@ export const timeSalesHeadless: HeadlessPaneDefinition<"bundle"> = {
41
82
  if (listedAbroad(symbol, instrument?.exchange)) {
42
83
  // Say why the table is empty and where the finest bars for it are, rather than the tape's bare "unavailable".
43
84
  return { complete: false, sections: [
44
- { title: ctx.settings?.tab === "quotes" ? "NBBO" : "Trades", rows: [], empty: subMinuteDataMessage(symbol) },
85
+ { title: ctx.settings?.tab === "quotes" ? "NBBO" : "Trades", rows: [], empty: subMinuteDataMessage(symbol, "abroad") },
45
86
  ] };
46
87
  }
47
- const data = await fetchTape(symbol, instrument?.exchange ?? "", ctx.signal, ctx.apiClient);
88
+ const exchange = instrument?.exchange ?? "";
89
+ const from = String(args.options.from ?? "").trim(), to = String(args.options.to ?? "").trim();
90
+ const windowed = from || to ? await loadWindow(symbol, exchange, from, to, ctx) : null;
91
+ const data: TapeSnapshot = windowed?.data ?? await fetchTape(symbol, exchange, ctx.signal, ctx.apiClient);
92
+ const limit = Number(args.options.limit ?? 100);
48
93
  const statistics = tapeStatistics(data);
49
94
  const window = [{ from: statistics.from, asOf: statistics.asOf, prints: statistics.count, shares: statistics.volume,
50
95
  vwap: statistics.vwap, low: statistics.low, high: statistics.high, pricePercentile: statistics.pricePercentile }];
51
- const quotes = newestFirst(data.quotes).slice(0, Number(args.options.limit ?? 100)).map((row) => ({ ...row, ...quoteSpread(row), conditions: row.conditions.join(" ") }));
96
+ // A window reads forward from its start; the latest tape newest first, as the pane lists it.
97
+ const ordered = <T extends { timestamp: string }>(rows: readonly T[]) => windowed ? oldestFirst(rows) : newestFirst(rows);
98
+ const quotes = ordered(data.quotes).slice(0, limit).map((row) => ({ ...row, ...quoteSpread(row), conditions: row.conditions.join(" ") }));
52
99
  // One decimal count per column, as the pane shows it, so sub-penny prints align.
53
100
  const price = fixedPrice(tapePriceDigits(data.trades.map((row) => row.price)));
54
- const trades = newestFirst(data.trades).slice(0, Number(args.options.limit ?? 100)).map((row) => ({ ...row, conditions: row.conditions.join(" ") }));
101
+ const trades = ordered(data.trades).slice(0, limit).map((row) => ({ ...row, conditions: row.conditions.join(" ") }));
102
+ const notes = windowed ? [...windowed.notes, ...listedNote(windowed.range, data.trades.length, trades.length)] : [];
55
103
  // SIP prints, real-time or fifteen minutes delayed by entitlement, dated by the newest print.
56
104
  const freshness = data.feed === "sip"
57
105
  ? { status: "live" as const, cadence: "daily" as const }
58
106
  : { status: "delayed" as const, delayMinutes: Math.round(data.delaySeconds / 60), cadence: "daily" as const };
59
- return { freshness, sections: [
60
- { title: "Observed window", columns: formattedColumns(window, { vwap: price, low: price, high: price }), rows: window },
107
+ return { freshness, ...(notes.length ? { notes } : {}), sections: [
108
+ // The last price's rank among the window's prints, whole, as the pane shows it.
109
+ { title: windowed ? "Window" : "Observed window", columns: formattedColumns(window, { vwap: price, low: price, high: price, pricePercentile: whole }), rows: window },
61
110
  { title: "Regular session", columns: formattedColumns([data.session], { high: price, low: price }), rows: [data.session] },
62
111
  { title: "Trades", columns: formattedColumns(trades, { price }), rows: trades },
63
112
  { title: "NBBO", columns: formattedColumns(quotes, { bps }), rows: quotes },
64
113
  ], errors: data.gaps, metadata: { source: data.source, feed: data.feed, delaySeconds: data.delaySeconds,
65
- asOf: data.asOf, observedFrom: data.observedFrom, generatedAt: data.generatedAt, status: data.status,
114
+ asOf: data.asOf, observedFrom: data.observedFrom, generatedAt: data.generatedAt, status: data.status, ...(windowed ? { window: windowed.range } : {}),
66
115
  complete: data.status === "available", capacity: data.capacity, dropped: data.dropped, corrections: data.corrections, cancels: data.cancels, connected: data.connected } };
67
116
  },
68
117
  };
@@ -36,6 +36,18 @@ export const quoteKey = (row: TapeQuote) => JSON.stringify([tapeTimeKey(row.time
36
36
  export function newestFirst<T extends { timestamp: string }>(rows: readonly T[]): T[] {
37
37
  return [...rows].sort((a, b) => tapeTimeKey(b.timestamp).localeCompare(tapeTimeKey(a.timestamp)));
38
38
  }
39
+ /**
40
+ * A moment in milliseconds as a tape key, the one comparison both picking the
41
+ * row at a pinned moment and muting the rows after it use, so a print at
42
+ * 14:30:00.000000002 is after a moment of 14:30:00.000 for both.
43
+ */
44
+ export const tapeMomentKey = (at: number) => tapeTimeKey(new Date(at).toISOString());
45
+ /** Whether a SIP stamp is after a moment's key (`tapeMomentKey`). */
46
+ export const tapeAfter = (timestamp: string, momentKey: string) => tapeTimeKey(timestamp) > momentKey;
47
+ /** Of rows newest first, the first printed at or before a moment's key: null when every row is later. */
48
+ export function tapeRowAtOrBefore<T>(rows: readonly T[], timestamp: (row: T) => string, momentKey: string): T | null {
49
+ return rows.find((row) => !tapeAfter(timestamp(row), momentKey)) ?? null;
50
+ }
39
51
  export function tapeStatistics(data: Pick<TapeSnapshot, "trades">) {
40
52
  const trades = newestFirst(data.trades);
41
53
  const prices = trades.map((row) => row.price);